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}
3912
3913#[derive(Clone, Debug)]
3914struct CoreSymbol {
3915 pub language_server_name: LanguageServerName,
3916 pub source_worktree_id: WorktreeId,
3917 pub source_language_server_id: LanguageServerId,
3918 pub path: SymbolLocation,
3919 pub name: String,
3920 pub kind: lsp::SymbolKind,
3921 pub range: Range<Unclipped<PointUtf16>>,
3922}
3923
3924#[derive(Clone, Debug, PartialEq, Eq)]
3925pub enum SymbolLocation {
3926 InProject(ProjectPath),
3927 OutsideProject {
3928 abs_path: Arc<Path>,
3929 signature: [u8; 32],
3930 },
3931}
3932
3933impl SymbolLocation {
3934 fn file_name(&self) -> Option<&str> {
3935 match self {
3936 Self::InProject(path) => path.path.file_name(),
3937 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3938 }
3939 }
3940}
3941
3942impl LspStore {
3943 pub fn init(client: &AnyProtoClient) {
3944 client.add_entity_request_handler(Self::handle_lsp_query);
3945 client.add_entity_message_handler(Self::handle_lsp_query_response);
3946 client.add_entity_request_handler(Self::handle_restart_language_servers);
3947 client.add_entity_request_handler(Self::handle_stop_language_servers);
3948 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3949 client.add_entity_message_handler(Self::handle_start_language_server);
3950 client.add_entity_message_handler(Self::handle_update_language_server);
3951 client.add_entity_message_handler(Self::handle_language_server_log);
3952 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3953 client.add_entity_request_handler(Self::handle_format_buffers);
3954 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3955 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3956 client.add_entity_request_handler(Self::handle_apply_code_action);
3957 client.add_entity_request_handler(Self::handle_get_project_symbols);
3958 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3959 client.add_entity_request_handler(Self::handle_get_color_presentation);
3960 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3961 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3962 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3963 client.add_entity_request_handler(Self::handle_on_type_formatting);
3964 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3965 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3966 client.add_entity_request_handler(Self::handle_rename_project_entry);
3967 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3968 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3969 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3970 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3971 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3972 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3973 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3974
3975 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3976 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3977 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3978 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3979 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3980 client.add_entity_request_handler(
3981 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3982 );
3983 client.add_entity_request_handler(
3984 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3985 );
3986 client.add_entity_request_handler(
3987 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3988 );
3989 }
3990
3991 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3992 match &self.mode {
3993 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3994 _ => None,
3995 }
3996 }
3997
3998 pub fn as_local(&self) -> Option<&LocalLspStore> {
3999 match &self.mode {
4000 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4001 _ => None,
4002 }
4003 }
4004
4005 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4006 match &mut self.mode {
4007 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4008 _ => None,
4009 }
4010 }
4011
4012 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4013 match &self.mode {
4014 LspStoreMode::Remote(RemoteLspStore {
4015 upstream_client: Some(upstream_client),
4016 upstream_project_id,
4017 ..
4018 }) => Some((upstream_client.clone(), *upstream_project_id)),
4019
4020 LspStoreMode::Remote(RemoteLspStore {
4021 upstream_client: None,
4022 ..
4023 }) => None,
4024 LspStoreMode::Local(_) => None,
4025 }
4026 }
4027
4028 pub fn new_local(
4029 buffer_store: Entity<BufferStore>,
4030 worktree_store: Entity<WorktreeStore>,
4031 prettier_store: Entity<PrettierStore>,
4032 toolchain_store: Entity<LocalToolchainStore>,
4033 environment: Entity<ProjectEnvironment>,
4034 manifest_tree: Entity<ManifestTree>,
4035 languages: Arc<LanguageRegistry>,
4036 http_client: Arc<dyn HttpClient>,
4037 fs: Arc<dyn Fs>,
4038 cx: &mut Context<Self>,
4039 ) -> Self {
4040 let yarn = YarnPathStore::new(fs.clone(), cx);
4041 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4042 .detach();
4043 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4044 .detach();
4045 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4046 .detach();
4047 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4048 .detach();
4049 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4050 .detach();
4051 subscribe_to_binary_statuses(&languages, cx).detach();
4052
4053 let _maintain_workspace_config = {
4054 let (sender, receiver) = watch::channel();
4055 (Self::maintain_workspace_config(receiver, cx), sender)
4056 };
4057
4058 Self {
4059 mode: LspStoreMode::Local(LocalLspStore {
4060 weak: cx.weak_entity(),
4061 worktree_store: worktree_store.clone(),
4062
4063 supplementary_language_servers: Default::default(),
4064 languages: languages.clone(),
4065 language_server_ids: Default::default(),
4066 language_servers: Default::default(),
4067 last_workspace_edits_by_language_server: Default::default(),
4068 language_server_watched_paths: Default::default(),
4069 language_server_paths_watched_for_rename: Default::default(),
4070 language_server_dynamic_registrations: Default::default(),
4071 buffers_being_formatted: Default::default(),
4072 buffers_to_refresh_hash_set: HashSet::default(),
4073 buffers_to_refresh_queue: VecDeque::new(),
4074 _background_diagnostics_worker: Task::ready(()).shared(),
4075 buffer_snapshots: Default::default(),
4076 prettier_store,
4077 environment,
4078 http_client,
4079 fs,
4080 yarn,
4081 next_diagnostic_group_id: Default::default(),
4082 diagnostics: Default::default(),
4083 _subscription: cx.on_app_quit(|this, cx| {
4084 this.as_local_mut()
4085 .unwrap()
4086 .shutdown_language_servers_on_quit(cx)
4087 }),
4088 lsp_tree: LanguageServerTree::new(
4089 manifest_tree,
4090 languages.clone(),
4091 toolchain_store.clone(),
4092 ),
4093 toolchain_store,
4094 registered_buffers: HashMap::default(),
4095 buffers_opened_in_servers: HashMap::default(),
4096 buffer_pull_diagnostics_result_ids: HashMap::default(),
4097 workspace_pull_diagnostics_result_ids: HashMap::default(),
4098 restricted_worktrees_tasks: HashMap::default(),
4099 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4100 .manifest_file_names(),
4101 }),
4102 last_formatting_failure: None,
4103 downstream_client: None,
4104 buffer_store,
4105 worktree_store,
4106 languages: languages.clone(),
4107 language_server_statuses: Default::default(),
4108 nonce: StdRng::from_os_rng().random(),
4109 diagnostic_summaries: HashMap::default(),
4110 lsp_server_capabilities: HashMap::default(),
4111 lsp_data: HashMap::default(),
4112 next_hint_id: Arc::default(),
4113 active_entry: None,
4114 _maintain_workspace_config,
4115 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4116 }
4117 }
4118
4119 fn send_lsp_proto_request<R: LspCommand>(
4120 &self,
4121 buffer: Entity<Buffer>,
4122 client: AnyProtoClient,
4123 upstream_project_id: u64,
4124 request: R,
4125 cx: &mut Context<LspStore>,
4126 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4127 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4128 return Task::ready(Ok(R::Response::default()));
4129 }
4130 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4131 cx.spawn(async move |this, cx| {
4132 let response = client.request(message).await?;
4133 let this = this.upgrade().context("project dropped")?;
4134 request
4135 .response_from_proto(response, this, buffer, cx.clone())
4136 .await
4137 })
4138 }
4139
4140 pub(super) fn new_remote(
4141 buffer_store: Entity<BufferStore>,
4142 worktree_store: Entity<WorktreeStore>,
4143 languages: Arc<LanguageRegistry>,
4144 upstream_client: AnyProtoClient,
4145 project_id: u64,
4146 cx: &mut Context<Self>,
4147 ) -> Self {
4148 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4149 .detach();
4150 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4151 .detach();
4152 subscribe_to_binary_statuses(&languages, cx).detach();
4153 let _maintain_workspace_config = {
4154 let (sender, receiver) = watch::channel();
4155 (Self::maintain_workspace_config(receiver, cx), sender)
4156 };
4157 Self {
4158 mode: LspStoreMode::Remote(RemoteLspStore {
4159 upstream_client: Some(upstream_client),
4160 upstream_project_id: project_id,
4161 }),
4162 downstream_client: None,
4163 last_formatting_failure: None,
4164 buffer_store,
4165 worktree_store,
4166 languages: languages.clone(),
4167 language_server_statuses: Default::default(),
4168 nonce: StdRng::from_os_rng().random(),
4169 diagnostic_summaries: HashMap::default(),
4170 lsp_server_capabilities: HashMap::default(),
4171 next_hint_id: Arc::default(),
4172 lsp_data: HashMap::default(),
4173 active_entry: None,
4174
4175 _maintain_workspace_config,
4176 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4177 }
4178 }
4179
4180 fn on_buffer_store_event(
4181 &mut self,
4182 _: Entity<BufferStore>,
4183 event: &BufferStoreEvent,
4184 cx: &mut Context<Self>,
4185 ) {
4186 match event {
4187 BufferStoreEvent::BufferAdded(buffer) => {
4188 self.on_buffer_added(buffer, cx).log_err();
4189 }
4190 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4191 let buffer_id = buffer.read(cx).remote_id();
4192 if let Some(local) = self.as_local_mut()
4193 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4194 {
4195 local.reset_buffer(buffer, old_file, cx);
4196
4197 if local.registered_buffers.contains_key(&buffer_id) {
4198 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4199 }
4200 }
4201
4202 self.detect_language_for_buffer(buffer, cx);
4203 if let Some(local) = self.as_local_mut() {
4204 local.initialize_buffer(buffer, cx);
4205 if local.registered_buffers.contains_key(&buffer_id) {
4206 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4207 }
4208 }
4209 }
4210 _ => {}
4211 }
4212 }
4213
4214 fn on_worktree_store_event(
4215 &mut self,
4216 _: Entity<WorktreeStore>,
4217 event: &WorktreeStoreEvent,
4218 cx: &mut Context<Self>,
4219 ) {
4220 match event {
4221 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4222 if !worktree.read(cx).is_local() {
4223 return;
4224 }
4225 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4226 worktree::Event::UpdatedEntries(changes) => {
4227 this.update_local_worktree_language_servers(&worktree, changes, cx);
4228 }
4229 worktree::Event::UpdatedGitRepositories(_)
4230 | worktree::Event::DeletedEntry(_) => {}
4231 })
4232 .detach()
4233 }
4234 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4235 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4236 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4237 }
4238 WorktreeStoreEvent::WorktreeReleased(..)
4239 | WorktreeStoreEvent::WorktreeOrderChanged
4240 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4241 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4242 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4243 }
4244 }
4245
4246 fn on_prettier_store_event(
4247 &mut self,
4248 _: Entity<PrettierStore>,
4249 event: &PrettierStoreEvent,
4250 cx: &mut Context<Self>,
4251 ) {
4252 match event {
4253 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4254 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4255 }
4256 PrettierStoreEvent::LanguageServerAdded {
4257 new_server_id,
4258 name,
4259 prettier_server,
4260 } => {
4261 self.register_supplementary_language_server(
4262 *new_server_id,
4263 name.clone(),
4264 prettier_server.clone(),
4265 cx,
4266 );
4267 }
4268 }
4269 }
4270
4271 fn on_toolchain_store_event(
4272 &mut self,
4273 _: Entity<LocalToolchainStore>,
4274 event: &ToolchainStoreEvent,
4275 _: &mut Context<Self>,
4276 ) {
4277 if let ToolchainStoreEvent::ToolchainActivated = event {
4278 self.request_workspace_config_refresh()
4279 }
4280 }
4281
4282 fn request_workspace_config_refresh(&mut self) {
4283 *self._maintain_workspace_config.1.borrow_mut() = ();
4284 }
4285
4286 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4287 self.as_local().map(|local| local.prettier_store.clone())
4288 }
4289
4290 fn on_buffer_event(
4291 &mut self,
4292 buffer: Entity<Buffer>,
4293 event: &language::BufferEvent,
4294 cx: &mut Context<Self>,
4295 ) {
4296 match event {
4297 language::BufferEvent::Edited => {
4298 self.on_buffer_edited(buffer, cx);
4299 }
4300
4301 language::BufferEvent::Saved => {
4302 self.on_buffer_saved(buffer, cx);
4303 }
4304
4305 _ => {}
4306 }
4307 }
4308
4309 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4310 buffer
4311 .read(cx)
4312 .set_language_registry(self.languages.clone());
4313
4314 cx.subscribe(buffer, |this, buffer, event, cx| {
4315 this.on_buffer_event(buffer, event, cx);
4316 })
4317 .detach();
4318
4319 self.detect_language_for_buffer(buffer, cx);
4320 if let Some(local) = self.as_local_mut() {
4321 local.initialize_buffer(buffer, cx);
4322 }
4323
4324 Ok(())
4325 }
4326
4327 pub fn refresh_background_diagnostics_for_buffers(
4328 &mut self,
4329 buffers: HashSet<BufferId>,
4330 cx: &mut Context<Self>,
4331 ) -> Shared<Task<()>> {
4332 let Some(local) = self.as_local_mut() else {
4333 return Task::ready(()).shared();
4334 };
4335 for buffer in buffers {
4336 if local.buffers_to_refresh_hash_set.insert(buffer) {
4337 local.buffers_to_refresh_queue.push_back(buffer);
4338 if local.buffers_to_refresh_queue.len() == 1 {
4339 local._background_diagnostics_worker =
4340 Self::background_diagnostics_worker(cx).shared();
4341 }
4342 }
4343 }
4344
4345 local._background_diagnostics_worker.clone()
4346 }
4347
4348 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4349 let buffer_store = self.buffer_store.clone();
4350 let local = self.as_local_mut()?;
4351 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4352 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4353 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4354 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4355 }
4356 }
4357 None
4358 }
4359
4360 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4361 cx.spawn(async move |this, cx| {
4362 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4363 task.await.log_err();
4364 }
4365 })
4366 }
4367
4368 pub(crate) fn register_buffer_with_language_servers(
4369 &mut self,
4370 buffer: &Entity<Buffer>,
4371 only_register_servers: HashSet<LanguageServerSelector>,
4372 ignore_refcounts: bool,
4373 cx: &mut Context<Self>,
4374 ) -> OpenLspBufferHandle {
4375 let buffer_id = buffer.read(cx).remote_id();
4376 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4377 if let Some(local) = self.as_local_mut() {
4378 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4379 if !ignore_refcounts {
4380 *refcount += 1;
4381 }
4382
4383 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4384 // 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
4385 // 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
4386 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4387 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4388 return handle;
4389 };
4390 if !file.is_local() {
4391 return handle;
4392 }
4393
4394 if ignore_refcounts || *refcount == 1 {
4395 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4396 }
4397 if !ignore_refcounts {
4398 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4399 let refcount = {
4400 let local = lsp_store.as_local_mut().unwrap();
4401 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4402 debug_panic!("bad refcounting");
4403 return;
4404 };
4405
4406 *refcount -= 1;
4407 *refcount
4408 };
4409 if refcount == 0 {
4410 lsp_store.lsp_data.remove(&buffer_id);
4411 let local = lsp_store.as_local_mut().unwrap();
4412 local.registered_buffers.remove(&buffer_id);
4413
4414 local.buffers_opened_in_servers.remove(&buffer_id);
4415 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4416 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4417
4418 let buffer_abs_path = file.abs_path(cx);
4419 for (_, buffer_pull_diagnostics_result_ids) in
4420 &mut local.buffer_pull_diagnostics_result_ids
4421 {
4422 buffer_pull_diagnostics_result_ids.retain(
4423 |_, buffer_result_ids| {
4424 buffer_result_ids.remove(&buffer_abs_path);
4425 !buffer_result_ids.is_empty()
4426 },
4427 );
4428 }
4429
4430 let diagnostic_updates = local
4431 .language_servers
4432 .keys()
4433 .cloned()
4434 .map(|server_id| DocumentDiagnosticsUpdate {
4435 diagnostics: DocumentDiagnostics {
4436 document_abs_path: buffer_abs_path.clone(),
4437 version: None,
4438 diagnostics: Vec::new(),
4439 },
4440 result_id: None,
4441 registration_id: None,
4442 server_id: server_id,
4443 disk_based_sources: Cow::Borrowed(&[]),
4444 })
4445 .collect::<Vec<_>>();
4446
4447 lsp_store
4448 .merge_diagnostic_entries(
4449 diagnostic_updates,
4450 |_, diagnostic, _| {
4451 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4452 },
4453 cx,
4454 )
4455 .context("Clearing diagnostics for the closed buffer")
4456 .log_err();
4457 }
4458 }
4459 })
4460 .detach();
4461 }
4462 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4463 let buffer_id = buffer.read(cx).remote_id().to_proto();
4464 cx.background_spawn(async move {
4465 upstream_client
4466 .request(proto::RegisterBufferWithLanguageServers {
4467 project_id: upstream_project_id,
4468 buffer_id,
4469 only_servers: only_register_servers
4470 .into_iter()
4471 .map(|selector| {
4472 let selector = match selector {
4473 LanguageServerSelector::Id(language_server_id) => {
4474 proto::language_server_selector::Selector::ServerId(
4475 language_server_id.to_proto(),
4476 )
4477 }
4478 LanguageServerSelector::Name(language_server_name) => {
4479 proto::language_server_selector::Selector::Name(
4480 language_server_name.to_string(),
4481 )
4482 }
4483 };
4484 proto::LanguageServerSelector {
4485 selector: Some(selector),
4486 }
4487 })
4488 .collect(),
4489 })
4490 .await
4491 })
4492 .detach();
4493 } else {
4494 // Our remote connection got closed
4495 }
4496 handle
4497 }
4498
4499 fn maintain_buffer_languages(
4500 languages: Arc<LanguageRegistry>,
4501 cx: &mut Context<Self>,
4502 ) -> Task<()> {
4503 let mut subscription = languages.subscribe();
4504 let mut prev_reload_count = languages.reload_count();
4505 cx.spawn(async move |this, cx| {
4506 while let Some(()) = subscription.next().await {
4507 if let Some(this) = this.upgrade() {
4508 // If the language registry has been reloaded, then remove and
4509 // re-assign the languages on all open buffers.
4510 let reload_count = languages.reload_count();
4511 if reload_count > prev_reload_count {
4512 prev_reload_count = reload_count;
4513 this.update(cx, |this, cx| {
4514 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4515 for buffer in buffer_store.buffers() {
4516 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4517 {
4518 buffer.update(cx, |buffer, cx| {
4519 buffer.set_language_async(None, cx)
4520 });
4521 if let Some(local) = this.as_local_mut() {
4522 local.reset_buffer(&buffer, &f, cx);
4523
4524 if local
4525 .registered_buffers
4526 .contains_key(&buffer.read(cx).remote_id())
4527 && let Some(file_url) =
4528 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4529 {
4530 local.unregister_buffer_from_language_servers(
4531 &buffer, &file_url, cx,
4532 );
4533 }
4534 }
4535 }
4536 }
4537 });
4538 });
4539 }
4540
4541 this.update(cx, |this, cx| {
4542 let mut plain_text_buffers = Vec::new();
4543 let mut buffers_with_unknown_injections = Vec::new();
4544 for handle in this.buffer_store.read(cx).buffers() {
4545 let buffer = handle.read(cx);
4546 if buffer.language().is_none()
4547 || buffer.language() == Some(&*language::PLAIN_TEXT)
4548 {
4549 plain_text_buffers.push(handle);
4550 } else if buffer.contains_unknown_injections() {
4551 buffers_with_unknown_injections.push(handle);
4552 }
4553 }
4554
4555 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4556 // and reused later in the invisible worktrees.
4557 plain_text_buffers.sort_by_key(|buffer| {
4558 Reverse(
4559 File::from_dyn(buffer.read(cx).file())
4560 .map(|file| file.worktree.read(cx).is_visible()),
4561 )
4562 });
4563
4564 for buffer in plain_text_buffers {
4565 this.detect_language_for_buffer(&buffer, cx);
4566 if let Some(local) = this.as_local_mut() {
4567 local.initialize_buffer(&buffer, cx);
4568 if local
4569 .registered_buffers
4570 .contains_key(&buffer.read(cx).remote_id())
4571 {
4572 local.register_buffer_with_language_servers(
4573 &buffer,
4574 HashSet::default(),
4575 cx,
4576 );
4577 }
4578 }
4579 }
4580
4581 for buffer in buffers_with_unknown_injections {
4582 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4583 }
4584 });
4585 }
4586 }
4587 })
4588 }
4589
4590 fn detect_language_for_buffer(
4591 &mut self,
4592 buffer_handle: &Entity<Buffer>,
4593 cx: &mut Context<Self>,
4594 ) -> Option<language::AvailableLanguage> {
4595 // If the buffer has a language, set it and start the language server if we haven't already.
4596 let buffer = buffer_handle.read(cx);
4597 let file = buffer.file()?;
4598
4599 let content = buffer.as_rope();
4600 let available_language = self.languages.language_for_file(file, Some(content), cx);
4601 if let Some(available_language) = &available_language {
4602 if let Some(Ok(Ok(new_language))) = self
4603 .languages
4604 .load_language(available_language)
4605 .now_or_never()
4606 {
4607 self.set_language_for_buffer(buffer_handle, new_language, cx);
4608 }
4609 } else {
4610 cx.emit(LspStoreEvent::LanguageDetected {
4611 buffer: buffer_handle.clone(),
4612 new_language: None,
4613 });
4614 }
4615
4616 available_language
4617 }
4618
4619 pub(crate) fn set_language_for_buffer(
4620 &mut self,
4621 buffer_entity: &Entity<Buffer>,
4622 new_language: Arc<Language>,
4623 cx: &mut Context<Self>,
4624 ) {
4625 let buffer = buffer_entity.read(cx);
4626 let buffer_file = buffer.file().cloned();
4627 let buffer_id = buffer.remote_id();
4628 if let Some(local_store) = self.as_local_mut()
4629 && local_store.registered_buffers.contains_key(&buffer_id)
4630 && let Some(abs_path) =
4631 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4632 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4633 {
4634 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4635 }
4636 buffer_entity.update(cx, |buffer, cx| {
4637 if buffer
4638 .language()
4639 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4640 {
4641 buffer.set_language_async(Some(new_language.clone()), cx);
4642 }
4643 });
4644
4645 let settings =
4646 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4647 let buffer_file = File::from_dyn(buffer_file.as_ref());
4648
4649 let worktree_id = if let Some(file) = buffer_file {
4650 let worktree = file.worktree.clone();
4651
4652 if let Some(local) = self.as_local_mut()
4653 && local.registered_buffers.contains_key(&buffer_id)
4654 {
4655 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4656 }
4657 Some(worktree.read(cx).id())
4658 } else {
4659 None
4660 };
4661
4662 if settings.prettier.allowed
4663 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4664 {
4665 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4666 if let Some(prettier_store) = prettier_store {
4667 prettier_store.update(cx, |prettier_store, cx| {
4668 prettier_store.install_default_prettier(
4669 worktree_id,
4670 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4671 cx,
4672 )
4673 })
4674 }
4675 }
4676
4677 cx.emit(LspStoreEvent::LanguageDetected {
4678 buffer: buffer_entity.clone(),
4679 new_language: Some(new_language),
4680 })
4681 }
4682
4683 pub fn buffer_store(&self) -> Entity<BufferStore> {
4684 self.buffer_store.clone()
4685 }
4686
4687 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4688 self.active_entry = active_entry;
4689 }
4690
4691 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4692 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4693 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4694 {
4695 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4696 summaries
4697 .iter()
4698 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4699 });
4700 if let Some(summary) = summaries.next() {
4701 client
4702 .send(proto::UpdateDiagnosticSummary {
4703 project_id: downstream_project_id,
4704 worktree_id: worktree.id().to_proto(),
4705 summary: Some(summary),
4706 more_summaries: summaries.collect(),
4707 })
4708 .log_err();
4709 }
4710 }
4711 }
4712
4713 fn is_capable_for_proto_request<R>(
4714 &self,
4715 buffer: &Entity<Buffer>,
4716 request: &R,
4717 cx: &App,
4718 ) -> bool
4719 where
4720 R: LspCommand,
4721 {
4722 self.check_if_capable_for_proto_request(
4723 buffer,
4724 |capabilities| {
4725 request.check_capabilities(AdapterServerCapabilities {
4726 server_capabilities: capabilities.clone(),
4727 code_action_kinds: None,
4728 })
4729 },
4730 cx,
4731 )
4732 }
4733
4734 fn check_if_capable_for_proto_request<F>(
4735 &self,
4736 buffer: &Entity<Buffer>,
4737 check: F,
4738 cx: &App,
4739 ) -> bool
4740 where
4741 F: FnMut(&lsp::ServerCapabilities) -> bool,
4742 {
4743 let Some(language) = buffer.read(cx).language().cloned() else {
4744 return false;
4745 };
4746 let registered_language_servers = self
4747 .languages
4748 .lsp_adapters(&language.name())
4749 .into_iter()
4750 .map(|lsp_adapter| lsp_adapter.name())
4751 .collect::<HashSet<_>>();
4752 self.language_server_statuses
4753 .iter()
4754 .filter_map(|(server_id, server_status)| {
4755 // Include servers that are either registered for this language OR
4756 // available to be loaded (for SSH remote mode where adapters like
4757 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4758 // but only loaded on the server side)
4759 let is_relevant = registered_language_servers.contains(&server_status.name)
4760 || self.languages.is_lsp_adapter_available(&server_status.name);
4761 is_relevant.then_some(server_id)
4762 })
4763 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4764 .any(check)
4765 }
4766
4767 fn all_capable_for_proto_request<F>(
4768 &self,
4769 buffer: &Entity<Buffer>,
4770 mut check: F,
4771 cx: &App,
4772 ) -> Vec<lsp::LanguageServerId>
4773 where
4774 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4775 {
4776 let Some(language) = buffer.read(cx).language().cloned() else {
4777 return Vec::default();
4778 };
4779 let registered_language_servers = self
4780 .languages
4781 .lsp_adapters(&language.name())
4782 .into_iter()
4783 .map(|lsp_adapter| lsp_adapter.name())
4784 .collect::<HashSet<_>>();
4785 self.language_server_statuses
4786 .iter()
4787 .filter_map(|(server_id, server_status)| {
4788 // Include servers that are either registered for this language OR
4789 // available to be loaded (for SSH remote mode where adapters like
4790 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4791 // but only loaded on the server side)
4792 let is_relevant = registered_language_servers.contains(&server_status.name)
4793 || self.languages.is_lsp_adapter_available(&server_status.name);
4794 is_relevant.then_some((server_id, &server_status.name))
4795 })
4796 .filter_map(|(server_id, server_name)| {
4797 self.lsp_server_capabilities
4798 .get(server_id)
4799 .map(|c| (server_id, server_name, c))
4800 })
4801 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4802 .map(|(server_id, _, _)| *server_id)
4803 .collect()
4804 }
4805
4806 pub fn request_lsp<R>(
4807 &mut self,
4808 buffer: Entity<Buffer>,
4809 server: LanguageServerToQuery,
4810 request: R,
4811 cx: &mut Context<Self>,
4812 ) -> Task<Result<R::Response>>
4813 where
4814 R: LspCommand,
4815 <R::LspRequest as lsp::request::Request>::Result: Send,
4816 <R::LspRequest as lsp::request::Request>::Params: Send,
4817 {
4818 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4819 return self.send_lsp_proto_request(
4820 buffer,
4821 upstream_client,
4822 upstream_project_id,
4823 request,
4824 cx,
4825 );
4826 }
4827
4828 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4829 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4830 local
4831 .language_servers_for_buffer(buffer, cx)
4832 .find(|(_, server)| {
4833 request.check_capabilities(server.adapter_server_capabilities())
4834 })
4835 .map(|(_, server)| server.clone())
4836 }),
4837 LanguageServerToQuery::Other(id) => self
4838 .language_server_for_local_buffer(buffer, id, cx)
4839 .and_then(|(_, server)| {
4840 request
4841 .check_capabilities(server.adapter_server_capabilities())
4842 .then(|| Arc::clone(server))
4843 }),
4844 }) else {
4845 return Task::ready(Ok(Default::default()));
4846 };
4847
4848 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4849
4850 let Some(file) = file else {
4851 return Task::ready(Ok(Default::default()));
4852 };
4853
4854 let lsp_params = match request.to_lsp_params_or_response(
4855 &file.abs_path(cx),
4856 buffer.read(cx),
4857 &language_server,
4858 cx,
4859 ) {
4860 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4861 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4862 Err(err) => {
4863 let message = format!(
4864 "{} via {} failed: {}",
4865 request.display_name(),
4866 language_server.name(),
4867 err
4868 );
4869 // rust-analyzer likes to error with this when its still loading up
4870 if !message.ends_with("content modified") {
4871 log::warn!("{message}");
4872 }
4873 return Task::ready(Err(anyhow!(message)));
4874 }
4875 };
4876
4877 let status = request.status();
4878 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4879 return Task::ready(Ok(Default::default()));
4880 }
4881 cx.spawn(async move |this, cx| {
4882 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4883
4884 let id = lsp_request.id();
4885 let _cleanup = if status.is_some() {
4886 cx.update(|cx| {
4887 this.update(cx, |this, cx| {
4888 this.on_lsp_work_start(
4889 language_server.server_id(),
4890 ProgressToken::Number(id),
4891 LanguageServerProgress {
4892 is_disk_based_diagnostics_progress: false,
4893 is_cancellable: false,
4894 title: None,
4895 message: status.clone(),
4896 percentage: None,
4897 last_update_at: cx.background_executor().now(),
4898 },
4899 cx,
4900 );
4901 })
4902 })
4903 .log_err();
4904
4905 Some(defer(|| {
4906 cx.update(|cx| {
4907 this.update(cx, |this, cx| {
4908 this.on_lsp_work_end(
4909 language_server.server_id(),
4910 ProgressToken::Number(id),
4911 cx,
4912 );
4913 })
4914 })
4915 .log_err();
4916 }))
4917 } else {
4918 None
4919 };
4920
4921 let result = lsp_request.await.into_response();
4922
4923 let response = result.map_err(|err| {
4924 let message = format!(
4925 "{} via {} failed: {}",
4926 request.display_name(),
4927 language_server.name(),
4928 err
4929 );
4930 // rust-analyzer likes to error with this when its still loading up
4931 if !message.ends_with("content modified") {
4932 log::warn!("{message}");
4933 }
4934 anyhow::anyhow!(message)
4935 })?;
4936
4937 request
4938 .response_from_lsp(
4939 response,
4940 this.upgrade().context("no app context")?,
4941 buffer,
4942 language_server.server_id(),
4943 cx.clone(),
4944 )
4945 .await
4946 })
4947 }
4948
4949 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4950 let mut language_formatters_to_check = Vec::new();
4951 for buffer in self.buffer_store.read(cx).buffers() {
4952 let buffer = buffer.read(cx);
4953 let buffer_file = File::from_dyn(buffer.file());
4954 let buffer_language = buffer.language();
4955 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4956 if buffer_language.is_some() {
4957 language_formatters_to_check.push((
4958 buffer_file.map(|f| f.worktree_id(cx)),
4959 settings.into_owned(),
4960 ));
4961 }
4962 }
4963
4964 self.request_workspace_config_refresh();
4965
4966 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4967 prettier_store.update(cx, |prettier_store, cx| {
4968 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4969 })
4970 }
4971
4972 cx.notify();
4973 }
4974
4975 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4976 let buffer_store = self.buffer_store.clone();
4977 let Some(local) = self.as_local_mut() else {
4978 return;
4979 };
4980 let mut adapters = BTreeMap::default();
4981 let get_adapter = {
4982 let languages = local.languages.clone();
4983 let environment = local.environment.clone();
4984 let weak = local.weak.clone();
4985 let worktree_store = local.worktree_store.clone();
4986 let http_client = local.http_client.clone();
4987 let fs = local.fs.clone();
4988 move |worktree_id, cx: &mut App| {
4989 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4990 Some(LocalLspAdapterDelegate::new(
4991 languages.clone(),
4992 &environment,
4993 weak.clone(),
4994 &worktree,
4995 http_client.clone(),
4996 fs.clone(),
4997 cx,
4998 ))
4999 }
5000 };
5001
5002 let mut messages_to_report = Vec::new();
5003 let (new_tree, to_stop) = {
5004 let mut rebase = local.lsp_tree.rebase();
5005 let buffers = buffer_store
5006 .read(cx)
5007 .buffers()
5008 .filter_map(|buffer| {
5009 let raw_buffer = buffer.read(cx);
5010 if !local
5011 .registered_buffers
5012 .contains_key(&raw_buffer.remote_id())
5013 {
5014 return None;
5015 }
5016 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5017 let language = raw_buffer.language().cloned()?;
5018 Some((file, language, raw_buffer.remote_id()))
5019 })
5020 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5021 for (file, language, buffer_id) in buffers {
5022 let worktree_id = file.worktree_id(cx);
5023 let Some(worktree) = local
5024 .worktree_store
5025 .read(cx)
5026 .worktree_for_id(worktree_id, cx)
5027 else {
5028 continue;
5029 };
5030
5031 if let Some((_, apply)) = local.reuse_existing_language_server(
5032 rebase.server_tree(),
5033 &worktree,
5034 &language.name(),
5035 cx,
5036 ) {
5037 (apply)(rebase.server_tree());
5038 } else if let Some(lsp_delegate) = adapters
5039 .entry(worktree_id)
5040 .or_insert_with(|| get_adapter(worktree_id, cx))
5041 .clone()
5042 {
5043 let delegate =
5044 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5045 let path = file
5046 .path()
5047 .parent()
5048 .map(Arc::from)
5049 .unwrap_or_else(|| file.path().clone());
5050 let worktree_path = ProjectPath { worktree_id, path };
5051 let abs_path = file.abs_path(cx);
5052 let nodes = rebase
5053 .walk(
5054 worktree_path,
5055 language.name(),
5056 language.manifest(),
5057 delegate.clone(),
5058 cx,
5059 )
5060 .collect::<Vec<_>>();
5061 for node in nodes {
5062 let server_id = node.server_id_or_init(|disposition| {
5063 let path = &disposition.path;
5064 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5065 let key = LanguageServerSeed {
5066 worktree_id,
5067 name: disposition.server_name.clone(),
5068 settings: LanguageServerSeedSettings {
5069 binary: disposition.settings.binary.clone(),
5070 initialization_options: disposition
5071 .settings
5072 .initialization_options
5073 .clone(),
5074 },
5075 toolchain: local.toolchain_store.read(cx).active_toolchain(
5076 path.worktree_id,
5077 &path.path,
5078 language.name(),
5079 ),
5080 };
5081 local.language_server_ids.remove(&key);
5082
5083 let server_id = local.get_or_insert_language_server(
5084 &worktree,
5085 lsp_delegate.clone(),
5086 disposition,
5087 &language.name(),
5088 cx,
5089 );
5090 if let Some(state) = local.language_servers.get(&server_id)
5091 && let Ok(uri) = uri
5092 {
5093 state.add_workspace_folder(uri);
5094 };
5095 server_id
5096 });
5097
5098 if let Some(language_server_id) = server_id {
5099 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5100 language_server_id,
5101 name: node.name(),
5102 message:
5103 proto::update_language_server::Variant::RegisteredForBuffer(
5104 proto::RegisteredForBuffer {
5105 buffer_abs_path: abs_path
5106 .to_string_lossy()
5107 .into_owned(),
5108 buffer_id: buffer_id.to_proto(),
5109 },
5110 ),
5111 });
5112 }
5113 }
5114 } else {
5115 continue;
5116 }
5117 }
5118 rebase.finish()
5119 };
5120 for message in messages_to_report {
5121 cx.emit(message);
5122 }
5123 local.lsp_tree = new_tree;
5124 for (id, _) in to_stop {
5125 self.stop_local_language_server(id, cx).detach();
5126 }
5127 }
5128
5129 pub fn apply_code_action(
5130 &self,
5131 buffer_handle: Entity<Buffer>,
5132 mut action: CodeAction,
5133 push_to_history: bool,
5134 cx: &mut Context<Self>,
5135 ) -> Task<Result<ProjectTransaction>> {
5136 if let Some((upstream_client, project_id)) = self.upstream_client() {
5137 let request = proto::ApplyCodeAction {
5138 project_id,
5139 buffer_id: buffer_handle.read(cx).remote_id().into(),
5140 action: Some(Self::serialize_code_action(&action)),
5141 };
5142 let buffer_store = self.buffer_store();
5143 cx.spawn(async move |_, cx| {
5144 let response = upstream_client
5145 .request(request)
5146 .await?
5147 .transaction
5148 .context("missing transaction")?;
5149
5150 buffer_store
5151 .update(cx, |buffer_store, cx| {
5152 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5153 })
5154 .await
5155 })
5156 } else if self.mode.is_local() {
5157 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5158 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5159 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5160 }) else {
5161 return Task::ready(Ok(ProjectTransaction::default()));
5162 };
5163 cx.spawn(async move |this, cx| {
5164 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5165 .await
5166 .context("resolving a code action")?;
5167 if let Some(edit) = action.lsp_action.edit()
5168 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5169 return LocalLspStore::deserialize_workspace_edit(
5170 this.upgrade().context("no app present")?,
5171 edit.clone(),
5172 push_to_history,
5173
5174 lang_server.clone(),
5175 cx,
5176 )
5177 .await;
5178 }
5179
5180 if let Some(command) = action.lsp_action.command() {
5181 let server_capabilities = lang_server.capabilities();
5182 let available_commands = server_capabilities
5183 .execute_command_provider
5184 .as_ref()
5185 .map(|options| options.commands.as_slice())
5186 .unwrap_or_default();
5187 if available_commands.contains(&command.command) {
5188 this.update(cx, |this, _| {
5189 this.as_local_mut()
5190 .unwrap()
5191 .last_workspace_edits_by_language_server
5192 .remove(&lang_server.server_id());
5193 })?;
5194
5195 let _result = lang_server
5196 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5197 command: command.command.clone(),
5198 arguments: command.arguments.clone().unwrap_or_default(),
5199 ..lsp::ExecuteCommandParams::default()
5200 })
5201 .await.into_response()
5202 .context("execute command")?;
5203
5204 return this.update(cx, |this, _| {
5205 this.as_local_mut()
5206 .unwrap()
5207 .last_workspace_edits_by_language_server
5208 .remove(&lang_server.server_id())
5209 .unwrap_or_default()
5210 });
5211 } else {
5212 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5213 }
5214 }
5215
5216 Ok(ProjectTransaction::default())
5217 })
5218 } else {
5219 Task::ready(Err(anyhow!("no upstream client and not local")))
5220 }
5221 }
5222
5223 pub fn apply_code_action_kind(
5224 &mut self,
5225 buffers: HashSet<Entity<Buffer>>,
5226 kind: CodeActionKind,
5227 push_to_history: bool,
5228 cx: &mut Context<Self>,
5229 ) -> Task<anyhow::Result<ProjectTransaction>> {
5230 if self.as_local().is_some() {
5231 cx.spawn(async move |lsp_store, cx| {
5232 let buffers = buffers.into_iter().collect::<Vec<_>>();
5233 let result = LocalLspStore::execute_code_action_kind_locally(
5234 lsp_store.clone(),
5235 buffers,
5236 kind,
5237 push_to_history,
5238 cx,
5239 )
5240 .await;
5241 lsp_store.update(cx, |lsp_store, _| {
5242 lsp_store.update_last_formatting_failure(&result);
5243 })?;
5244 result
5245 })
5246 } else if let Some((client, project_id)) = self.upstream_client() {
5247 let buffer_store = self.buffer_store();
5248 cx.spawn(async move |lsp_store, cx| {
5249 let result = client
5250 .request(proto::ApplyCodeActionKind {
5251 project_id,
5252 kind: kind.as_str().to_owned(),
5253 buffer_ids: buffers
5254 .iter()
5255 .map(|buffer| {
5256 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5257 })
5258 .collect(),
5259 })
5260 .await
5261 .and_then(|result| result.transaction.context("missing transaction"));
5262 lsp_store.update(cx, |lsp_store, _| {
5263 lsp_store.update_last_formatting_failure(&result);
5264 })?;
5265
5266 let transaction_response = result?;
5267 buffer_store
5268 .update(cx, |buffer_store, cx| {
5269 buffer_store.deserialize_project_transaction(
5270 transaction_response,
5271 push_to_history,
5272 cx,
5273 )
5274 })
5275 .await
5276 })
5277 } else {
5278 Task::ready(Ok(ProjectTransaction::default()))
5279 }
5280 }
5281
5282 pub fn resolved_hint(
5283 &mut self,
5284 buffer_id: BufferId,
5285 id: InlayId,
5286 cx: &mut Context<Self>,
5287 ) -> Option<ResolvedHint> {
5288 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5289
5290 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5291 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5292 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5293 let (server_id, resolve_data) = match &hint.resolve_state {
5294 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5295 ResolveState::Resolving => {
5296 return Some(ResolvedHint::Resolving(
5297 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5298 ));
5299 }
5300 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5301 };
5302
5303 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5304 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5305 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5306 id,
5307 cx.spawn(async move |lsp_store, cx| {
5308 let resolved_hint = resolve_task.await;
5309 lsp_store
5310 .update(cx, |lsp_store, _| {
5311 if let Some(old_inlay_hint) = lsp_store
5312 .lsp_data
5313 .get_mut(&buffer_id)
5314 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5315 {
5316 match resolved_hint {
5317 Ok(resolved_hint) => {
5318 *old_inlay_hint = resolved_hint;
5319 }
5320 Err(e) => {
5321 old_inlay_hint.resolve_state =
5322 ResolveState::CanResolve(server_id, resolve_data);
5323 log::error!("Inlay hint resolve failed: {e:#}");
5324 }
5325 }
5326 }
5327 })
5328 .ok();
5329 })
5330 .shared(),
5331 );
5332 debug_assert!(
5333 previous_task.is_none(),
5334 "Did not change hint's resolve state after spawning its resolve"
5335 );
5336 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5337 None
5338 }
5339
5340 fn resolve_inlay_hint(
5341 &self,
5342 mut hint: InlayHint,
5343 buffer: Entity<Buffer>,
5344 server_id: LanguageServerId,
5345 cx: &mut Context<Self>,
5346 ) -> Task<anyhow::Result<InlayHint>> {
5347 if let Some((upstream_client, project_id)) = self.upstream_client() {
5348 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5349 {
5350 hint.resolve_state = ResolveState::Resolved;
5351 return Task::ready(Ok(hint));
5352 }
5353 let request = proto::ResolveInlayHint {
5354 project_id,
5355 buffer_id: buffer.read(cx).remote_id().into(),
5356 language_server_id: server_id.0 as u64,
5357 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5358 };
5359 cx.background_spawn(async move {
5360 let response = upstream_client
5361 .request(request)
5362 .await
5363 .context("inlay hints proto request")?;
5364 match response.hint {
5365 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5366 .context("inlay hints proto resolve response conversion"),
5367 None => Ok(hint),
5368 }
5369 })
5370 } else {
5371 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5372 self.language_server_for_local_buffer(buffer, server_id, cx)
5373 .map(|(_, server)| server.clone())
5374 }) else {
5375 return Task::ready(Ok(hint));
5376 };
5377 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5378 return Task::ready(Ok(hint));
5379 }
5380 let buffer_snapshot = buffer.read(cx).snapshot();
5381 cx.spawn(async move |_, cx| {
5382 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5383 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5384 );
5385 let resolved_hint = resolve_task
5386 .await
5387 .into_response()
5388 .context("inlay hint resolve LSP request")?;
5389 let resolved_hint = InlayHints::lsp_to_project_hint(
5390 resolved_hint,
5391 &buffer,
5392 server_id,
5393 ResolveState::Resolved,
5394 false,
5395 cx,
5396 )
5397 .await?;
5398 Ok(resolved_hint)
5399 })
5400 }
5401 }
5402
5403 pub fn resolve_color_presentation(
5404 &mut self,
5405 mut color: DocumentColor,
5406 buffer: Entity<Buffer>,
5407 server_id: LanguageServerId,
5408 cx: &mut Context<Self>,
5409 ) -> Task<Result<DocumentColor>> {
5410 if color.resolved {
5411 return Task::ready(Ok(color));
5412 }
5413
5414 if let Some((upstream_client, project_id)) = self.upstream_client() {
5415 let start = color.lsp_range.start;
5416 let end = color.lsp_range.end;
5417 let request = proto::GetColorPresentation {
5418 project_id,
5419 server_id: server_id.to_proto(),
5420 buffer_id: buffer.read(cx).remote_id().into(),
5421 color: Some(proto::ColorInformation {
5422 red: color.color.red,
5423 green: color.color.green,
5424 blue: color.color.blue,
5425 alpha: color.color.alpha,
5426 lsp_range_start: Some(proto::PointUtf16 {
5427 row: start.line,
5428 column: start.character,
5429 }),
5430 lsp_range_end: Some(proto::PointUtf16 {
5431 row: end.line,
5432 column: end.character,
5433 }),
5434 }),
5435 };
5436 cx.background_spawn(async move {
5437 let response = upstream_client
5438 .request(request)
5439 .await
5440 .context("color presentation proto request")?;
5441 color.resolved = true;
5442 color.color_presentations = response
5443 .presentations
5444 .into_iter()
5445 .map(|presentation| ColorPresentation {
5446 label: SharedString::from(presentation.label),
5447 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5448 additional_text_edits: presentation
5449 .additional_text_edits
5450 .into_iter()
5451 .filter_map(deserialize_lsp_edit)
5452 .collect(),
5453 })
5454 .collect();
5455 Ok(color)
5456 })
5457 } else {
5458 let path = match buffer
5459 .update(cx, |buffer, cx| {
5460 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5461 })
5462 .context("buffer with the missing path")
5463 {
5464 Ok(path) => path,
5465 Err(e) => return Task::ready(Err(e)),
5466 };
5467 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5468 self.language_server_for_local_buffer(buffer, server_id, cx)
5469 .map(|(_, server)| server.clone())
5470 }) else {
5471 return Task::ready(Ok(color));
5472 };
5473 cx.background_spawn(async move {
5474 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5475 lsp::ColorPresentationParams {
5476 text_document: make_text_document_identifier(&path)?,
5477 color: color.color,
5478 range: color.lsp_range,
5479 work_done_progress_params: Default::default(),
5480 partial_result_params: Default::default(),
5481 },
5482 );
5483 color.color_presentations = resolve_task
5484 .await
5485 .into_response()
5486 .context("color presentation resolve LSP request")?
5487 .into_iter()
5488 .map(|presentation| ColorPresentation {
5489 label: SharedString::from(presentation.label),
5490 text_edit: presentation.text_edit,
5491 additional_text_edits: presentation
5492 .additional_text_edits
5493 .unwrap_or_default(),
5494 })
5495 .collect();
5496 color.resolved = true;
5497 Ok(color)
5498 })
5499 }
5500 }
5501
5502 pub(crate) fn linked_edits(
5503 &mut self,
5504 buffer: &Entity<Buffer>,
5505 position: Anchor,
5506 cx: &mut Context<Self>,
5507 ) -> Task<Result<Vec<Range<Anchor>>>> {
5508 let snapshot = buffer.read(cx).snapshot();
5509 let scope = snapshot.language_scope_at(position);
5510 let Some(server_id) = self
5511 .as_local()
5512 .and_then(|local| {
5513 buffer.update(cx, |buffer, cx| {
5514 local
5515 .language_servers_for_buffer(buffer, cx)
5516 .filter(|(_, server)| {
5517 LinkedEditingRange::check_server_capabilities(server.capabilities())
5518 })
5519 .filter(|(adapter, _)| {
5520 scope
5521 .as_ref()
5522 .map(|scope| scope.language_allowed(&adapter.name))
5523 .unwrap_or(true)
5524 })
5525 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5526 .next()
5527 })
5528 })
5529 .or_else(|| {
5530 self.upstream_client()
5531 .is_some()
5532 .then_some(LanguageServerToQuery::FirstCapable)
5533 })
5534 .filter(|_| {
5535 maybe!({
5536 let language = buffer.read(cx).language_at(position)?;
5537 Some(
5538 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5539 .linked_edits,
5540 )
5541 }) == Some(true)
5542 })
5543 else {
5544 return Task::ready(Ok(Vec::new()));
5545 };
5546
5547 self.request_lsp(
5548 buffer.clone(),
5549 server_id,
5550 LinkedEditingRange { position },
5551 cx,
5552 )
5553 }
5554
5555 fn apply_on_type_formatting(
5556 &mut self,
5557 buffer: Entity<Buffer>,
5558 position: Anchor,
5559 trigger: String,
5560 cx: &mut Context<Self>,
5561 ) -> Task<Result<Option<Transaction>>> {
5562 if let Some((client, project_id)) = self.upstream_client() {
5563 if !self.check_if_capable_for_proto_request(
5564 &buffer,
5565 |capabilities| {
5566 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5567 },
5568 cx,
5569 ) {
5570 return Task::ready(Ok(None));
5571 }
5572 let request = proto::OnTypeFormatting {
5573 project_id,
5574 buffer_id: buffer.read(cx).remote_id().into(),
5575 position: Some(serialize_anchor(&position)),
5576 trigger,
5577 version: serialize_version(&buffer.read(cx).version()),
5578 };
5579 cx.background_spawn(async move {
5580 client
5581 .request(request)
5582 .await?
5583 .transaction
5584 .map(language::proto::deserialize_transaction)
5585 .transpose()
5586 })
5587 } else if let Some(local) = self.as_local_mut() {
5588 let buffer_id = buffer.read(cx).remote_id();
5589 local.buffers_being_formatted.insert(buffer_id);
5590 cx.spawn(async move |this, cx| {
5591 let _cleanup = defer({
5592 let this = this.clone();
5593 let mut cx = cx.clone();
5594 move || {
5595 this.update(&mut cx, |this, _| {
5596 if let Some(local) = this.as_local_mut() {
5597 local.buffers_being_formatted.remove(&buffer_id);
5598 }
5599 })
5600 .ok();
5601 }
5602 });
5603
5604 buffer
5605 .update(cx, |buffer, _| {
5606 buffer.wait_for_edits(Some(position.timestamp))
5607 })
5608 .await?;
5609 this.update(cx, |this, cx| {
5610 let position = position.to_point_utf16(buffer.read(cx));
5611 this.on_type_format(buffer, position, trigger, false, cx)
5612 })?
5613 .await
5614 })
5615 } else {
5616 Task::ready(Err(anyhow!("No upstream client or local language server")))
5617 }
5618 }
5619
5620 pub fn on_type_format<T: ToPointUtf16>(
5621 &mut self,
5622 buffer: Entity<Buffer>,
5623 position: T,
5624 trigger: String,
5625 push_to_history: bool,
5626 cx: &mut Context<Self>,
5627 ) -> Task<Result<Option<Transaction>>> {
5628 let position = position.to_point_utf16(buffer.read(cx));
5629 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5630 }
5631
5632 fn on_type_format_impl(
5633 &mut self,
5634 buffer: Entity<Buffer>,
5635 position: PointUtf16,
5636 trigger: String,
5637 push_to_history: bool,
5638 cx: &mut Context<Self>,
5639 ) -> Task<Result<Option<Transaction>>> {
5640 let options = buffer.update(cx, |buffer, cx| {
5641 lsp_command::lsp_formatting_options(
5642 language_settings(
5643 buffer.language_at(position).map(|l| l.name()),
5644 buffer.file(),
5645 cx,
5646 )
5647 .as_ref(),
5648 )
5649 });
5650
5651 cx.spawn(async move |this, cx| {
5652 if let Some(waiter) =
5653 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5654 {
5655 waiter.await?;
5656 }
5657 cx.update(|cx| {
5658 this.update(cx, |this, cx| {
5659 this.request_lsp(
5660 buffer.clone(),
5661 LanguageServerToQuery::FirstCapable,
5662 OnTypeFormatting {
5663 position,
5664 trigger,
5665 options,
5666 push_to_history,
5667 },
5668 cx,
5669 )
5670 })
5671 })?
5672 .await
5673 })
5674 }
5675
5676 pub fn definitions(
5677 &mut self,
5678 buffer: &Entity<Buffer>,
5679 position: PointUtf16,
5680 cx: &mut Context<Self>,
5681 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5682 if let Some((upstream_client, project_id)) = self.upstream_client() {
5683 let request = GetDefinitions { position };
5684 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5685 return Task::ready(Ok(None));
5686 }
5687 let request_task = upstream_client.request_lsp(
5688 project_id,
5689 None,
5690 LSP_REQUEST_TIMEOUT,
5691 cx.background_executor().clone(),
5692 request.to_proto(project_id, buffer.read(cx)),
5693 );
5694 let buffer = buffer.clone();
5695 cx.spawn(async move |weak_lsp_store, cx| {
5696 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5697 return Ok(None);
5698 };
5699 let Some(responses) = request_task.await? else {
5700 return Ok(None);
5701 };
5702 let actions = join_all(responses.payload.into_iter().map(|response| {
5703 GetDefinitions { position }.response_from_proto(
5704 response.response,
5705 lsp_store.clone(),
5706 buffer.clone(),
5707 cx.clone(),
5708 )
5709 }))
5710 .await;
5711
5712 Ok(Some(
5713 actions
5714 .into_iter()
5715 .collect::<Result<Vec<Vec<_>>>>()?
5716 .into_iter()
5717 .flatten()
5718 .dedup()
5719 .collect(),
5720 ))
5721 })
5722 } else {
5723 let definitions_task = self.request_multiple_lsp_locally(
5724 buffer,
5725 Some(position),
5726 GetDefinitions { position },
5727 cx,
5728 );
5729 cx.background_spawn(async move {
5730 Ok(Some(
5731 definitions_task
5732 .await
5733 .into_iter()
5734 .flat_map(|(_, definitions)| definitions)
5735 .dedup()
5736 .collect(),
5737 ))
5738 })
5739 }
5740 }
5741
5742 pub fn declarations(
5743 &mut self,
5744 buffer: &Entity<Buffer>,
5745 position: PointUtf16,
5746 cx: &mut Context<Self>,
5747 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5748 if let Some((upstream_client, project_id)) = self.upstream_client() {
5749 let request = GetDeclarations { position };
5750 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5751 return Task::ready(Ok(None));
5752 }
5753 let request_task = upstream_client.request_lsp(
5754 project_id,
5755 None,
5756 LSP_REQUEST_TIMEOUT,
5757 cx.background_executor().clone(),
5758 request.to_proto(project_id, buffer.read(cx)),
5759 );
5760 let buffer = buffer.clone();
5761 cx.spawn(async move |weak_lsp_store, cx| {
5762 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5763 return Ok(None);
5764 };
5765 let Some(responses) = request_task.await? else {
5766 return Ok(None);
5767 };
5768 let actions = join_all(responses.payload.into_iter().map(|response| {
5769 GetDeclarations { position }.response_from_proto(
5770 response.response,
5771 lsp_store.clone(),
5772 buffer.clone(),
5773 cx.clone(),
5774 )
5775 }))
5776 .await;
5777
5778 Ok(Some(
5779 actions
5780 .into_iter()
5781 .collect::<Result<Vec<Vec<_>>>>()?
5782 .into_iter()
5783 .flatten()
5784 .dedup()
5785 .collect(),
5786 ))
5787 })
5788 } else {
5789 let declarations_task = self.request_multiple_lsp_locally(
5790 buffer,
5791 Some(position),
5792 GetDeclarations { position },
5793 cx,
5794 );
5795 cx.background_spawn(async move {
5796 Ok(Some(
5797 declarations_task
5798 .await
5799 .into_iter()
5800 .flat_map(|(_, declarations)| declarations)
5801 .dedup()
5802 .collect(),
5803 ))
5804 })
5805 }
5806 }
5807
5808 pub fn type_definitions(
5809 &mut self,
5810 buffer: &Entity<Buffer>,
5811 position: PointUtf16,
5812 cx: &mut Context<Self>,
5813 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5814 if let Some((upstream_client, project_id)) = self.upstream_client() {
5815 let request = GetTypeDefinitions { position };
5816 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5817 return Task::ready(Ok(None));
5818 }
5819 let request_task = upstream_client.request_lsp(
5820 project_id,
5821 None,
5822 LSP_REQUEST_TIMEOUT,
5823 cx.background_executor().clone(),
5824 request.to_proto(project_id, buffer.read(cx)),
5825 );
5826 let buffer = buffer.clone();
5827 cx.spawn(async move |weak_lsp_store, cx| {
5828 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5829 return Ok(None);
5830 };
5831 let Some(responses) = request_task.await? else {
5832 return Ok(None);
5833 };
5834 let actions = join_all(responses.payload.into_iter().map(|response| {
5835 GetTypeDefinitions { position }.response_from_proto(
5836 response.response,
5837 lsp_store.clone(),
5838 buffer.clone(),
5839 cx.clone(),
5840 )
5841 }))
5842 .await;
5843
5844 Ok(Some(
5845 actions
5846 .into_iter()
5847 .collect::<Result<Vec<Vec<_>>>>()?
5848 .into_iter()
5849 .flatten()
5850 .dedup()
5851 .collect(),
5852 ))
5853 })
5854 } else {
5855 let type_definitions_task = self.request_multiple_lsp_locally(
5856 buffer,
5857 Some(position),
5858 GetTypeDefinitions { position },
5859 cx,
5860 );
5861 cx.background_spawn(async move {
5862 Ok(Some(
5863 type_definitions_task
5864 .await
5865 .into_iter()
5866 .flat_map(|(_, type_definitions)| type_definitions)
5867 .dedup()
5868 .collect(),
5869 ))
5870 })
5871 }
5872 }
5873
5874 pub fn implementations(
5875 &mut self,
5876 buffer: &Entity<Buffer>,
5877 position: PointUtf16,
5878 cx: &mut Context<Self>,
5879 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5880 if let Some((upstream_client, project_id)) = self.upstream_client() {
5881 let request = GetImplementations { position };
5882 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5883 return Task::ready(Ok(None));
5884 }
5885 let request_task = upstream_client.request_lsp(
5886 project_id,
5887 None,
5888 LSP_REQUEST_TIMEOUT,
5889 cx.background_executor().clone(),
5890 request.to_proto(project_id, buffer.read(cx)),
5891 );
5892 let buffer = buffer.clone();
5893 cx.spawn(async move |weak_lsp_store, cx| {
5894 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5895 return Ok(None);
5896 };
5897 let Some(responses) = request_task.await? else {
5898 return Ok(None);
5899 };
5900 let actions = join_all(responses.payload.into_iter().map(|response| {
5901 GetImplementations { position }.response_from_proto(
5902 response.response,
5903 lsp_store.clone(),
5904 buffer.clone(),
5905 cx.clone(),
5906 )
5907 }))
5908 .await;
5909
5910 Ok(Some(
5911 actions
5912 .into_iter()
5913 .collect::<Result<Vec<Vec<_>>>>()?
5914 .into_iter()
5915 .flatten()
5916 .dedup()
5917 .collect(),
5918 ))
5919 })
5920 } else {
5921 let implementations_task = self.request_multiple_lsp_locally(
5922 buffer,
5923 Some(position),
5924 GetImplementations { position },
5925 cx,
5926 );
5927 cx.background_spawn(async move {
5928 Ok(Some(
5929 implementations_task
5930 .await
5931 .into_iter()
5932 .flat_map(|(_, implementations)| implementations)
5933 .dedup()
5934 .collect(),
5935 ))
5936 })
5937 }
5938 }
5939
5940 pub fn references(
5941 &mut self,
5942 buffer: &Entity<Buffer>,
5943 position: PointUtf16,
5944 cx: &mut Context<Self>,
5945 ) -> Task<Result<Option<Vec<Location>>>> {
5946 if let Some((upstream_client, project_id)) = self.upstream_client() {
5947 let request = GetReferences { position };
5948 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5949 return Task::ready(Ok(None));
5950 }
5951
5952 let request_task = upstream_client.request_lsp(
5953 project_id,
5954 None,
5955 LSP_REQUEST_TIMEOUT,
5956 cx.background_executor().clone(),
5957 request.to_proto(project_id, buffer.read(cx)),
5958 );
5959 let buffer = buffer.clone();
5960 cx.spawn(async move |weak_lsp_store, cx| {
5961 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5962 return Ok(None);
5963 };
5964 let Some(responses) = request_task.await? else {
5965 return Ok(None);
5966 };
5967
5968 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5969 GetReferences { position }.response_from_proto(
5970 lsp_response.response,
5971 lsp_store.clone(),
5972 buffer.clone(),
5973 cx.clone(),
5974 )
5975 }))
5976 .await
5977 .into_iter()
5978 .collect::<Result<Vec<Vec<_>>>>()?
5979 .into_iter()
5980 .flatten()
5981 .dedup()
5982 .collect();
5983 Ok(Some(locations))
5984 })
5985 } else {
5986 let references_task = self.request_multiple_lsp_locally(
5987 buffer,
5988 Some(position),
5989 GetReferences { position },
5990 cx,
5991 );
5992 cx.background_spawn(async move {
5993 Ok(Some(
5994 references_task
5995 .await
5996 .into_iter()
5997 .flat_map(|(_, references)| references)
5998 .dedup()
5999 .collect(),
6000 ))
6001 })
6002 }
6003 }
6004
6005 pub fn code_actions(
6006 &mut self,
6007 buffer: &Entity<Buffer>,
6008 range: Range<Anchor>,
6009 kinds: Option<Vec<CodeActionKind>>,
6010 cx: &mut Context<Self>,
6011 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6012 if let Some((upstream_client, project_id)) = self.upstream_client() {
6013 let request = GetCodeActions {
6014 range: range.clone(),
6015 kinds: kinds.clone(),
6016 };
6017 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6018 return Task::ready(Ok(None));
6019 }
6020 let request_task = upstream_client.request_lsp(
6021 project_id,
6022 None,
6023 LSP_REQUEST_TIMEOUT,
6024 cx.background_executor().clone(),
6025 request.to_proto(project_id, buffer.read(cx)),
6026 );
6027 let buffer = buffer.clone();
6028 cx.spawn(async move |weak_lsp_store, cx| {
6029 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6030 return Ok(None);
6031 };
6032 let Some(responses) = request_task.await? else {
6033 return Ok(None);
6034 };
6035 let actions = join_all(responses.payload.into_iter().map(|response| {
6036 GetCodeActions {
6037 range: range.clone(),
6038 kinds: kinds.clone(),
6039 }
6040 .response_from_proto(
6041 response.response,
6042 lsp_store.clone(),
6043 buffer.clone(),
6044 cx.clone(),
6045 )
6046 }))
6047 .await;
6048
6049 Ok(Some(
6050 actions
6051 .into_iter()
6052 .collect::<Result<Vec<Vec<_>>>>()?
6053 .into_iter()
6054 .flatten()
6055 .collect(),
6056 ))
6057 })
6058 } else {
6059 let all_actions_task = self.request_multiple_lsp_locally(
6060 buffer,
6061 Some(range.start),
6062 GetCodeActions { range, kinds },
6063 cx,
6064 );
6065 cx.background_spawn(async move {
6066 Ok(Some(
6067 all_actions_task
6068 .await
6069 .into_iter()
6070 .flat_map(|(_, actions)| actions)
6071 .collect(),
6072 ))
6073 })
6074 }
6075 }
6076
6077 pub fn code_lens_actions(
6078 &mut self,
6079 buffer: &Entity<Buffer>,
6080 cx: &mut Context<Self>,
6081 ) -> CodeLensTask {
6082 let version_queried_for = buffer.read(cx).version();
6083 let buffer_id = buffer.read(cx).remote_id();
6084 let existing_servers = self.as_local().map(|local| {
6085 local
6086 .buffers_opened_in_servers
6087 .get(&buffer_id)
6088 .cloned()
6089 .unwrap_or_default()
6090 });
6091
6092 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6093 if let Some(cached_lens) = &lsp_data.code_lens {
6094 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6095 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6096 existing_servers != cached_lens.lens.keys().copied().collect()
6097 });
6098 if !has_different_servers {
6099 return Task::ready(Ok(Some(
6100 cached_lens.lens.values().flatten().cloned().collect(),
6101 )))
6102 .shared();
6103 }
6104 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6105 if !version_queried_for.changed_since(updating_for) {
6106 return running_update.clone();
6107 }
6108 }
6109 }
6110 }
6111
6112 let lens_lsp_data = self
6113 .latest_lsp_data(buffer, cx)
6114 .code_lens
6115 .get_or_insert_default();
6116 let buffer = buffer.clone();
6117 let query_version_queried_for = version_queried_for.clone();
6118 let new_task = cx
6119 .spawn(async move |lsp_store, cx| {
6120 cx.background_executor()
6121 .timer(Duration::from_millis(30))
6122 .await;
6123 let fetched_lens = lsp_store
6124 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6125 .map_err(Arc::new)?
6126 .await
6127 .context("fetching code lens")
6128 .map_err(Arc::new);
6129 let fetched_lens = match fetched_lens {
6130 Ok(fetched_lens) => fetched_lens,
6131 Err(e) => {
6132 lsp_store
6133 .update(cx, |lsp_store, _| {
6134 if let Some(lens_lsp_data) = lsp_store
6135 .lsp_data
6136 .get_mut(&buffer_id)
6137 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6138 {
6139 lens_lsp_data.update = None;
6140 }
6141 })
6142 .ok();
6143 return Err(e);
6144 }
6145 };
6146
6147 lsp_store
6148 .update(cx, |lsp_store, _| {
6149 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6150 let code_lens = lsp_data.code_lens.as_mut()?;
6151 if let Some(fetched_lens) = fetched_lens {
6152 if lsp_data.buffer_version == query_version_queried_for {
6153 code_lens.lens.extend(fetched_lens);
6154 } else if !lsp_data
6155 .buffer_version
6156 .changed_since(&query_version_queried_for)
6157 {
6158 lsp_data.buffer_version = query_version_queried_for;
6159 code_lens.lens = fetched_lens;
6160 }
6161 }
6162 code_lens.update = None;
6163 Some(code_lens.lens.values().flatten().cloned().collect())
6164 })
6165 .map_err(Arc::new)
6166 })
6167 .shared();
6168 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6169 new_task
6170 }
6171
6172 fn fetch_code_lens(
6173 &mut self,
6174 buffer: &Entity<Buffer>,
6175 cx: &mut Context<Self>,
6176 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6177 if let Some((upstream_client, project_id)) = self.upstream_client() {
6178 let request = GetCodeLens;
6179 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6180 return Task::ready(Ok(None));
6181 }
6182 let request_task = upstream_client.request_lsp(
6183 project_id,
6184 None,
6185 LSP_REQUEST_TIMEOUT,
6186 cx.background_executor().clone(),
6187 request.to_proto(project_id, buffer.read(cx)),
6188 );
6189 let buffer = buffer.clone();
6190 cx.spawn(async move |weak_lsp_store, cx| {
6191 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6192 return Ok(None);
6193 };
6194 let Some(responses) = request_task.await? else {
6195 return Ok(None);
6196 };
6197
6198 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6199 let lsp_store = lsp_store.clone();
6200 let buffer = buffer.clone();
6201 let cx = cx.clone();
6202 async move {
6203 (
6204 LanguageServerId::from_proto(response.server_id),
6205 GetCodeLens
6206 .response_from_proto(response.response, lsp_store, buffer, cx)
6207 .await,
6208 )
6209 }
6210 }))
6211 .await;
6212
6213 let mut has_errors = false;
6214 let code_lens_actions = code_lens_actions
6215 .into_iter()
6216 .filter_map(|(server_id, code_lens)| match code_lens {
6217 Ok(code_lens) => Some((server_id, code_lens)),
6218 Err(e) => {
6219 has_errors = true;
6220 log::error!("{e:#}");
6221 None
6222 }
6223 })
6224 .collect::<HashMap<_, _>>();
6225 anyhow::ensure!(
6226 !has_errors || !code_lens_actions.is_empty(),
6227 "Failed to fetch code lens"
6228 );
6229 Ok(Some(code_lens_actions))
6230 })
6231 } else {
6232 let code_lens_actions_task =
6233 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6234 cx.background_spawn(async move {
6235 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6236 })
6237 }
6238 }
6239
6240 #[inline(never)]
6241 pub fn completions(
6242 &self,
6243 buffer: &Entity<Buffer>,
6244 position: PointUtf16,
6245 context: CompletionContext,
6246 cx: &mut Context<Self>,
6247 ) -> Task<Result<Vec<CompletionResponse>>> {
6248 let language_registry = self.languages.clone();
6249
6250 if let Some((upstream_client, project_id)) = self.upstream_client() {
6251 let snapshot = buffer.read(cx).snapshot();
6252 let offset = position.to_offset(&snapshot);
6253 let scope = snapshot.language_scope_at(offset);
6254 let capable_lsps = self.all_capable_for_proto_request(
6255 buffer,
6256 |server_name, capabilities| {
6257 capabilities.completion_provider.is_some()
6258 && scope
6259 .as_ref()
6260 .map(|scope| scope.language_allowed(server_name))
6261 .unwrap_or(true)
6262 },
6263 cx,
6264 );
6265 if capable_lsps.is_empty() {
6266 return Task::ready(Ok(Vec::new()));
6267 }
6268
6269 let language = buffer.read(cx).language().cloned();
6270
6271 // In the future, we should provide project guests with the names of LSP adapters,
6272 // so that they can use the correct LSP adapter when computing labels. For now,
6273 // guests just use the first LSP adapter associated with the buffer's language.
6274 let lsp_adapter = language.as_ref().and_then(|language| {
6275 language_registry
6276 .lsp_adapters(&language.name())
6277 .first()
6278 .cloned()
6279 });
6280
6281 let buffer = buffer.clone();
6282
6283 cx.spawn(async move |this, cx| {
6284 let requests = join_all(
6285 capable_lsps
6286 .into_iter()
6287 .map(|id| {
6288 let request = GetCompletions {
6289 position,
6290 context: context.clone(),
6291 server_id: Some(id),
6292 };
6293 let buffer = buffer.clone();
6294 let language = language.clone();
6295 let lsp_adapter = lsp_adapter.clone();
6296 let upstream_client = upstream_client.clone();
6297 let response = this
6298 .update(cx, |this, cx| {
6299 this.send_lsp_proto_request(
6300 buffer,
6301 upstream_client,
6302 project_id,
6303 request,
6304 cx,
6305 )
6306 })
6307 .log_err();
6308 async move {
6309 let response = response?.await.log_err()?;
6310
6311 let completions = populate_labels_for_completions(
6312 response.completions,
6313 language,
6314 lsp_adapter,
6315 )
6316 .await;
6317
6318 Some(CompletionResponse {
6319 completions,
6320 display_options: CompletionDisplayOptions::default(),
6321 is_incomplete: response.is_incomplete,
6322 })
6323 }
6324 })
6325 .collect::<Vec<_>>(),
6326 );
6327 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6328 })
6329 } else if let Some(local) = self.as_local() {
6330 let snapshot = buffer.read(cx).snapshot();
6331 let offset = position.to_offset(&snapshot);
6332 let scope = snapshot.language_scope_at(offset);
6333 let language = snapshot.language().cloned();
6334 let completion_settings = language_settings(
6335 language.as_ref().map(|language| language.name()),
6336 buffer.read(cx).file(),
6337 cx,
6338 )
6339 .completions
6340 .clone();
6341 if !completion_settings.lsp {
6342 return Task::ready(Ok(Vec::new()));
6343 }
6344
6345 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6346 local
6347 .language_servers_for_buffer(buffer, cx)
6348 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6349 .filter(|(adapter, _)| {
6350 scope
6351 .as_ref()
6352 .map(|scope| scope.language_allowed(&adapter.name))
6353 .unwrap_or(true)
6354 })
6355 .map(|(_, server)| server.server_id())
6356 .collect()
6357 });
6358
6359 let buffer = buffer.clone();
6360 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6361 let lsp_timeout = if lsp_timeout > 0 {
6362 Some(Duration::from_millis(lsp_timeout))
6363 } else {
6364 None
6365 };
6366 cx.spawn(async move |this, cx| {
6367 let mut tasks = Vec::with_capacity(server_ids.len());
6368 this.update(cx, |lsp_store, cx| {
6369 for server_id in server_ids {
6370 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6371 let lsp_timeout = lsp_timeout
6372 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6373 let mut timeout = cx.background_spawn(async move {
6374 match lsp_timeout {
6375 Some(lsp_timeout) => {
6376 lsp_timeout.await;
6377 true
6378 },
6379 None => false,
6380 }
6381 }).fuse();
6382 let mut lsp_request = lsp_store.request_lsp(
6383 buffer.clone(),
6384 LanguageServerToQuery::Other(server_id),
6385 GetCompletions {
6386 position,
6387 context: context.clone(),
6388 server_id: Some(server_id),
6389 },
6390 cx,
6391 ).fuse();
6392 let new_task = cx.background_spawn(async move {
6393 select_biased! {
6394 response = lsp_request => anyhow::Ok(Some(response?)),
6395 timeout_happened = timeout => {
6396 if timeout_happened {
6397 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6398 Ok(None)
6399 } else {
6400 let completions = lsp_request.await?;
6401 Ok(Some(completions))
6402 }
6403 },
6404 }
6405 });
6406 tasks.push((lsp_adapter, new_task));
6407 }
6408 })?;
6409
6410 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6411 let completion_response = task.await.ok()??;
6412 let completions = populate_labels_for_completions(
6413 completion_response.completions,
6414 language.clone(),
6415 lsp_adapter,
6416 )
6417 .await;
6418 Some(CompletionResponse {
6419 completions,
6420 display_options: CompletionDisplayOptions::default(),
6421 is_incomplete: completion_response.is_incomplete,
6422 })
6423 });
6424
6425 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6426
6427 Ok(responses.into_iter().flatten().collect())
6428 })
6429 } else {
6430 Task::ready(Err(anyhow!("No upstream client or local language server")))
6431 }
6432 }
6433
6434 pub fn resolve_completions(
6435 &self,
6436 buffer: Entity<Buffer>,
6437 completion_indices: Vec<usize>,
6438 completions: Rc<RefCell<Box<[Completion]>>>,
6439 cx: &mut Context<Self>,
6440 ) -> Task<Result<bool>> {
6441 let client = self.upstream_client();
6442 let buffer_id = buffer.read(cx).remote_id();
6443 let buffer_snapshot = buffer.read(cx).snapshot();
6444
6445 if !self.check_if_capable_for_proto_request(
6446 &buffer,
6447 GetCompletions::can_resolve_completions,
6448 cx,
6449 ) {
6450 return Task::ready(Ok(false));
6451 }
6452 cx.spawn(async move |lsp_store, cx| {
6453 let mut did_resolve = false;
6454 if let Some((client, project_id)) = client {
6455 for completion_index in completion_indices {
6456 let server_id = {
6457 let completion = &completions.borrow()[completion_index];
6458 completion.source.server_id()
6459 };
6460 if let Some(server_id) = server_id {
6461 if Self::resolve_completion_remote(
6462 project_id,
6463 server_id,
6464 buffer_id,
6465 completions.clone(),
6466 completion_index,
6467 client.clone(),
6468 )
6469 .await
6470 .log_err()
6471 .is_some()
6472 {
6473 did_resolve = true;
6474 }
6475 } else {
6476 resolve_word_completion(
6477 &buffer_snapshot,
6478 &mut completions.borrow_mut()[completion_index],
6479 );
6480 }
6481 }
6482 } else {
6483 for completion_index in completion_indices {
6484 let server_id = {
6485 let completion = &completions.borrow()[completion_index];
6486 completion.source.server_id()
6487 };
6488 if let Some(server_id) = server_id {
6489 let server_and_adapter = lsp_store
6490 .read_with(cx, |lsp_store, _| {
6491 let server = lsp_store.language_server_for_id(server_id)?;
6492 let adapter =
6493 lsp_store.language_server_adapter_for_id(server.server_id())?;
6494 Some((server, adapter))
6495 })
6496 .ok()
6497 .flatten();
6498 let Some((server, adapter)) = server_and_adapter else {
6499 continue;
6500 };
6501
6502 let resolved = Self::resolve_completion_local(
6503 server,
6504 completions.clone(),
6505 completion_index,
6506 )
6507 .await
6508 .log_err()
6509 .is_some();
6510 if resolved {
6511 Self::regenerate_completion_labels(
6512 adapter,
6513 &buffer_snapshot,
6514 completions.clone(),
6515 completion_index,
6516 )
6517 .await
6518 .log_err();
6519 did_resolve = true;
6520 }
6521 } else {
6522 resolve_word_completion(
6523 &buffer_snapshot,
6524 &mut completions.borrow_mut()[completion_index],
6525 );
6526 }
6527 }
6528 }
6529
6530 Ok(did_resolve)
6531 })
6532 }
6533
6534 async fn resolve_completion_local(
6535 server: Arc<lsp::LanguageServer>,
6536 completions: Rc<RefCell<Box<[Completion]>>>,
6537 completion_index: usize,
6538 ) -> Result<()> {
6539 let server_id = server.server_id();
6540 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6541 return Ok(());
6542 }
6543
6544 let request = {
6545 let completion = &completions.borrow()[completion_index];
6546 match &completion.source {
6547 CompletionSource::Lsp {
6548 lsp_completion,
6549 resolved,
6550 server_id: completion_server_id,
6551 ..
6552 } => {
6553 if *resolved {
6554 return Ok(());
6555 }
6556 anyhow::ensure!(
6557 server_id == *completion_server_id,
6558 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6559 );
6560 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6561 }
6562 CompletionSource::BufferWord { .. }
6563 | CompletionSource::Dap { .. }
6564 | CompletionSource::Custom => {
6565 return Ok(());
6566 }
6567 }
6568 };
6569 let resolved_completion = request
6570 .await
6571 .into_response()
6572 .context("resolve completion")?;
6573
6574 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6575 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6576
6577 let mut completions = completions.borrow_mut();
6578 let completion = &mut completions[completion_index];
6579 if let CompletionSource::Lsp {
6580 lsp_completion,
6581 resolved,
6582 server_id: completion_server_id,
6583 ..
6584 } = &mut completion.source
6585 {
6586 if *resolved {
6587 return Ok(());
6588 }
6589 anyhow::ensure!(
6590 server_id == *completion_server_id,
6591 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6592 );
6593 **lsp_completion = resolved_completion;
6594 *resolved = true;
6595 }
6596 Ok(())
6597 }
6598
6599 async fn regenerate_completion_labels(
6600 adapter: Arc<CachedLspAdapter>,
6601 snapshot: &BufferSnapshot,
6602 completions: Rc<RefCell<Box<[Completion]>>>,
6603 completion_index: usize,
6604 ) -> Result<()> {
6605 let completion_item = completions.borrow()[completion_index]
6606 .source
6607 .lsp_completion(true)
6608 .map(Cow::into_owned);
6609 if let Some(lsp_documentation) = completion_item
6610 .as_ref()
6611 .and_then(|completion_item| completion_item.documentation.clone())
6612 {
6613 let mut completions = completions.borrow_mut();
6614 let completion = &mut completions[completion_index];
6615 completion.documentation = Some(lsp_documentation.into());
6616 } else {
6617 let mut completions = completions.borrow_mut();
6618 let completion = &mut completions[completion_index];
6619 completion.documentation = Some(CompletionDocumentation::Undocumented);
6620 }
6621
6622 let mut new_label = match completion_item {
6623 Some(completion_item) => {
6624 // Some language servers always return `detail` lazily via resolve, regardless of
6625 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6626 // See: https://github.com/yioneko/vtsls/issues/213
6627 let language = snapshot.language();
6628 match language {
6629 Some(language) => {
6630 adapter
6631 .labels_for_completions(
6632 std::slice::from_ref(&completion_item),
6633 language,
6634 )
6635 .await?
6636 }
6637 None => Vec::new(),
6638 }
6639 .pop()
6640 .flatten()
6641 .unwrap_or_else(|| {
6642 CodeLabel::fallback_for_completion(
6643 &completion_item,
6644 language.map(|language| language.as_ref()),
6645 )
6646 })
6647 }
6648 None => CodeLabel::plain(
6649 completions.borrow()[completion_index].new_text.clone(),
6650 None,
6651 ),
6652 };
6653 ensure_uniform_list_compatible_label(&mut new_label);
6654
6655 let mut completions = completions.borrow_mut();
6656 let completion = &mut completions[completion_index];
6657 if completion.label.filter_text() == new_label.filter_text() {
6658 completion.label = new_label;
6659 } else {
6660 log::error!(
6661 "Resolved completion changed display label from {} to {}. \
6662 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6663 completion.label.text(),
6664 new_label.text(),
6665 completion.label.filter_text(),
6666 new_label.filter_text()
6667 );
6668 }
6669
6670 Ok(())
6671 }
6672
6673 async fn resolve_completion_remote(
6674 project_id: u64,
6675 server_id: LanguageServerId,
6676 buffer_id: BufferId,
6677 completions: Rc<RefCell<Box<[Completion]>>>,
6678 completion_index: usize,
6679 client: AnyProtoClient,
6680 ) -> Result<()> {
6681 let lsp_completion = {
6682 let completion = &completions.borrow()[completion_index];
6683 match &completion.source {
6684 CompletionSource::Lsp {
6685 lsp_completion,
6686 resolved,
6687 server_id: completion_server_id,
6688 ..
6689 } => {
6690 anyhow::ensure!(
6691 server_id == *completion_server_id,
6692 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6693 );
6694 if *resolved {
6695 return Ok(());
6696 }
6697 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6698 }
6699 CompletionSource::Custom
6700 | CompletionSource::Dap { .. }
6701 | CompletionSource::BufferWord { .. } => {
6702 return Ok(());
6703 }
6704 }
6705 };
6706 let request = proto::ResolveCompletionDocumentation {
6707 project_id,
6708 language_server_id: server_id.0 as u64,
6709 lsp_completion,
6710 buffer_id: buffer_id.into(),
6711 };
6712
6713 let response = client
6714 .request(request)
6715 .await
6716 .context("completion documentation resolve proto request")?;
6717 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6718
6719 let documentation = if response.documentation.is_empty() {
6720 CompletionDocumentation::Undocumented
6721 } else if response.documentation_is_markdown {
6722 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6723 } else if response.documentation.lines().count() <= 1 {
6724 CompletionDocumentation::SingleLine(response.documentation.into())
6725 } else {
6726 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6727 };
6728
6729 let mut completions = completions.borrow_mut();
6730 let completion = &mut completions[completion_index];
6731 completion.documentation = Some(documentation);
6732 if let CompletionSource::Lsp {
6733 insert_range,
6734 lsp_completion,
6735 resolved,
6736 server_id: completion_server_id,
6737 lsp_defaults: _,
6738 } = &mut completion.source
6739 {
6740 let completion_insert_range = response
6741 .old_insert_start
6742 .and_then(deserialize_anchor)
6743 .zip(response.old_insert_end.and_then(deserialize_anchor));
6744 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6745
6746 if *resolved {
6747 return Ok(());
6748 }
6749 anyhow::ensure!(
6750 server_id == *completion_server_id,
6751 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6752 );
6753 **lsp_completion = resolved_lsp_completion;
6754 *resolved = true;
6755 }
6756
6757 let replace_range = response
6758 .old_replace_start
6759 .and_then(deserialize_anchor)
6760 .zip(response.old_replace_end.and_then(deserialize_anchor));
6761 if let Some((old_replace_start, old_replace_end)) = replace_range
6762 && !response.new_text.is_empty()
6763 {
6764 completion.new_text = response.new_text;
6765 completion.replace_range = old_replace_start..old_replace_end;
6766 }
6767
6768 Ok(())
6769 }
6770
6771 pub fn apply_additional_edits_for_completion(
6772 &self,
6773 buffer_handle: Entity<Buffer>,
6774 completions: Rc<RefCell<Box<[Completion]>>>,
6775 completion_index: usize,
6776 push_to_history: bool,
6777 cx: &mut Context<Self>,
6778 ) -> Task<Result<Option<Transaction>>> {
6779 if let Some((client, project_id)) = self.upstream_client() {
6780 let buffer = buffer_handle.read(cx);
6781 let buffer_id = buffer.remote_id();
6782 cx.spawn(async move |_, cx| {
6783 let request = {
6784 let completion = completions.borrow()[completion_index].clone();
6785 proto::ApplyCompletionAdditionalEdits {
6786 project_id,
6787 buffer_id: buffer_id.into(),
6788 completion: Some(Self::serialize_completion(&CoreCompletion {
6789 replace_range: completion.replace_range,
6790 new_text: completion.new_text,
6791 source: completion.source,
6792 })),
6793 }
6794 };
6795
6796 if let Some(transaction) = client.request(request).await?.transaction {
6797 let transaction = language::proto::deserialize_transaction(transaction)?;
6798 buffer_handle
6799 .update(cx, |buffer, _| {
6800 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6801 })
6802 .await?;
6803 if push_to_history {
6804 buffer_handle.update(cx, |buffer, _| {
6805 buffer.push_transaction(transaction.clone(), Instant::now());
6806 buffer.finalize_last_transaction();
6807 });
6808 }
6809 Ok(Some(transaction))
6810 } else {
6811 Ok(None)
6812 }
6813 })
6814 } else {
6815 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6816 let completion = &completions.borrow()[completion_index];
6817 let server_id = completion.source.server_id()?;
6818 Some(
6819 self.language_server_for_local_buffer(buffer, server_id, cx)?
6820 .1
6821 .clone(),
6822 )
6823 }) else {
6824 return Task::ready(Ok(None));
6825 };
6826
6827 cx.spawn(async move |this, cx| {
6828 Self::resolve_completion_local(
6829 server.clone(),
6830 completions.clone(),
6831 completion_index,
6832 )
6833 .await
6834 .context("resolving completion")?;
6835 let completion = completions.borrow()[completion_index].clone();
6836 let additional_text_edits = completion
6837 .source
6838 .lsp_completion(true)
6839 .as_ref()
6840 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6841 if let Some(edits) = additional_text_edits {
6842 let edits = this
6843 .update(cx, |this, cx| {
6844 this.as_local_mut().unwrap().edits_from_lsp(
6845 &buffer_handle,
6846 edits,
6847 server.server_id(),
6848 None,
6849 cx,
6850 )
6851 })?
6852 .await?;
6853
6854 buffer_handle.update(cx, |buffer, cx| {
6855 buffer.finalize_last_transaction();
6856 buffer.start_transaction();
6857
6858 for (range, text) in edits {
6859 let primary = &completion.replace_range;
6860
6861 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6862 // and the primary completion is just an insertion (empty range), then this is likely
6863 // an auto-import scenario and should not be considered overlapping
6864 // https://github.com/zed-industries/zed/issues/26136
6865 let is_file_start_auto_import = {
6866 let snapshot = buffer.snapshot();
6867 let primary_start_point = primary.start.to_point(&snapshot);
6868 let range_start_point = range.start.to_point(&snapshot);
6869
6870 let result = primary_start_point.row == 0
6871 && primary_start_point.column == 0
6872 && range_start_point.row == 0
6873 && range_start_point.column == 0;
6874
6875 result
6876 };
6877
6878 let has_overlap = if is_file_start_auto_import {
6879 false
6880 } else {
6881 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6882 && primary.end.cmp(&range.start, buffer).is_ge();
6883 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6884 && range.end.cmp(&primary.end, buffer).is_ge();
6885 let result = start_within || end_within;
6886 result
6887 };
6888
6889 //Skip additional edits which overlap with the primary completion edit
6890 //https://github.com/zed-industries/zed/pull/1871
6891 if !has_overlap {
6892 buffer.edit([(range, text)], None, cx);
6893 }
6894 }
6895
6896 let transaction = if buffer.end_transaction(cx).is_some() {
6897 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6898 if !push_to_history {
6899 buffer.forget_transaction(transaction.id);
6900 }
6901 Some(transaction)
6902 } else {
6903 None
6904 };
6905 Ok(transaction)
6906 })
6907 } else {
6908 Ok(None)
6909 }
6910 })
6911 }
6912 }
6913
6914 pub fn pull_diagnostics(
6915 &mut self,
6916 buffer: Entity<Buffer>,
6917 cx: &mut Context<Self>,
6918 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6919 let buffer_id = buffer.read(cx).remote_id();
6920
6921 if let Some((client, upstream_project_id)) = self.upstream_client() {
6922 let mut suitable_capabilities = None;
6923 // Are we capable for proto request?
6924 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6925 &buffer,
6926 |capabilities| {
6927 if let Some(caps) = &capabilities.diagnostic_provider {
6928 suitable_capabilities = Some(caps.clone());
6929 true
6930 } else {
6931 false
6932 }
6933 },
6934 cx,
6935 );
6936 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6937 let Some(dynamic_caps) = suitable_capabilities else {
6938 return Task::ready(Ok(None));
6939 };
6940 assert!(any_server_has_diagnostics_provider);
6941
6942 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6943 let request = GetDocumentDiagnostics {
6944 previous_result_id: None,
6945 identifier,
6946 registration_id: None,
6947 };
6948 let request_task = client.request_lsp(
6949 upstream_project_id,
6950 None,
6951 LSP_REQUEST_TIMEOUT,
6952 cx.background_executor().clone(),
6953 request.to_proto(upstream_project_id, buffer.read(cx)),
6954 );
6955 cx.background_spawn(async move {
6956 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6957 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6958 // Do not attempt to further process the dummy responses here.
6959 let _response = request_task.await?;
6960 Ok(None)
6961 })
6962 } else {
6963 let servers = buffer.update(cx, |buffer, cx| {
6964 self.running_language_servers_for_local_buffer(buffer, cx)
6965 .map(|(_, server)| server.clone())
6966 .collect::<Vec<_>>()
6967 });
6968
6969 let pull_diagnostics = servers
6970 .into_iter()
6971 .flat_map(|server| {
6972 let result = maybe!({
6973 let local = self.as_local()?;
6974 let server_id = server.server_id();
6975 let providers_with_identifiers = local
6976 .language_server_dynamic_registrations
6977 .get(&server_id)
6978 .into_iter()
6979 .flat_map(|registrations| registrations.diagnostics.clone())
6980 .collect::<Vec<_>>();
6981 Some(
6982 providers_with_identifiers
6983 .into_iter()
6984 .map(|(registration_id, dynamic_caps)| {
6985 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6986 let registration_id = registration_id.map(SharedString::from);
6987 let result_id = self.result_id_for_buffer_pull(
6988 server_id,
6989 buffer_id,
6990 ®istration_id,
6991 cx,
6992 );
6993 self.request_lsp(
6994 buffer.clone(),
6995 LanguageServerToQuery::Other(server_id),
6996 GetDocumentDiagnostics {
6997 previous_result_id: result_id,
6998 registration_id,
6999 identifier,
7000 },
7001 cx,
7002 )
7003 })
7004 .collect::<Vec<_>>(),
7005 )
7006 });
7007
7008 result.unwrap_or_default()
7009 })
7010 .collect::<Vec<_>>();
7011
7012 cx.background_spawn(async move {
7013 let mut responses = Vec::new();
7014 for diagnostics in join_all(pull_diagnostics).await {
7015 responses.extend(diagnostics?);
7016 }
7017 Ok(Some(responses))
7018 })
7019 }
7020 }
7021
7022 pub fn applicable_inlay_chunks(
7023 &mut self,
7024 buffer: &Entity<Buffer>,
7025 ranges: &[Range<text::Anchor>],
7026 cx: &mut Context<Self>,
7027 ) -> Vec<Range<BufferRow>> {
7028 let buffer_snapshot = buffer.read(cx).snapshot();
7029 let ranges = ranges
7030 .iter()
7031 .map(|range| range.to_point(&buffer_snapshot))
7032 .collect::<Vec<_>>();
7033
7034 self.latest_lsp_data(buffer, cx)
7035 .inlay_hints
7036 .applicable_chunks(ranges.as_slice())
7037 .map(|chunk| chunk.row_range())
7038 .collect()
7039 }
7040
7041 pub fn invalidate_inlay_hints<'a>(
7042 &'a mut self,
7043 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7044 ) {
7045 for buffer_id in for_buffers {
7046 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7047 lsp_data.inlay_hints.clear();
7048 }
7049 }
7050 }
7051
7052 pub fn inlay_hints(
7053 &mut self,
7054 invalidate: InvalidationStrategy,
7055 buffer: Entity<Buffer>,
7056 ranges: Vec<Range<text::Anchor>>,
7057 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7058 cx: &mut Context<Self>,
7059 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7060 let next_hint_id = self.next_hint_id.clone();
7061 let lsp_data = self.latest_lsp_data(&buffer, cx);
7062 let query_version = lsp_data.buffer_version.clone();
7063 let mut lsp_refresh_requested = false;
7064 let for_server = if let InvalidationStrategy::RefreshRequested {
7065 server_id,
7066 request_id,
7067 } = invalidate
7068 {
7069 let invalidated = lsp_data
7070 .inlay_hints
7071 .invalidate_for_server_refresh(server_id, request_id);
7072 lsp_refresh_requested = invalidated;
7073 Some(server_id)
7074 } else {
7075 None
7076 };
7077 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7078 let known_chunks = known_chunks
7079 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7080 .map(|(_, known_chunks)| known_chunks)
7081 .unwrap_or_default();
7082
7083 let buffer_snapshot = buffer.read(cx).snapshot();
7084 let ranges = ranges
7085 .iter()
7086 .map(|range| range.to_point(&buffer_snapshot))
7087 .collect::<Vec<_>>();
7088
7089 let mut hint_fetch_tasks = Vec::new();
7090 let mut cached_inlay_hints = None;
7091 let mut ranges_to_query = None;
7092 let applicable_chunks = existing_inlay_hints
7093 .applicable_chunks(ranges.as_slice())
7094 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7095 .collect::<Vec<_>>();
7096 if applicable_chunks.is_empty() {
7097 return HashMap::default();
7098 }
7099
7100 for row_chunk in applicable_chunks {
7101 match (
7102 existing_inlay_hints
7103 .cached_hints(&row_chunk)
7104 .filter(|_| !lsp_refresh_requested)
7105 .cloned(),
7106 existing_inlay_hints
7107 .fetched_hints(&row_chunk)
7108 .as_ref()
7109 .filter(|_| !lsp_refresh_requested)
7110 .cloned(),
7111 ) {
7112 (None, None) => {
7113 let chunk_range = row_chunk.anchor_range();
7114 ranges_to_query
7115 .get_or_insert_with(Vec::new)
7116 .push((row_chunk, chunk_range));
7117 }
7118 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7119 (Some(cached_hints), None) => {
7120 for (server_id, cached_hints) in cached_hints {
7121 if for_server.is_none_or(|for_server| for_server == server_id) {
7122 cached_inlay_hints
7123 .get_or_insert_with(HashMap::default)
7124 .entry(row_chunk.row_range())
7125 .or_insert_with(HashMap::default)
7126 .entry(server_id)
7127 .or_insert_with(Vec::new)
7128 .extend(cached_hints);
7129 }
7130 }
7131 }
7132 (Some(cached_hints), Some(fetched_hints)) => {
7133 hint_fetch_tasks.push((row_chunk, fetched_hints));
7134 for (server_id, cached_hints) in cached_hints {
7135 if for_server.is_none_or(|for_server| for_server == server_id) {
7136 cached_inlay_hints
7137 .get_or_insert_with(HashMap::default)
7138 .entry(row_chunk.row_range())
7139 .or_insert_with(HashMap::default)
7140 .entry(server_id)
7141 .or_insert_with(Vec::new)
7142 .extend(cached_hints);
7143 }
7144 }
7145 }
7146 }
7147 }
7148
7149 if hint_fetch_tasks.is_empty()
7150 && ranges_to_query
7151 .as_ref()
7152 .is_none_or(|ranges| ranges.is_empty())
7153 && let Some(cached_inlay_hints) = cached_inlay_hints
7154 {
7155 cached_inlay_hints
7156 .into_iter()
7157 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7158 .collect()
7159 } else {
7160 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7161 let next_hint_id = next_hint_id.clone();
7162 let buffer = buffer.clone();
7163 let query_version = query_version.clone();
7164 let new_inlay_hints = cx
7165 .spawn(async move |lsp_store, cx| {
7166 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7167 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7168 })?;
7169 new_fetch_task
7170 .await
7171 .and_then(|new_hints_by_server| {
7172 lsp_store.update(cx, |lsp_store, cx| {
7173 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7174 let update_cache = lsp_data.buffer_version == query_version;
7175 if new_hints_by_server.is_empty() {
7176 if update_cache {
7177 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7178 }
7179 HashMap::default()
7180 } else {
7181 new_hints_by_server
7182 .into_iter()
7183 .map(|(server_id, new_hints)| {
7184 let new_hints = new_hints
7185 .into_iter()
7186 .map(|new_hint| {
7187 (
7188 InlayId::Hint(next_hint_id.fetch_add(
7189 1,
7190 atomic::Ordering::AcqRel,
7191 )),
7192 new_hint,
7193 )
7194 })
7195 .collect::<Vec<_>>();
7196 if update_cache {
7197 lsp_data.inlay_hints.insert_new_hints(
7198 chunk,
7199 server_id,
7200 new_hints.clone(),
7201 );
7202 }
7203 (server_id, new_hints)
7204 })
7205 .collect()
7206 }
7207 })
7208 })
7209 .map_err(Arc::new)
7210 })
7211 .shared();
7212
7213 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7214 *fetch_task = Some(new_inlay_hints.clone());
7215 hint_fetch_tasks.push((chunk, new_inlay_hints));
7216 }
7217
7218 cached_inlay_hints
7219 .unwrap_or_default()
7220 .into_iter()
7221 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7222 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7223 (
7224 chunk.row_range(),
7225 cx.spawn(async move |_, _| {
7226 hints_fetch.await.map_err(|e| {
7227 if e.error_code() != ErrorCode::Internal {
7228 anyhow!(e.error_code())
7229 } else {
7230 anyhow!("{e:#}")
7231 }
7232 })
7233 }),
7234 )
7235 }))
7236 .collect()
7237 }
7238 }
7239
7240 fn fetch_inlay_hints(
7241 &mut self,
7242 for_server: Option<LanguageServerId>,
7243 buffer: &Entity<Buffer>,
7244 range: Range<Anchor>,
7245 cx: &mut Context<Self>,
7246 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7247 let request = InlayHints {
7248 range: range.clone(),
7249 };
7250 if let Some((upstream_client, project_id)) = self.upstream_client() {
7251 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7252 return Task::ready(Ok(HashMap::default()));
7253 }
7254 let request_task = upstream_client.request_lsp(
7255 project_id,
7256 for_server.map(|id| id.to_proto()),
7257 LSP_REQUEST_TIMEOUT,
7258 cx.background_executor().clone(),
7259 request.to_proto(project_id, buffer.read(cx)),
7260 );
7261 let buffer = buffer.clone();
7262 cx.spawn(async move |weak_lsp_store, cx| {
7263 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7264 return Ok(HashMap::default());
7265 };
7266 let Some(responses) = request_task.await? else {
7267 return Ok(HashMap::default());
7268 };
7269
7270 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7271 let lsp_store = lsp_store.clone();
7272 let buffer = buffer.clone();
7273 let cx = cx.clone();
7274 let request = request.clone();
7275 async move {
7276 (
7277 LanguageServerId::from_proto(response.server_id),
7278 request
7279 .response_from_proto(response.response, lsp_store, buffer, cx)
7280 .await,
7281 )
7282 }
7283 }))
7284 .await;
7285
7286 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7287 let mut has_errors = false;
7288 let inlay_hints = inlay_hints
7289 .into_iter()
7290 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7291 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7292 Err(e) => {
7293 has_errors = true;
7294 log::error!("{e:#}");
7295 None
7296 }
7297 })
7298 .map(|(server_id, mut new_hints)| {
7299 new_hints.retain(|hint| {
7300 hint.position.is_valid(&buffer_snapshot)
7301 && range.start.is_valid(&buffer_snapshot)
7302 && range.end.is_valid(&buffer_snapshot)
7303 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7304 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7305 });
7306 (server_id, new_hints)
7307 })
7308 .collect::<HashMap<_, _>>();
7309 anyhow::ensure!(
7310 !has_errors || !inlay_hints.is_empty(),
7311 "Failed to fetch inlay hints"
7312 );
7313 Ok(inlay_hints)
7314 })
7315 } else {
7316 let inlay_hints_task = match for_server {
7317 Some(server_id) => {
7318 let server_task = self.request_lsp(
7319 buffer.clone(),
7320 LanguageServerToQuery::Other(server_id),
7321 request,
7322 cx,
7323 );
7324 cx.background_spawn(async move {
7325 let mut responses = Vec::new();
7326 match server_task.await {
7327 Ok(response) => responses.push((server_id, response)),
7328 // rust-analyzer likes to error with this when its still loading up
7329 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7330 Err(e) => log::error!(
7331 "Error handling response for inlay hints request: {e:#}"
7332 ),
7333 }
7334 responses
7335 })
7336 }
7337 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7338 };
7339 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7340 cx.background_spawn(async move {
7341 Ok(inlay_hints_task
7342 .await
7343 .into_iter()
7344 .map(|(server_id, mut new_hints)| {
7345 new_hints.retain(|hint| {
7346 hint.position.is_valid(&buffer_snapshot)
7347 && range.start.is_valid(&buffer_snapshot)
7348 && range.end.is_valid(&buffer_snapshot)
7349 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7350 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7351 });
7352 (server_id, new_hints)
7353 })
7354 .collect())
7355 })
7356 }
7357 }
7358
7359 fn diagnostic_registration_exists(
7360 &self,
7361 server_id: LanguageServerId,
7362 registration_id: &Option<SharedString>,
7363 ) -> bool {
7364 let Some(local) = self.as_local() else {
7365 return false;
7366 };
7367 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7368 else {
7369 return false;
7370 };
7371 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7372 registrations.diagnostics.contains_key(®istration_key)
7373 }
7374
7375 pub fn pull_diagnostics_for_buffer(
7376 &mut self,
7377 buffer: Entity<Buffer>,
7378 cx: &mut Context<Self>,
7379 ) -> Task<anyhow::Result<()>> {
7380 let diagnostics = self.pull_diagnostics(buffer, cx);
7381 cx.spawn(async move |lsp_store, cx| {
7382 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7383 return Ok(());
7384 };
7385 lsp_store.update(cx, |lsp_store, cx| {
7386 if lsp_store.as_local().is_none() {
7387 return;
7388 }
7389
7390 let mut unchanged_buffers = HashMap::default();
7391 let server_diagnostics_updates = diagnostics
7392 .into_iter()
7393 .filter_map(|diagnostics_set| match diagnostics_set {
7394 LspPullDiagnostics::Response {
7395 server_id,
7396 uri,
7397 diagnostics,
7398 registration_id,
7399 } => Some((server_id, uri, diagnostics, registration_id)),
7400 LspPullDiagnostics::Default => None,
7401 })
7402 .filter(|(server_id, _, _, registration_id)| {
7403 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7404 })
7405 .fold(
7406 HashMap::default(),
7407 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7408 let (result_id, diagnostics) = match diagnostics {
7409 PulledDiagnostics::Unchanged { result_id } => {
7410 unchanged_buffers
7411 .entry(new_registration_id.clone())
7412 .or_insert_with(HashSet::default)
7413 .insert(uri.clone());
7414 (Some(result_id), Vec::new())
7415 }
7416 PulledDiagnostics::Changed {
7417 result_id,
7418 diagnostics,
7419 } => (result_id, diagnostics),
7420 };
7421 let disk_based_sources = Cow::Owned(
7422 lsp_store
7423 .language_server_adapter_for_id(server_id)
7424 .as_ref()
7425 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7426 .unwrap_or(&[])
7427 .to_vec(),
7428 );
7429 acc.entry(server_id)
7430 .or_insert_with(HashMap::default)
7431 .entry(new_registration_id.clone())
7432 .or_insert_with(Vec::new)
7433 .push(DocumentDiagnosticsUpdate {
7434 server_id,
7435 diagnostics: lsp::PublishDiagnosticsParams {
7436 uri,
7437 diagnostics,
7438 version: None,
7439 },
7440 result_id,
7441 disk_based_sources,
7442 registration_id: new_registration_id,
7443 });
7444 acc
7445 },
7446 );
7447
7448 for diagnostic_updates in server_diagnostics_updates.into_values() {
7449 for (registration_id, diagnostic_updates) in diagnostic_updates {
7450 lsp_store
7451 .merge_lsp_diagnostics(
7452 DiagnosticSourceKind::Pulled,
7453 diagnostic_updates,
7454 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7455 DiagnosticSourceKind::Pulled => {
7456 old_diagnostic.registration_id != registration_id
7457 || unchanged_buffers
7458 .get(&old_diagnostic.registration_id)
7459 .is_some_and(|unchanged_buffers| {
7460 unchanged_buffers.contains(&document_uri)
7461 })
7462 }
7463 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7464 true
7465 }
7466 },
7467 cx,
7468 )
7469 .log_err();
7470 }
7471 }
7472 })
7473 })
7474 }
7475
7476 pub fn document_colors(
7477 &mut self,
7478 known_cache_version: Option<usize>,
7479 buffer: Entity<Buffer>,
7480 cx: &mut Context<Self>,
7481 ) -> Option<DocumentColorTask> {
7482 let version_queried_for = buffer.read(cx).version();
7483 let buffer_id = buffer.read(cx).remote_id();
7484
7485 let current_language_servers = self.as_local().map(|local| {
7486 local
7487 .buffers_opened_in_servers
7488 .get(&buffer_id)
7489 .cloned()
7490 .unwrap_or_default()
7491 });
7492
7493 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7494 if let Some(cached_colors) = &lsp_data.document_colors {
7495 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7496 let has_different_servers =
7497 current_language_servers.is_some_and(|current_language_servers| {
7498 current_language_servers
7499 != cached_colors.colors.keys().copied().collect()
7500 });
7501 if !has_different_servers {
7502 let cache_version = cached_colors.cache_version;
7503 if Some(cache_version) == known_cache_version {
7504 return None;
7505 } else {
7506 return Some(
7507 Task::ready(Ok(DocumentColors {
7508 colors: cached_colors
7509 .colors
7510 .values()
7511 .flatten()
7512 .cloned()
7513 .collect(),
7514 cache_version: Some(cache_version),
7515 }))
7516 .shared(),
7517 );
7518 }
7519 }
7520 }
7521 }
7522 }
7523
7524 let color_lsp_data = self
7525 .latest_lsp_data(&buffer, cx)
7526 .document_colors
7527 .get_or_insert_default();
7528 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7529 && !version_queried_for.changed_since(updating_for)
7530 {
7531 return Some(running_update.clone());
7532 }
7533 let buffer_version_queried_for = version_queried_for.clone();
7534 let new_task = cx
7535 .spawn(async move |lsp_store, cx| {
7536 cx.background_executor()
7537 .timer(Duration::from_millis(30))
7538 .await;
7539 let fetched_colors = lsp_store
7540 .update(cx, |lsp_store, cx| {
7541 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7542 })?
7543 .await
7544 .context("fetching document colors")
7545 .map_err(Arc::new);
7546 let fetched_colors = match fetched_colors {
7547 Ok(fetched_colors) => {
7548 if buffer.update(cx, |buffer, _| {
7549 buffer.version() != buffer_version_queried_for
7550 }) {
7551 return Ok(DocumentColors::default());
7552 }
7553 fetched_colors
7554 }
7555 Err(e) => {
7556 lsp_store
7557 .update(cx, |lsp_store, _| {
7558 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7559 if let Some(document_colors) = &mut lsp_data.document_colors {
7560 document_colors.colors_update = None;
7561 }
7562 }
7563 })
7564 .ok();
7565 return Err(e);
7566 }
7567 };
7568
7569 lsp_store
7570 .update(cx, |lsp_store, cx| {
7571 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7572 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7573
7574 if let Some(fetched_colors) = fetched_colors {
7575 if lsp_data.buffer_version == buffer_version_queried_for {
7576 lsp_colors.colors.extend(fetched_colors);
7577 lsp_colors.cache_version += 1;
7578 } else if !lsp_data
7579 .buffer_version
7580 .changed_since(&buffer_version_queried_for)
7581 {
7582 lsp_data.buffer_version = buffer_version_queried_for;
7583 lsp_colors.colors = fetched_colors;
7584 lsp_colors.cache_version += 1;
7585 }
7586 }
7587 lsp_colors.colors_update = None;
7588 let colors = lsp_colors
7589 .colors
7590 .values()
7591 .flatten()
7592 .cloned()
7593 .collect::<HashSet<_>>();
7594 DocumentColors {
7595 colors,
7596 cache_version: Some(lsp_colors.cache_version),
7597 }
7598 })
7599 .map_err(Arc::new)
7600 })
7601 .shared();
7602 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7603 Some(new_task)
7604 }
7605
7606 fn fetch_document_colors_for_buffer(
7607 &mut self,
7608 buffer: &Entity<Buffer>,
7609 cx: &mut Context<Self>,
7610 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7611 if let Some((client, project_id)) = self.upstream_client() {
7612 let request = GetDocumentColor {};
7613 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7614 return Task::ready(Ok(None));
7615 }
7616
7617 let request_task = client.request_lsp(
7618 project_id,
7619 None,
7620 LSP_REQUEST_TIMEOUT,
7621 cx.background_executor().clone(),
7622 request.to_proto(project_id, buffer.read(cx)),
7623 );
7624 let buffer = buffer.clone();
7625 cx.spawn(async move |lsp_store, cx| {
7626 let Some(lsp_store) = lsp_store.upgrade() else {
7627 return Ok(None);
7628 };
7629 let colors = join_all(
7630 request_task
7631 .await
7632 .log_err()
7633 .flatten()
7634 .map(|response| response.payload)
7635 .unwrap_or_default()
7636 .into_iter()
7637 .map(|color_response| {
7638 let response = request.response_from_proto(
7639 color_response.response,
7640 lsp_store.clone(),
7641 buffer.clone(),
7642 cx.clone(),
7643 );
7644 async move {
7645 (
7646 LanguageServerId::from_proto(color_response.server_id),
7647 response.await.log_err().unwrap_or_default(),
7648 )
7649 }
7650 }),
7651 )
7652 .await
7653 .into_iter()
7654 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7655 acc.entry(server_id)
7656 .or_insert_with(HashSet::default)
7657 .extend(colors);
7658 acc
7659 });
7660 Ok(Some(colors))
7661 })
7662 } else {
7663 let document_colors_task =
7664 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7665 cx.background_spawn(async move {
7666 Ok(Some(
7667 document_colors_task
7668 .await
7669 .into_iter()
7670 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7671 acc.entry(server_id)
7672 .or_insert_with(HashSet::default)
7673 .extend(colors);
7674 acc
7675 })
7676 .into_iter()
7677 .collect(),
7678 ))
7679 })
7680 }
7681 }
7682
7683 pub fn signature_help<T: ToPointUtf16>(
7684 &mut self,
7685 buffer: &Entity<Buffer>,
7686 position: T,
7687 cx: &mut Context<Self>,
7688 ) -> Task<Option<Vec<SignatureHelp>>> {
7689 let position = position.to_point_utf16(buffer.read(cx));
7690
7691 if let Some((client, upstream_project_id)) = self.upstream_client() {
7692 let request = GetSignatureHelp { position };
7693 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7694 return Task::ready(None);
7695 }
7696 let request_task = client.request_lsp(
7697 upstream_project_id,
7698 None,
7699 LSP_REQUEST_TIMEOUT,
7700 cx.background_executor().clone(),
7701 request.to_proto(upstream_project_id, buffer.read(cx)),
7702 );
7703 let buffer = buffer.clone();
7704 cx.spawn(async move |weak_lsp_store, cx| {
7705 let lsp_store = weak_lsp_store.upgrade()?;
7706 let signatures = join_all(
7707 request_task
7708 .await
7709 .log_err()
7710 .flatten()
7711 .map(|response| response.payload)
7712 .unwrap_or_default()
7713 .into_iter()
7714 .map(|response| {
7715 let response = GetSignatureHelp { position }.response_from_proto(
7716 response.response,
7717 lsp_store.clone(),
7718 buffer.clone(),
7719 cx.clone(),
7720 );
7721 async move { response.await.log_err().flatten() }
7722 }),
7723 )
7724 .await
7725 .into_iter()
7726 .flatten()
7727 .collect();
7728 Some(signatures)
7729 })
7730 } else {
7731 let all_actions_task = self.request_multiple_lsp_locally(
7732 buffer,
7733 Some(position),
7734 GetSignatureHelp { position },
7735 cx,
7736 );
7737 cx.background_spawn(async move {
7738 Some(
7739 all_actions_task
7740 .await
7741 .into_iter()
7742 .flat_map(|(_, actions)| actions)
7743 .collect::<Vec<_>>(),
7744 )
7745 })
7746 }
7747 }
7748
7749 pub fn hover(
7750 &mut self,
7751 buffer: &Entity<Buffer>,
7752 position: PointUtf16,
7753 cx: &mut Context<Self>,
7754 ) -> Task<Option<Vec<Hover>>> {
7755 if let Some((client, upstream_project_id)) = self.upstream_client() {
7756 let request = GetHover { position };
7757 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7758 return Task::ready(None);
7759 }
7760 let request_task = client.request_lsp(
7761 upstream_project_id,
7762 None,
7763 LSP_REQUEST_TIMEOUT,
7764 cx.background_executor().clone(),
7765 request.to_proto(upstream_project_id, buffer.read(cx)),
7766 );
7767 let buffer = buffer.clone();
7768 cx.spawn(async move |weak_lsp_store, cx| {
7769 let lsp_store = weak_lsp_store.upgrade()?;
7770 let hovers = join_all(
7771 request_task
7772 .await
7773 .log_err()
7774 .flatten()
7775 .map(|response| response.payload)
7776 .unwrap_or_default()
7777 .into_iter()
7778 .map(|response| {
7779 let response = GetHover { position }.response_from_proto(
7780 response.response,
7781 lsp_store.clone(),
7782 buffer.clone(),
7783 cx.clone(),
7784 );
7785 async move {
7786 response
7787 .await
7788 .log_err()
7789 .flatten()
7790 .and_then(remove_empty_hover_blocks)
7791 }
7792 }),
7793 )
7794 .await
7795 .into_iter()
7796 .flatten()
7797 .collect();
7798 Some(hovers)
7799 })
7800 } else {
7801 let all_actions_task = self.request_multiple_lsp_locally(
7802 buffer,
7803 Some(position),
7804 GetHover { position },
7805 cx,
7806 );
7807 cx.background_spawn(async move {
7808 Some(
7809 all_actions_task
7810 .await
7811 .into_iter()
7812 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7813 .collect::<Vec<Hover>>(),
7814 )
7815 })
7816 }
7817 }
7818
7819 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7820 let language_registry = self.languages.clone();
7821
7822 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7823 let request = upstream_client.request(proto::GetProjectSymbols {
7824 project_id: *project_id,
7825 query: query.to_string(),
7826 });
7827 cx.foreground_executor().spawn(async move {
7828 let response = request.await?;
7829 let mut symbols = Vec::new();
7830 let core_symbols = response
7831 .symbols
7832 .into_iter()
7833 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7834 .collect::<Vec<_>>();
7835 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7836 .await;
7837 Ok(symbols)
7838 })
7839 } else if let Some(local) = self.as_local() {
7840 struct WorkspaceSymbolsResult {
7841 server_id: LanguageServerId,
7842 lsp_adapter: Arc<CachedLspAdapter>,
7843 worktree: WeakEntity<Worktree>,
7844 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7845 }
7846
7847 let mut requests = Vec::new();
7848 let mut requested_servers = BTreeSet::new();
7849 for (seed, state) in local.language_server_ids.iter() {
7850 let Some(worktree_handle) = self
7851 .worktree_store
7852 .read(cx)
7853 .worktree_for_id(seed.worktree_id, cx)
7854 else {
7855 continue;
7856 };
7857 let worktree = worktree_handle.read(cx);
7858 if !worktree.is_visible() {
7859 continue;
7860 }
7861
7862 if !requested_servers.insert(state.id) {
7863 continue;
7864 }
7865
7866 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7867 Some(LanguageServerState::Running {
7868 adapter, server, ..
7869 }) => (adapter.clone(), server),
7870
7871 _ => continue,
7872 };
7873 let supports_workspace_symbol_request =
7874 match server.capabilities().workspace_symbol_provider {
7875 Some(OneOf::Left(supported)) => supported,
7876 Some(OneOf::Right(_)) => true,
7877 None => false,
7878 };
7879 if !supports_workspace_symbol_request {
7880 continue;
7881 }
7882 let worktree_handle = worktree_handle.clone();
7883 let server_id = server.server_id();
7884 requests.push(
7885 server
7886 .request::<lsp::request::WorkspaceSymbolRequest>(
7887 lsp::WorkspaceSymbolParams {
7888 query: query.to_string(),
7889 ..Default::default()
7890 },
7891 )
7892 .map(move |response| {
7893 let lsp_symbols = response
7894 .into_response()
7895 .context("workspace symbols request")
7896 .log_err()
7897 .flatten()
7898 .map(|symbol_response| match symbol_response {
7899 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7900 flat_responses
7901 .into_iter()
7902 .map(|lsp_symbol| {
7903 (
7904 lsp_symbol.name,
7905 lsp_symbol.kind,
7906 lsp_symbol.location,
7907 )
7908 })
7909 .collect::<Vec<_>>()
7910 }
7911 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7912 nested_responses
7913 .into_iter()
7914 .filter_map(|lsp_symbol| {
7915 let location = match lsp_symbol.location {
7916 OneOf::Left(location) => location,
7917 OneOf::Right(_) => {
7918 log::error!(
7919 "Unexpected: client capabilities \
7920 forbid symbol resolutions in \
7921 workspace.symbol.resolveSupport"
7922 );
7923 return None;
7924 }
7925 };
7926 Some((lsp_symbol.name, lsp_symbol.kind, location))
7927 })
7928 .collect::<Vec<_>>()
7929 }
7930 })
7931 .unwrap_or_default();
7932
7933 WorkspaceSymbolsResult {
7934 server_id,
7935 lsp_adapter,
7936 worktree: worktree_handle.downgrade(),
7937 lsp_symbols,
7938 }
7939 }),
7940 );
7941 }
7942
7943 cx.spawn(async move |this, cx| {
7944 let responses = futures::future::join_all(requests).await;
7945 let this = match this.upgrade() {
7946 Some(this) => this,
7947 None => return Ok(Vec::new()),
7948 };
7949
7950 let mut symbols = Vec::new();
7951 for result in responses {
7952 let core_symbols = this.update(cx, |this, cx| {
7953 result
7954 .lsp_symbols
7955 .into_iter()
7956 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7957 let abs_path = symbol_location.uri.to_file_path().ok()?;
7958 let source_worktree = result.worktree.upgrade()?;
7959 let source_worktree_id = source_worktree.read(cx).id();
7960
7961 let path = if let Some((tree, rel_path)) =
7962 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7963 {
7964 let worktree_id = tree.read(cx).id();
7965 SymbolLocation::InProject(ProjectPath {
7966 worktree_id,
7967 path: rel_path,
7968 })
7969 } else {
7970 SymbolLocation::OutsideProject {
7971 signature: this.symbol_signature(&abs_path),
7972 abs_path: abs_path.into(),
7973 }
7974 };
7975
7976 Some(CoreSymbol {
7977 source_language_server_id: result.server_id,
7978 language_server_name: result.lsp_adapter.name.clone(),
7979 source_worktree_id,
7980 path,
7981 kind: symbol_kind,
7982 name: symbol_name,
7983 range: range_from_lsp(symbol_location.range),
7984 })
7985 })
7986 .collect::<Vec<_>>()
7987 });
7988
7989 populate_labels_for_symbols(
7990 core_symbols,
7991 &language_registry,
7992 Some(result.lsp_adapter),
7993 &mut symbols,
7994 )
7995 .await;
7996 }
7997
7998 Ok(symbols)
7999 })
8000 } else {
8001 Task::ready(Err(anyhow!("No upstream client or local language server")))
8002 }
8003 }
8004
8005 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
8006 let mut summary = DiagnosticSummary::default();
8007 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
8008 summary.error_count += path_summary.error_count;
8009 summary.warning_count += path_summary.warning_count;
8010 }
8011 summary
8012 }
8013
8014 /// Returns the diagnostic summary for a specific project path.
8015 pub fn diagnostic_summary_for_path(
8016 &self,
8017 project_path: &ProjectPath,
8018 _: &App,
8019 ) -> DiagnosticSummary {
8020 if let Some(summaries) = self
8021 .diagnostic_summaries
8022 .get(&project_path.worktree_id)
8023 .and_then(|map| map.get(&project_path.path))
8024 {
8025 let (error_count, warning_count) = summaries.iter().fold(
8026 (0, 0),
8027 |(error_count, warning_count), (_language_server_id, summary)| {
8028 (
8029 error_count + summary.error_count,
8030 warning_count + summary.warning_count,
8031 )
8032 },
8033 );
8034
8035 DiagnosticSummary {
8036 error_count,
8037 warning_count,
8038 }
8039 } else {
8040 DiagnosticSummary::default()
8041 }
8042 }
8043
8044 pub fn diagnostic_summaries<'a>(
8045 &'a self,
8046 include_ignored: bool,
8047 cx: &'a App,
8048 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
8049 self.worktree_store
8050 .read(cx)
8051 .visible_worktrees(cx)
8052 .filter_map(|worktree| {
8053 let worktree = worktree.read(cx);
8054 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
8055 })
8056 .flat_map(move |(worktree, summaries)| {
8057 let worktree_id = worktree.id();
8058 summaries
8059 .iter()
8060 .filter(move |(path, _)| {
8061 include_ignored
8062 || worktree
8063 .entry_for_path(path.as_ref())
8064 .is_some_and(|entry| !entry.is_ignored)
8065 })
8066 .flat_map(move |(path, summaries)| {
8067 summaries.iter().map(move |(server_id, summary)| {
8068 (
8069 ProjectPath {
8070 worktree_id,
8071 path: path.clone(),
8072 },
8073 *server_id,
8074 *summary,
8075 )
8076 })
8077 })
8078 })
8079 }
8080
8081 pub fn on_buffer_edited(
8082 &mut self,
8083 buffer: Entity<Buffer>,
8084 cx: &mut Context<Self>,
8085 ) -> Option<()> {
8086 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8087 Some(
8088 self.as_local()?
8089 .language_servers_for_buffer(buffer, cx)
8090 .map(|i| i.1.clone())
8091 .collect(),
8092 )
8093 })?;
8094
8095 let buffer = buffer.read(cx);
8096 let file = File::from_dyn(buffer.file())?;
8097 let abs_path = file.as_local()?.abs_path(cx);
8098 let uri = lsp::Uri::from_file_path(&abs_path)
8099 .ok()
8100 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8101 .log_err()?;
8102 let next_snapshot = buffer.text_snapshot();
8103 for language_server in language_servers {
8104 let language_server = language_server.clone();
8105
8106 let buffer_snapshots = self
8107 .as_local_mut()?
8108 .buffer_snapshots
8109 .get_mut(&buffer.remote_id())
8110 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8111 let previous_snapshot = buffer_snapshots.last()?;
8112
8113 let build_incremental_change = || {
8114 buffer
8115 .edits_since::<Dimensions<PointUtf16, usize>>(
8116 previous_snapshot.snapshot.version(),
8117 )
8118 .map(|edit| {
8119 let edit_start = edit.new.start.0;
8120 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8121 let new_text = next_snapshot
8122 .text_for_range(edit.new.start.1..edit.new.end.1)
8123 .collect();
8124 lsp::TextDocumentContentChangeEvent {
8125 range: Some(lsp::Range::new(
8126 point_to_lsp(edit_start),
8127 point_to_lsp(edit_end),
8128 )),
8129 range_length: None,
8130 text: new_text,
8131 }
8132 })
8133 .collect()
8134 };
8135
8136 let document_sync_kind = language_server
8137 .capabilities()
8138 .text_document_sync
8139 .as_ref()
8140 .and_then(|sync| match sync {
8141 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8142 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8143 });
8144
8145 let content_changes: Vec<_> = match document_sync_kind {
8146 Some(lsp::TextDocumentSyncKind::FULL) => {
8147 vec![lsp::TextDocumentContentChangeEvent {
8148 range: None,
8149 range_length: None,
8150 text: next_snapshot.text(),
8151 }]
8152 }
8153 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8154 _ => {
8155 #[cfg(any(test, feature = "test-support"))]
8156 {
8157 build_incremental_change()
8158 }
8159
8160 #[cfg(not(any(test, feature = "test-support")))]
8161 {
8162 continue;
8163 }
8164 }
8165 };
8166
8167 let next_version = previous_snapshot.version + 1;
8168 buffer_snapshots.push(LspBufferSnapshot {
8169 version: next_version,
8170 snapshot: next_snapshot.clone(),
8171 });
8172
8173 language_server
8174 .notify::<lsp::notification::DidChangeTextDocument>(
8175 lsp::DidChangeTextDocumentParams {
8176 text_document: lsp::VersionedTextDocumentIdentifier::new(
8177 uri.clone(),
8178 next_version,
8179 ),
8180 content_changes,
8181 },
8182 )
8183 .ok();
8184 self.pull_workspace_diagnostics(language_server.server_id());
8185 }
8186
8187 None
8188 }
8189
8190 pub fn on_buffer_saved(
8191 &mut self,
8192 buffer: Entity<Buffer>,
8193 cx: &mut Context<Self>,
8194 ) -> Option<()> {
8195 let file = File::from_dyn(buffer.read(cx).file())?;
8196 let worktree_id = file.worktree_id(cx);
8197 let abs_path = file.as_local()?.abs_path(cx);
8198 let text_document = lsp::TextDocumentIdentifier {
8199 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8200 };
8201 let local = self.as_local()?;
8202
8203 for server in local.language_servers_for_worktree(worktree_id) {
8204 if let Some(include_text) = include_text(server.as_ref()) {
8205 let text = if include_text {
8206 Some(buffer.read(cx).text())
8207 } else {
8208 None
8209 };
8210 server
8211 .notify::<lsp::notification::DidSaveTextDocument>(
8212 lsp::DidSaveTextDocumentParams {
8213 text_document: text_document.clone(),
8214 text,
8215 },
8216 )
8217 .ok();
8218 }
8219 }
8220
8221 let language_servers = buffer.update(cx, |buffer, cx| {
8222 local.language_server_ids_for_buffer(buffer, cx)
8223 });
8224 for language_server_id in language_servers {
8225 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8226 }
8227
8228 None
8229 }
8230
8231 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8232 maybe!(async move {
8233 let mut refreshed_servers = HashSet::default();
8234 let servers = lsp_store
8235 .update(cx, |lsp_store, cx| {
8236 let local = lsp_store.as_local()?;
8237
8238 let servers = local
8239 .language_server_ids
8240 .iter()
8241 .filter_map(|(seed, state)| {
8242 let worktree = lsp_store
8243 .worktree_store
8244 .read(cx)
8245 .worktree_for_id(seed.worktree_id, cx);
8246 let delegate: Arc<dyn LspAdapterDelegate> =
8247 worktree.map(|worktree| {
8248 LocalLspAdapterDelegate::new(
8249 local.languages.clone(),
8250 &local.environment,
8251 cx.weak_entity(),
8252 &worktree,
8253 local.http_client.clone(),
8254 local.fs.clone(),
8255 cx,
8256 )
8257 })?;
8258 let server_id = state.id;
8259
8260 let states = local.language_servers.get(&server_id)?;
8261
8262 match states {
8263 LanguageServerState::Starting { .. } => None,
8264 LanguageServerState::Running {
8265 adapter, server, ..
8266 } => {
8267 let adapter = adapter.clone();
8268 let server = server.clone();
8269 refreshed_servers.insert(server.name());
8270 let toolchain = seed.toolchain.clone();
8271 Some(cx.spawn(async move |_, cx| {
8272 let settings =
8273 LocalLspStore::workspace_configuration_for_adapter(
8274 adapter.adapter.clone(),
8275 &delegate,
8276 toolchain,
8277 None,
8278 cx,
8279 )
8280 .await
8281 .ok()?;
8282 server
8283 .notify::<lsp::notification::DidChangeConfiguration>(
8284 lsp::DidChangeConfigurationParams { settings },
8285 )
8286 .ok()?;
8287 Some(())
8288 }))
8289 }
8290 }
8291 })
8292 .collect::<Vec<_>>();
8293
8294 Some(servers)
8295 })
8296 .ok()
8297 .flatten()?;
8298
8299 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8300 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8301 // to stop and unregister its language server wrapper.
8302 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8303 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8304 let _: Vec<Option<()>> = join_all(servers).await;
8305
8306 Some(())
8307 })
8308 .await;
8309 }
8310
8311 fn maintain_workspace_config(
8312 external_refresh_requests: watch::Receiver<()>,
8313 cx: &mut Context<Self>,
8314 ) -> Task<Result<()>> {
8315 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8316 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8317
8318 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8319 *settings_changed_tx.borrow_mut() = ();
8320 });
8321
8322 let mut joint_future =
8323 futures::stream::select(settings_changed_rx, external_refresh_requests);
8324 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8325 // - 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).
8326 // - 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.
8327 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8328 // - 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,
8329 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8330 cx.spawn(async move |this, cx| {
8331 while let Some(()) = joint_future.next().await {
8332 this.update(cx, |this, cx| {
8333 this.refresh_server_tree(cx);
8334 })
8335 .ok();
8336
8337 Self::refresh_workspace_configurations(&this, cx).await;
8338 }
8339
8340 drop(settings_observation);
8341 anyhow::Ok(())
8342 })
8343 }
8344
8345 pub fn running_language_servers_for_local_buffer<'a>(
8346 &'a self,
8347 buffer: &Buffer,
8348 cx: &mut App,
8349 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8350 let local = self.as_local();
8351 let language_server_ids = local
8352 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8353 .unwrap_or_default();
8354
8355 language_server_ids
8356 .into_iter()
8357 .filter_map(
8358 move |server_id| match local?.language_servers.get(&server_id)? {
8359 LanguageServerState::Running {
8360 adapter, server, ..
8361 } => Some((adapter, server)),
8362 _ => None,
8363 },
8364 )
8365 }
8366
8367 pub fn language_servers_for_local_buffer(
8368 &self,
8369 buffer: &Buffer,
8370 cx: &mut App,
8371 ) -> Vec<LanguageServerId> {
8372 let local = self.as_local();
8373 local
8374 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8375 .unwrap_or_default()
8376 }
8377
8378 pub fn language_server_for_local_buffer<'a>(
8379 &'a self,
8380 buffer: &'a Buffer,
8381 server_id: LanguageServerId,
8382 cx: &'a mut App,
8383 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8384 self.as_local()?
8385 .language_servers_for_buffer(buffer, cx)
8386 .find(|(_, s)| s.server_id() == server_id)
8387 }
8388
8389 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8390 self.diagnostic_summaries.remove(&id_to_remove);
8391 if let Some(local) = self.as_local_mut() {
8392 let to_remove = local.remove_worktree(id_to_remove, cx);
8393 for server in to_remove {
8394 self.language_server_statuses.remove(&server);
8395 }
8396 }
8397 }
8398
8399 pub fn shared(
8400 &mut self,
8401 project_id: u64,
8402 downstream_client: AnyProtoClient,
8403 _: &mut Context<Self>,
8404 ) {
8405 self.downstream_client = Some((downstream_client.clone(), project_id));
8406
8407 for (server_id, status) in &self.language_server_statuses {
8408 if let Some(server) = self.language_server_for_id(*server_id) {
8409 downstream_client
8410 .send(proto::StartLanguageServer {
8411 project_id,
8412 server: Some(proto::LanguageServer {
8413 id: server_id.to_proto(),
8414 name: status.name.to_string(),
8415 worktree_id: status.worktree.map(|id| id.to_proto()),
8416 }),
8417 capabilities: serde_json::to_string(&server.capabilities())
8418 .expect("serializing server LSP capabilities"),
8419 })
8420 .log_err();
8421 }
8422 }
8423 }
8424
8425 pub fn disconnected_from_host(&mut self) {
8426 self.downstream_client.take();
8427 }
8428
8429 pub fn disconnected_from_ssh_remote(&mut self) {
8430 if let LspStoreMode::Remote(RemoteLspStore {
8431 upstream_client, ..
8432 }) = &mut self.mode
8433 {
8434 upstream_client.take();
8435 }
8436 }
8437
8438 pub(crate) fn set_language_server_statuses_from_proto(
8439 &mut self,
8440 project: WeakEntity<Project>,
8441 language_servers: Vec<proto::LanguageServer>,
8442 server_capabilities: Vec<String>,
8443 cx: &mut Context<Self>,
8444 ) {
8445 let lsp_logs = cx
8446 .try_global::<GlobalLogStore>()
8447 .map(|lsp_store| lsp_store.0.clone());
8448
8449 self.language_server_statuses = language_servers
8450 .into_iter()
8451 .zip(server_capabilities)
8452 .map(|(server, server_capabilities)| {
8453 let server_id = LanguageServerId(server.id as usize);
8454 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8455 self.lsp_server_capabilities
8456 .insert(server_id, server_capabilities);
8457 }
8458
8459 let name = LanguageServerName::from_proto(server.name);
8460 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8461
8462 if let Some(lsp_logs) = &lsp_logs {
8463 lsp_logs.update(cx, |lsp_logs, cx| {
8464 lsp_logs.add_language_server(
8465 // Only remote clients get their language servers set from proto
8466 LanguageServerKind::Remote {
8467 project: project.clone(),
8468 },
8469 server_id,
8470 Some(name.clone()),
8471 worktree,
8472 None,
8473 cx,
8474 );
8475 });
8476 }
8477
8478 (
8479 server_id,
8480 LanguageServerStatus {
8481 name,
8482 server_version: None,
8483 pending_work: Default::default(),
8484 has_pending_diagnostic_updates: false,
8485 progress_tokens: Default::default(),
8486 worktree,
8487 binary: None,
8488 configuration: None,
8489 workspace_folders: BTreeSet::new(),
8490 },
8491 )
8492 })
8493 .collect();
8494 }
8495
8496 #[cfg(feature = "test-support")]
8497 pub fn update_diagnostic_entries(
8498 &mut self,
8499 server_id: LanguageServerId,
8500 abs_path: PathBuf,
8501 result_id: Option<SharedString>,
8502 version: Option<i32>,
8503 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8504 cx: &mut Context<Self>,
8505 ) -> anyhow::Result<()> {
8506 self.merge_diagnostic_entries(
8507 vec![DocumentDiagnosticsUpdate {
8508 diagnostics: DocumentDiagnostics {
8509 diagnostics,
8510 document_abs_path: abs_path,
8511 version,
8512 },
8513 result_id,
8514 server_id,
8515 disk_based_sources: Cow::Borrowed(&[]),
8516 registration_id: None,
8517 }],
8518 |_, _, _| false,
8519 cx,
8520 )?;
8521 Ok(())
8522 }
8523
8524 pub fn merge_diagnostic_entries<'a>(
8525 &mut self,
8526 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8527 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8528 cx: &mut Context<Self>,
8529 ) -> anyhow::Result<()> {
8530 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8531 let mut updated_diagnostics_paths = HashMap::default();
8532 for mut update in diagnostic_updates {
8533 let abs_path = &update.diagnostics.document_abs_path;
8534 let server_id = update.server_id;
8535 let Some((worktree, relative_path)) =
8536 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8537 else {
8538 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8539 return Ok(());
8540 };
8541
8542 let worktree_id = worktree.read(cx).id();
8543 let project_path = ProjectPath {
8544 worktree_id,
8545 path: relative_path,
8546 };
8547
8548 let document_uri = lsp::Uri::from_file_path(abs_path)
8549 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8550 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8551 let snapshot = buffer_handle.read(cx).snapshot();
8552 let buffer = buffer_handle.read(cx);
8553 let reused_diagnostics = buffer
8554 .buffer_diagnostics(Some(server_id))
8555 .iter()
8556 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8557 .map(|v| {
8558 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8559 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8560 DiagnosticEntry {
8561 range: start..end,
8562 diagnostic: v.diagnostic.clone(),
8563 }
8564 })
8565 .collect::<Vec<_>>();
8566
8567 self.as_local_mut()
8568 .context("cannot merge diagnostics on a remote LspStore")?
8569 .update_buffer_diagnostics(
8570 &buffer_handle,
8571 server_id,
8572 Some(update.registration_id),
8573 update.result_id,
8574 update.diagnostics.version,
8575 update.diagnostics.diagnostics.clone(),
8576 reused_diagnostics.clone(),
8577 cx,
8578 )?;
8579
8580 update.diagnostics.diagnostics.extend(reused_diagnostics);
8581 } else if let Some(local) = self.as_local() {
8582 let reused_diagnostics = local
8583 .diagnostics
8584 .get(&worktree_id)
8585 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8586 .and_then(|diagnostics_by_server_id| {
8587 diagnostics_by_server_id
8588 .binary_search_by_key(&server_id, |e| e.0)
8589 .ok()
8590 .map(|ix| &diagnostics_by_server_id[ix].1)
8591 })
8592 .into_iter()
8593 .flatten()
8594 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8595
8596 update
8597 .diagnostics
8598 .diagnostics
8599 .extend(reused_diagnostics.cloned());
8600 }
8601
8602 let updated = worktree.update(cx, |worktree, cx| {
8603 self.update_worktree_diagnostics(
8604 worktree.id(),
8605 server_id,
8606 project_path.path.clone(),
8607 update.diagnostics.diagnostics,
8608 cx,
8609 )
8610 })?;
8611 match updated {
8612 ControlFlow::Continue(new_summary) => {
8613 if let Some((project_id, new_summary)) = new_summary {
8614 match &mut diagnostics_summary {
8615 Some(diagnostics_summary) => {
8616 diagnostics_summary
8617 .more_summaries
8618 .push(proto::DiagnosticSummary {
8619 path: project_path.path.as_ref().to_proto(),
8620 language_server_id: server_id.0 as u64,
8621 error_count: new_summary.error_count,
8622 warning_count: new_summary.warning_count,
8623 })
8624 }
8625 None => {
8626 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8627 project_id,
8628 worktree_id: worktree_id.to_proto(),
8629 summary: Some(proto::DiagnosticSummary {
8630 path: project_path.path.as_ref().to_proto(),
8631 language_server_id: server_id.0 as u64,
8632 error_count: new_summary.error_count,
8633 warning_count: new_summary.warning_count,
8634 }),
8635 more_summaries: Vec::new(),
8636 })
8637 }
8638 }
8639 }
8640 updated_diagnostics_paths
8641 .entry(server_id)
8642 .or_insert_with(Vec::new)
8643 .push(project_path);
8644 }
8645 ControlFlow::Break(()) => {}
8646 }
8647 }
8648
8649 if let Some((diagnostics_summary, (downstream_client, _))) =
8650 diagnostics_summary.zip(self.downstream_client.as_ref())
8651 {
8652 downstream_client.send(diagnostics_summary).log_err();
8653 }
8654 for (server_id, paths) in updated_diagnostics_paths {
8655 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8656 }
8657 Ok(())
8658 }
8659
8660 fn update_worktree_diagnostics(
8661 &mut self,
8662 worktree_id: WorktreeId,
8663 server_id: LanguageServerId,
8664 path_in_worktree: Arc<RelPath>,
8665 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8666 _: &mut Context<Worktree>,
8667 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8668 let local = match &mut self.mode {
8669 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8670 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8671 };
8672
8673 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8674 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8675 let summaries_by_server_id = summaries_for_tree
8676 .entry(path_in_worktree.clone())
8677 .or_default();
8678
8679 let old_summary = summaries_by_server_id
8680 .remove(&server_id)
8681 .unwrap_or_default();
8682
8683 let new_summary = DiagnosticSummary::new(&diagnostics);
8684 if diagnostics.is_empty() {
8685 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8686 {
8687 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8688 diagnostics_by_server_id.remove(ix);
8689 }
8690 if diagnostics_by_server_id.is_empty() {
8691 diagnostics_for_tree.remove(&path_in_worktree);
8692 }
8693 }
8694 } else {
8695 summaries_by_server_id.insert(server_id, new_summary);
8696 let diagnostics_by_server_id = diagnostics_for_tree
8697 .entry(path_in_worktree.clone())
8698 .or_default();
8699 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8700 Ok(ix) => {
8701 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8702 }
8703 Err(ix) => {
8704 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8705 }
8706 }
8707 }
8708
8709 if !old_summary.is_empty() || !new_summary.is_empty() {
8710 if let Some((_, project_id)) = &self.downstream_client {
8711 Ok(ControlFlow::Continue(Some((
8712 *project_id,
8713 proto::DiagnosticSummary {
8714 path: path_in_worktree.to_proto(),
8715 language_server_id: server_id.0 as u64,
8716 error_count: new_summary.error_count as u32,
8717 warning_count: new_summary.warning_count as u32,
8718 },
8719 ))))
8720 } else {
8721 Ok(ControlFlow::Continue(None))
8722 }
8723 } else {
8724 Ok(ControlFlow::Break(()))
8725 }
8726 }
8727
8728 pub fn open_buffer_for_symbol(
8729 &mut self,
8730 symbol: &Symbol,
8731 cx: &mut Context<Self>,
8732 ) -> Task<Result<Entity<Buffer>>> {
8733 if let Some((client, project_id)) = self.upstream_client() {
8734 let request = client.request(proto::OpenBufferForSymbol {
8735 project_id,
8736 symbol: Some(Self::serialize_symbol(symbol)),
8737 });
8738 cx.spawn(async move |this, cx| {
8739 let response = request.await?;
8740 let buffer_id = BufferId::new(response.buffer_id)?;
8741 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8742 .await
8743 })
8744 } else if let Some(local) = self.as_local() {
8745 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8746 seed.worktree_id == symbol.source_worktree_id
8747 && state.id == symbol.source_language_server_id
8748 && symbol.language_server_name == seed.name
8749 });
8750 if !is_valid {
8751 return Task::ready(Err(anyhow!(
8752 "language server for worktree and language not found"
8753 )));
8754 };
8755
8756 let symbol_abs_path = match &symbol.path {
8757 SymbolLocation::InProject(project_path) => self
8758 .worktree_store
8759 .read(cx)
8760 .absolutize(&project_path, cx)
8761 .context("no such worktree"),
8762 SymbolLocation::OutsideProject {
8763 abs_path,
8764 signature: _,
8765 } => Ok(abs_path.to_path_buf()),
8766 };
8767 let symbol_abs_path = match symbol_abs_path {
8768 Ok(abs_path) => abs_path,
8769 Err(err) => return Task::ready(Err(err)),
8770 };
8771 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8772 uri
8773 } else {
8774 return Task::ready(Err(anyhow!("invalid symbol path")));
8775 };
8776
8777 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8778 } else {
8779 Task::ready(Err(anyhow!("no upstream client or local store")))
8780 }
8781 }
8782
8783 pub(crate) fn open_local_buffer_via_lsp(
8784 &mut self,
8785 abs_path: lsp::Uri,
8786 language_server_id: LanguageServerId,
8787 cx: &mut Context<Self>,
8788 ) -> Task<Result<Entity<Buffer>>> {
8789 let path_style = self.worktree_store.read(cx).path_style();
8790 cx.spawn(async move |lsp_store, cx| {
8791 // Escape percent-encoded string.
8792 let current_scheme = abs_path.scheme().to_owned();
8793 // Uri is immutable, so we can't modify the scheme
8794
8795 let abs_path = abs_path
8796 .to_file_path_ext(path_style)
8797 .map_err(|()| anyhow!("can't convert URI to path"))?;
8798 let p = abs_path.clone();
8799 let yarn_worktree = lsp_store
8800 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8801 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8802 cx.spawn(async move |this, cx| {
8803 let t = this
8804 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8805 .ok()?;
8806 t.await
8807 })
8808 }),
8809 None => Task::ready(None),
8810 })?
8811 .await;
8812 let (worktree_root_target, known_relative_path) =
8813 if let Some((zip_root, relative_path)) = yarn_worktree {
8814 (zip_root, Some(relative_path))
8815 } else {
8816 (Arc::<Path>::from(abs_path.as_path()), None)
8817 };
8818 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8819 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8820 worktree_store.find_worktree(&worktree_root_target, cx)
8821 })
8822 })?;
8823 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8824 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8825 (result.0, relative_path, None)
8826 } else {
8827 let worktree = lsp_store
8828 .update(cx, |lsp_store, cx| {
8829 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8830 worktree_store.create_worktree(&worktree_root_target, false, cx)
8831 })
8832 })?
8833 .await?;
8834 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8835 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8836 lsp_store
8837 .update(cx, |lsp_store, cx| {
8838 if let Some(local) = lsp_store.as_local_mut() {
8839 local.register_language_server_for_invisible_worktree(
8840 &worktree,
8841 language_server_id,
8842 cx,
8843 )
8844 }
8845 match lsp_store.language_server_statuses.get(&language_server_id) {
8846 Some(status) => status.worktree,
8847 None => None,
8848 }
8849 })
8850 .ok()
8851 .flatten()
8852 .zip(Some(worktree_root.clone()))
8853 } else {
8854 None
8855 };
8856 let relative_path = if let Some(known_path) = known_relative_path {
8857 known_path
8858 } else {
8859 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8860 .into_arc()
8861 };
8862 (worktree, relative_path, source_ws)
8863 };
8864 let project_path = ProjectPath {
8865 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8866 path: relative_path,
8867 };
8868 let buffer = lsp_store
8869 .update(cx, |lsp_store, cx| {
8870 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8871 buffer_store.open_buffer(project_path, cx)
8872 })
8873 })?
8874 .await?;
8875 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8876 if let Some((source_ws, worktree_root)) = source_ws {
8877 buffer.update(cx, |buffer, cx| {
8878 let settings = WorktreeSettings::get(
8879 Some(
8880 (&ProjectPath {
8881 worktree_id: source_ws,
8882 path: Arc::from(RelPath::empty()),
8883 })
8884 .into(),
8885 ),
8886 cx,
8887 );
8888 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8889 if is_read_only {
8890 buffer.set_capability(Capability::ReadOnly, cx);
8891 }
8892 });
8893 }
8894 Ok(buffer)
8895 })
8896 }
8897
8898 fn request_multiple_lsp_locally<P, R>(
8899 &mut self,
8900 buffer: &Entity<Buffer>,
8901 position: Option<P>,
8902 request: R,
8903 cx: &mut Context<Self>,
8904 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8905 where
8906 P: ToOffset,
8907 R: LspCommand + Clone,
8908 <R::LspRequest as lsp::request::Request>::Result: Send,
8909 <R::LspRequest as lsp::request::Request>::Params: Send,
8910 {
8911 let Some(local) = self.as_local() else {
8912 return Task::ready(Vec::new());
8913 };
8914
8915 let snapshot = buffer.read(cx).snapshot();
8916 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8917
8918 let server_ids = buffer.update(cx, |buffer, cx| {
8919 local
8920 .language_servers_for_buffer(buffer, cx)
8921 .filter(|(adapter, _)| {
8922 scope
8923 .as_ref()
8924 .map(|scope| scope.language_allowed(&adapter.name))
8925 .unwrap_or(true)
8926 })
8927 .map(|(_, server)| server.server_id())
8928 .filter(|server_id| {
8929 self.as_local().is_none_or(|local| {
8930 local
8931 .buffers_opened_in_servers
8932 .get(&snapshot.remote_id())
8933 .is_some_and(|servers| servers.contains(server_id))
8934 })
8935 })
8936 .collect::<Vec<_>>()
8937 });
8938
8939 let mut response_results = server_ids
8940 .into_iter()
8941 .map(|server_id| {
8942 let task = self.request_lsp(
8943 buffer.clone(),
8944 LanguageServerToQuery::Other(server_id),
8945 request.clone(),
8946 cx,
8947 );
8948 async move { (server_id, task.await) }
8949 })
8950 .collect::<FuturesUnordered<_>>();
8951
8952 cx.background_spawn(async move {
8953 let mut responses = Vec::with_capacity(response_results.len());
8954 while let Some((server_id, response_result)) = response_results.next().await {
8955 match response_result {
8956 Ok(response) => responses.push((server_id, response)),
8957 // rust-analyzer likes to error with this when its still loading up
8958 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8959 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8960 }
8961 }
8962 responses
8963 })
8964 }
8965
8966 async fn handle_lsp_get_completions(
8967 this: Entity<Self>,
8968 envelope: TypedEnvelope<proto::GetCompletions>,
8969 mut cx: AsyncApp,
8970 ) -> Result<proto::GetCompletionsResponse> {
8971 let sender_id = envelope.original_sender_id().unwrap_or_default();
8972
8973 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8974 let buffer_handle = this.update(&mut cx, |this, cx| {
8975 this.buffer_store.read(cx).get_existing(buffer_id)
8976 })?;
8977 let request = GetCompletions::from_proto(
8978 envelope.payload,
8979 this.clone(),
8980 buffer_handle.clone(),
8981 cx.clone(),
8982 )
8983 .await?;
8984
8985 let server_to_query = match request.server_id {
8986 Some(server_id) => LanguageServerToQuery::Other(server_id),
8987 None => LanguageServerToQuery::FirstCapable,
8988 };
8989
8990 let response = this
8991 .update(&mut cx, |this, cx| {
8992 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8993 })
8994 .await?;
8995 this.update(&mut cx, |this, cx| {
8996 Ok(GetCompletions::response_to_proto(
8997 response,
8998 this,
8999 sender_id,
9000 &buffer_handle.read(cx).version(),
9001 cx,
9002 ))
9003 })
9004 }
9005
9006 async fn handle_lsp_command<T: LspCommand>(
9007 this: Entity<Self>,
9008 envelope: TypedEnvelope<T::ProtoRequest>,
9009 mut cx: AsyncApp,
9010 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
9011 where
9012 <T::LspRequest as lsp::request::Request>::Params: Send,
9013 <T::LspRequest as lsp::request::Request>::Result: Send,
9014 {
9015 let sender_id = envelope.original_sender_id().unwrap_or_default();
9016 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
9017 let buffer_handle = this.update(&mut cx, |this, cx| {
9018 this.buffer_store.read(cx).get_existing(buffer_id)
9019 })?;
9020 let request = T::from_proto(
9021 envelope.payload,
9022 this.clone(),
9023 buffer_handle.clone(),
9024 cx.clone(),
9025 )
9026 .await?;
9027 let response = this
9028 .update(&mut cx, |this, cx| {
9029 this.request_lsp(
9030 buffer_handle.clone(),
9031 LanguageServerToQuery::FirstCapable,
9032 request,
9033 cx,
9034 )
9035 })
9036 .await?;
9037 this.update(&mut cx, |this, cx| {
9038 Ok(T::response_to_proto(
9039 response,
9040 this,
9041 sender_id,
9042 &buffer_handle.read(cx).version(),
9043 cx,
9044 ))
9045 })
9046 }
9047
9048 async fn handle_lsp_query(
9049 lsp_store: Entity<Self>,
9050 envelope: TypedEnvelope<proto::LspQuery>,
9051 mut cx: AsyncApp,
9052 ) -> Result<proto::Ack> {
9053 use proto::lsp_query::Request;
9054 let sender_id = envelope.original_sender_id().unwrap_or_default();
9055 let lsp_query = envelope.payload;
9056 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
9057 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
9058 match lsp_query.request.context("invalid LSP query request")? {
9059 Request::GetReferences(get_references) => {
9060 let position = get_references.position.clone().and_then(deserialize_anchor);
9061 Self::query_lsp_locally::<GetReferences>(
9062 lsp_store,
9063 server_id,
9064 sender_id,
9065 lsp_request_id,
9066 get_references,
9067 position,
9068 &mut cx,
9069 )
9070 .await?;
9071 }
9072 Request::GetDocumentColor(get_document_color) => {
9073 Self::query_lsp_locally::<GetDocumentColor>(
9074 lsp_store,
9075 server_id,
9076 sender_id,
9077 lsp_request_id,
9078 get_document_color,
9079 None,
9080 &mut cx,
9081 )
9082 .await?;
9083 }
9084 Request::GetHover(get_hover) => {
9085 let position = get_hover.position.clone().and_then(deserialize_anchor);
9086 Self::query_lsp_locally::<GetHover>(
9087 lsp_store,
9088 server_id,
9089 sender_id,
9090 lsp_request_id,
9091 get_hover,
9092 position,
9093 &mut cx,
9094 )
9095 .await?;
9096 }
9097 Request::GetCodeActions(get_code_actions) => {
9098 Self::query_lsp_locally::<GetCodeActions>(
9099 lsp_store,
9100 server_id,
9101 sender_id,
9102 lsp_request_id,
9103 get_code_actions,
9104 None,
9105 &mut cx,
9106 )
9107 .await?;
9108 }
9109 Request::GetSignatureHelp(get_signature_help) => {
9110 let position = get_signature_help
9111 .position
9112 .clone()
9113 .and_then(deserialize_anchor);
9114 Self::query_lsp_locally::<GetSignatureHelp>(
9115 lsp_store,
9116 server_id,
9117 sender_id,
9118 lsp_request_id,
9119 get_signature_help,
9120 position,
9121 &mut cx,
9122 )
9123 .await?;
9124 }
9125 Request::GetCodeLens(get_code_lens) => {
9126 Self::query_lsp_locally::<GetCodeLens>(
9127 lsp_store,
9128 server_id,
9129 sender_id,
9130 lsp_request_id,
9131 get_code_lens,
9132 None,
9133 &mut cx,
9134 )
9135 .await?;
9136 }
9137 Request::GetDefinition(get_definition) => {
9138 let position = get_definition.position.clone().and_then(deserialize_anchor);
9139 Self::query_lsp_locally::<GetDefinitions>(
9140 lsp_store,
9141 server_id,
9142 sender_id,
9143 lsp_request_id,
9144 get_definition,
9145 position,
9146 &mut cx,
9147 )
9148 .await?;
9149 }
9150 Request::GetDeclaration(get_declaration) => {
9151 let position = get_declaration
9152 .position
9153 .clone()
9154 .and_then(deserialize_anchor);
9155 Self::query_lsp_locally::<GetDeclarations>(
9156 lsp_store,
9157 server_id,
9158 sender_id,
9159 lsp_request_id,
9160 get_declaration,
9161 position,
9162 &mut cx,
9163 )
9164 .await?;
9165 }
9166 Request::GetTypeDefinition(get_type_definition) => {
9167 let position = get_type_definition
9168 .position
9169 .clone()
9170 .and_then(deserialize_anchor);
9171 Self::query_lsp_locally::<GetTypeDefinitions>(
9172 lsp_store,
9173 server_id,
9174 sender_id,
9175 lsp_request_id,
9176 get_type_definition,
9177 position,
9178 &mut cx,
9179 )
9180 .await?;
9181 }
9182 Request::GetImplementation(get_implementation) => {
9183 let position = get_implementation
9184 .position
9185 .clone()
9186 .and_then(deserialize_anchor);
9187 Self::query_lsp_locally::<GetImplementations>(
9188 lsp_store,
9189 server_id,
9190 sender_id,
9191 lsp_request_id,
9192 get_implementation,
9193 position,
9194 &mut cx,
9195 )
9196 .await?;
9197 }
9198 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9199 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9200 let version = deserialize_version(get_document_diagnostics.buffer_version());
9201 let buffer = lsp_store.update(&mut cx, |this, cx| {
9202 this.buffer_store.read(cx).get_existing(buffer_id)
9203 })?;
9204 buffer
9205 .update(&mut cx, |buffer, _| {
9206 buffer.wait_for_version(version.clone())
9207 })
9208 .await?;
9209 lsp_store.update(&mut cx, |lsp_store, cx| {
9210 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9211 let key = LspKey {
9212 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9213 server_queried: server_id,
9214 };
9215 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9216 ) {
9217 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9218 lsp_requests.clear();
9219 };
9220 }
9221
9222 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9223 existing_queries.insert(
9224 lsp_request_id,
9225 cx.spawn(async move |lsp_store, cx| {
9226 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9227 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9228 });
9229 if let Ok(diagnostics_pull) = diagnostics_pull {
9230 match diagnostics_pull.await {
9231 Ok(()) => {}
9232 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9233 };
9234 }
9235 }),
9236 );
9237 });
9238 }
9239 Request::InlayHints(inlay_hints) => {
9240 let query_start = inlay_hints
9241 .start
9242 .clone()
9243 .and_then(deserialize_anchor)
9244 .context("invalid inlay hints range start")?;
9245 let query_end = inlay_hints
9246 .end
9247 .clone()
9248 .and_then(deserialize_anchor)
9249 .context("invalid inlay hints range end")?;
9250 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9251 &lsp_store,
9252 server_id,
9253 lsp_request_id,
9254 &inlay_hints,
9255 query_start..query_end,
9256 &mut cx,
9257 )
9258 .await
9259 .context("preparing inlay hints request")?;
9260 Self::query_lsp_locally::<InlayHints>(
9261 lsp_store,
9262 server_id,
9263 sender_id,
9264 lsp_request_id,
9265 inlay_hints,
9266 None,
9267 &mut cx,
9268 )
9269 .await
9270 .context("querying for inlay hints")?
9271 }
9272 }
9273 Ok(proto::Ack {})
9274 }
9275
9276 async fn handle_lsp_query_response(
9277 lsp_store: Entity<Self>,
9278 envelope: TypedEnvelope<proto::LspQueryResponse>,
9279 cx: AsyncApp,
9280 ) -> Result<()> {
9281 lsp_store.read_with(&cx, |lsp_store, _| {
9282 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9283 upstream_client.handle_lsp_response(envelope.clone());
9284 }
9285 });
9286 Ok(())
9287 }
9288
9289 async fn handle_apply_code_action(
9290 this: Entity<Self>,
9291 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9292 mut cx: AsyncApp,
9293 ) -> Result<proto::ApplyCodeActionResponse> {
9294 let sender_id = envelope.original_sender_id().unwrap_or_default();
9295 let action =
9296 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9297 let apply_code_action = this.update(&mut cx, |this, cx| {
9298 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9299 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9300 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9301 })?;
9302
9303 let project_transaction = apply_code_action.await?;
9304 let project_transaction = this.update(&mut cx, |this, cx| {
9305 this.buffer_store.update(cx, |buffer_store, cx| {
9306 buffer_store.serialize_project_transaction_for_peer(
9307 project_transaction,
9308 sender_id,
9309 cx,
9310 )
9311 })
9312 });
9313 Ok(proto::ApplyCodeActionResponse {
9314 transaction: Some(project_transaction),
9315 })
9316 }
9317
9318 async fn handle_register_buffer_with_language_servers(
9319 this: Entity<Self>,
9320 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9321 mut cx: AsyncApp,
9322 ) -> Result<proto::Ack> {
9323 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9324 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9325 this.update(&mut cx, |this, cx| {
9326 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9327 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9328 project_id: upstream_project_id,
9329 buffer_id: buffer_id.to_proto(),
9330 only_servers: envelope.payload.only_servers,
9331 });
9332 }
9333
9334 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9335 anyhow::bail!("buffer is not open");
9336 };
9337
9338 let handle = this.register_buffer_with_language_servers(
9339 &buffer,
9340 envelope
9341 .payload
9342 .only_servers
9343 .into_iter()
9344 .filter_map(|selector| {
9345 Some(match selector.selector? {
9346 proto::language_server_selector::Selector::ServerId(server_id) => {
9347 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9348 }
9349 proto::language_server_selector::Selector::Name(name) => {
9350 LanguageServerSelector::Name(LanguageServerName(
9351 SharedString::from(name),
9352 ))
9353 }
9354 })
9355 })
9356 .collect(),
9357 false,
9358 cx,
9359 );
9360 // Pull diagnostics for the buffer even if it was already registered.
9361 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9362 // but it's unclear if we need it.
9363 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9364 .detach();
9365 this.buffer_store().update(cx, |buffer_store, _| {
9366 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9367 });
9368
9369 Ok(())
9370 })?;
9371 Ok(proto::Ack {})
9372 }
9373
9374 async fn handle_rename_project_entry(
9375 this: Entity<Self>,
9376 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9377 mut cx: AsyncApp,
9378 ) -> Result<proto::ProjectEntryResponse> {
9379 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9380 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9381 let new_path =
9382 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9383
9384 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9385 .update(&mut cx, |this, cx| {
9386 let (worktree, entry) = this
9387 .worktree_store
9388 .read(cx)
9389 .worktree_and_entry_for_id(entry_id, cx)?;
9390 let new_worktree = this
9391 .worktree_store
9392 .read(cx)
9393 .worktree_for_id(new_worktree_id, cx)?;
9394 Some((
9395 this.worktree_store.clone(),
9396 worktree,
9397 new_worktree,
9398 entry.clone(),
9399 ))
9400 })
9401 .context("worktree not found")?;
9402 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9403 (worktree.absolutize(&old_entry.path), worktree.id())
9404 });
9405 let new_abs_path =
9406 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9407
9408 let _transaction = Self::will_rename_entry(
9409 this.downgrade(),
9410 old_worktree_id,
9411 &old_abs_path,
9412 &new_abs_path,
9413 old_entry.is_dir(),
9414 cx.clone(),
9415 )
9416 .await;
9417 let response = WorktreeStore::handle_rename_project_entry(
9418 worktree_store,
9419 envelope.payload,
9420 cx.clone(),
9421 )
9422 .await;
9423 this.read_with(&cx, |this, _| {
9424 this.did_rename_entry(
9425 old_worktree_id,
9426 &old_abs_path,
9427 &new_abs_path,
9428 old_entry.is_dir(),
9429 );
9430 });
9431 response
9432 }
9433
9434 async fn handle_update_diagnostic_summary(
9435 this: Entity<Self>,
9436 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9437 mut cx: AsyncApp,
9438 ) -> Result<()> {
9439 this.update(&mut cx, |lsp_store, cx| {
9440 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9441 let mut updated_diagnostics_paths = HashMap::default();
9442 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9443 for message_summary in envelope
9444 .payload
9445 .summary
9446 .into_iter()
9447 .chain(envelope.payload.more_summaries)
9448 {
9449 let project_path = ProjectPath {
9450 worktree_id,
9451 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9452 };
9453 let path = project_path.path.clone();
9454 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9455 let summary = DiagnosticSummary {
9456 error_count: message_summary.error_count as usize,
9457 warning_count: message_summary.warning_count as usize,
9458 };
9459
9460 if summary.is_empty() {
9461 if let Some(worktree_summaries) =
9462 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9463 && let Some(summaries) = worktree_summaries.get_mut(&path)
9464 {
9465 summaries.remove(&server_id);
9466 if summaries.is_empty() {
9467 worktree_summaries.remove(&path);
9468 }
9469 }
9470 } else {
9471 lsp_store
9472 .diagnostic_summaries
9473 .entry(worktree_id)
9474 .or_default()
9475 .entry(path)
9476 .or_default()
9477 .insert(server_id, summary);
9478 }
9479
9480 if let Some((_, project_id)) = &lsp_store.downstream_client {
9481 match &mut diagnostics_summary {
9482 Some(diagnostics_summary) => {
9483 diagnostics_summary
9484 .more_summaries
9485 .push(proto::DiagnosticSummary {
9486 path: project_path.path.as_ref().to_proto(),
9487 language_server_id: server_id.0 as u64,
9488 error_count: summary.error_count as u32,
9489 warning_count: summary.warning_count as u32,
9490 })
9491 }
9492 None => {
9493 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9494 project_id: *project_id,
9495 worktree_id: worktree_id.to_proto(),
9496 summary: Some(proto::DiagnosticSummary {
9497 path: project_path.path.as_ref().to_proto(),
9498 language_server_id: server_id.0 as u64,
9499 error_count: summary.error_count as u32,
9500 warning_count: summary.warning_count as u32,
9501 }),
9502 more_summaries: Vec::new(),
9503 })
9504 }
9505 }
9506 }
9507 updated_diagnostics_paths
9508 .entry(server_id)
9509 .or_insert_with(Vec::new)
9510 .push(project_path);
9511 }
9512
9513 if let Some((diagnostics_summary, (downstream_client, _))) =
9514 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9515 {
9516 downstream_client.send(diagnostics_summary).log_err();
9517 }
9518 for (server_id, paths) in updated_diagnostics_paths {
9519 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9520 }
9521 Ok(())
9522 })
9523 }
9524
9525 async fn handle_start_language_server(
9526 lsp_store: Entity<Self>,
9527 envelope: TypedEnvelope<proto::StartLanguageServer>,
9528 mut cx: AsyncApp,
9529 ) -> Result<()> {
9530 let server = envelope.payload.server.context("invalid server")?;
9531 let server_capabilities =
9532 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9533 .with_context(|| {
9534 format!(
9535 "incorrect server capabilities {}",
9536 envelope.payload.capabilities
9537 )
9538 })?;
9539 lsp_store.update(&mut cx, |lsp_store, cx| {
9540 let server_id = LanguageServerId(server.id as usize);
9541 let server_name = LanguageServerName::from_proto(server.name.clone());
9542 lsp_store
9543 .lsp_server_capabilities
9544 .insert(server_id, server_capabilities);
9545 lsp_store.language_server_statuses.insert(
9546 server_id,
9547 LanguageServerStatus {
9548 name: server_name.clone(),
9549 server_version: None,
9550 pending_work: Default::default(),
9551 has_pending_diagnostic_updates: false,
9552 progress_tokens: Default::default(),
9553 worktree: server.worktree_id.map(WorktreeId::from_proto),
9554 binary: None,
9555 configuration: None,
9556 workspace_folders: BTreeSet::new(),
9557 },
9558 );
9559 cx.emit(LspStoreEvent::LanguageServerAdded(
9560 server_id,
9561 server_name,
9562 server.worktree_id.map(WorktreeId::from_proto),
9563 ));
9564 cx.notify();
9565 });
9566 Ok(())
9567 }
9568
9569 async fn handle_update_language_server(
9570 lsp_store: Entity<Self>,
9571 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9572 mut cx: AsyncApp,
9573 ) -> Result<()> {
9574 lsp_store.update(&mut cx, |lsp_store, cx| {
9575 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9576
9577 match envelope.payload.variant.context("invalid variant")? {
9578 proto::update_language_server::Variant::WorkStart(payload) => {
9579 lsp_store.on_lsp_work_start(
9580 language_server_id,
9581 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9582 .context("invalid progress token value")?,
9583 LanguageServerProgress {
9584 title: payload.title,
9585 is_disk_based_diagnostics_progress: false,
9586 is_cancellable: payload.is_cancellable.unwrap_or(false),
9587 message: payload.message,
9588 percentage: payload.percentage.map(|p| p as usize),
9589 last_update_at: cx.background_executor().now(),
9590 },
9591 cx,
9592 );
9593 }
9594 proto::update_language_server::Variant::WorkProgress(payload) => {
9595 lsp_store.on_lsp_work_progress(
9596 language_server_id,
9597 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9598 .context("invalid progress token value")?,
9599 LanguageServerProgress {
9600 title: None,
9601 is_disk_based_diagnostics_progress: false,
9602 is_cancellable: payload.is_cancellable.unwrap_or(false),
9603 message: payload.message,
9604 percentage: payload.percentage.map(|p| p as usize),
9605 last_update_at: cx.background_executor().now(),
9606 },
9607 cx,
9608 );
9609 }
9610
9611 proto::update_language_server::Variant::WorkEnd(payload) => {
9612 lsp_store.on_lsp_work_end(
9613 language_server_id,
9614 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9615 .context("invalid progress token value")?,
9616 cx,
9617 );
9618 }
9619
9620 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9621 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9622 }
9623
9624 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9625 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9626 }
9627
9628 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9629 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9630 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9631 cx.emit(LspStoreEvent::LanguageServerUpdate {
9632 language_server_id,
9633 name: envelope
9634 .payload
9635 .server_name
9636 .map(SharedString::new)
9637 .map(LanguageServerName),
9638 message: non_lsp,
9639 });
9640 }
9641 }
9642
9643 Ok(())
9644 })
9645 }
9646
9647 async fn handle_language_server_log(
9648 this: Entity<Self>,
9649 envelope: TypedEnvelope<proto::LanguageServerLog>,
9650 mut cx: AsyncApp,
9651 ) -> Result<()> {
9652 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9653 let log_type = envelope
9654 .payload
9655 .log_type
9656 .map(LanguageServerLogType::from_proto)
9657 .context("invalid language server log type")?;
9658
9659 let message = envelope.payload.message;
9660
9661 this.update(&mut cx, |_, cx| {
9662 cx.emit(LspStoreEvent::LanguageServerLog(
9663 language_server_id,
9664 log_type,
9665 message,
9666 ));
9667 });
9668 Ok(())
9669 }
9670
9671 async fn handle_lsp_ext_cancel_flycheck(
9672 lsp_store: Entity<Self>,
9673 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9674 cx: AsyncApp,
9675 ) -> Result<proto::Ack> {
9676 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9677 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9678 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9679 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9680 } else {
9681 None
9682 }
9683 });
9684 if let Some(task) = task {
9685 task.context("handling lsp ext cancel flycheck")?;
9686 }
9687
9688 Ok(proto::Ack {})
9689 }
9690
9691 async fn handle_lsp_ext_run_flycheck(
9692 lsp_store: Entity<Self>,
9693 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9694 mut cx: AsyncApp,
9695 ) -> Result<proto::Ack> {
9696 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9697 lsp_store.update(&mut cx, |lsp_store, cx| {
9698 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9699 let text_document = if envelope.payload.current_file_only {
9700 let buffer_id = envelope
9701 .payload
9702 .buffer_id
9703 .map(|id| BufferId::new(id))
9704 .transpose()?;
9705 buffer_id
9706 .and_then(|buffer_id| {
9707 lsp_store
9708 .buffer_store()
9709 .read(cx)
9710 .get(buffer_id)
9711 .and_then(|buffer| {
9712 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9713 })
9714 .map(|path| make_text_document_identifier(&path))
9715 })
9716 .transpose()?
9717 } else {
9718 None
9719 };
9720 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9721 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9722 )?;
9723 }
9724 anyhow::Ok(())
9725 })?;
9726
9727 Ok(proto::Ack {})
9728 }
9729
9730 async fn handle_lsp_ext_clear_flycheck(
9731 lsp_store: Entity<Self>,
9732 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9733 cx: AsyncApp,
9734 ) -> Result<proto::Ack> {
9735 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9736 lsp_store.read_with(&cx, |lsp_store, _| {
9737 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9738 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9739 } else {
9740 None
9741 }
9742 });
9743
9744 Ok(proto::Ack {})
9745 }
9746
9747 pub fn disk_based_diagnostics_started(
9748 &mut self,
9749 language_server_id: LanguageServerId,
9750 cx: &mut Context<Self>,
9751 ) {
9752 if let Some(language_server_status) =
9753 self.language_server_statuses.get_mut(&language_server_id)
9754 {
9755 language_server_status.has_pending_diagnostic_updates = true;
9756 }
9757
9758 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9759 cx.emit(LspStoreEvent::LanguageServerUpdate {
9760 language_server_id,
9761 name: self
9762 .language_server_adapter_for_id(language_server_id)
9763 .map(|adapter| adapter.name()),
9764 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9765 Default::default(),
9766 ),
9767 })
9768 }
9769
9770 pub fn disk_based_diagnostics_finished(
9771 &mut self,
9772 language_server_id: LanguageServerId,
9773 cx: &mut Context<Self>,
9774 ) {
9775 if let Some(language_server_status) =
9776 self.language_server_statuses.get_mut(&language_server_id)
9777 {
9778 language_server_status.has_pending_diagnostic_updates = false;
9779 }
9780
9781 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9782 cx.emit(LspStoreEvent::LanguageServerUpdate {
9783 language_server_id,
9784 name: self
9785 .language_server_adapter_for_id(language_server_id)
9786 .map(|adapter| adapter.name()),
9787 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9788 Default::default(),
9789 ),
9790 })
9791 }
9792
9793 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9794 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9795 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9796 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9797 // the language server might take some time to publish diagnostics.
9798 fn simulate_disk_based_diagnostics_events_if_needed(
9799 &mut self,
9800 language_server_id: LanguageServerId,
9801 cx: &mut Context<Self>,
9802 ) {
9803 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9804
9805 let Some(LanguageServerState::Running {
9806 simulate_disk_based_diagnostics_completion,
9807 adapter,
9808 ..
9809 }) = self
9810 .as_local_mut()
9811 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9812 else {
9813 return;
9814 };
9815
9816 if adapter.disk_based_diagnostics_progress_token.is_some() {
9817 return;
9818 }
9819
9820 let prev_task =
9821 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9822 cx.background_executor()
9823 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9824 .await;
9825
9826 this.update(cx, |this, cx| {
9827 this.disk_based_diagnostics_finished(language_server_id, cx);
9828
9829 if let Some(LanguageServerState::Running {
9830 simulate_disk_based_diagnostics_completion,
9831 ..
9832 }) = this.as_local_mut().and_then(|local_store| {
9833 local_store.language_servers.get_mut(&language_server_id)
9834 }) {
9835 *simulate_disk_based_diagnostics_completion = None;
9836 }
9837 })
9838 .ok();
9839 }));
9840
9841 if prev_task.is_none() {
9842 self.disk_based_diagnostics_started(language_server_id, cx);
9843 }
9844 }
9845
9846 pub fn language_server_statuses(
9847 &self,
9848 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9849 self.language_server_statuses
9850 .iter()
9851 .map(|(key, value)| (*key, value))
9852 }
9853
9854 pub(super) fn did_rename_entry(
9855 &self,
9856 worktree_id: WorktreeId,
9857 old_path: &Path,
9858 new_path: &Path,
9859 is_dir: bool,
9860 ) {
9861 maybe!({
9862 let local_store = self.as_local()?;
9863
9864 let old_uri = lsp::Uri::from_file_path(old_path)
9865 .ok()
9866 .map(|uri| uri.to_string())?;
9867 let new_uri = lsp::Uri::from_file_path(new_path)
9868 .ok()
9869 .map(|uri| uri.to_string())?;
9870
9871 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9872 let Some(filter) = local_store
9873 .language_server_paths_watched_for_rename
9874 .get(&language_server.server_id())
9875 else {
9876 continue;
9877 };
9878
9879 if filter.should_send_did_rename(&old_uri, is_dir) {
9880 language_server
9881 .notify::<DidRenameFiles>(RenameFilesParams {
9882 files: vec![FileRename {
9883 old_uri: old_uri.clone(),
9884 new_uri: new_uri.clone(),
9885 }],
9886 })
9887 .ok();
9888 }
9889 }
9890 Some(())
9891 });
9892 }
9893
9894 pub(super) fn will_rename_entry(
9895 this: WeakEntity<Self>,
9896 worktree_id: WorktreeId,
9897 old_path: &Path,
9898 new_path: &Path,
9899 is_dir: bool,
9900 cx: AsyncApp,
9901 ) -> Task<ProjectTransaction> {
9902 let old_uri = lsp::Uri::from_file_path(old_path)
9903 .ok()
9904 .map(|uri| uri.to_string());
9905 let new_uri = lsp::Uri::from_file_path(new_path)
9906 .ok()
9907 .map(|uri| uri.to_string());
9908 cx.spawn(async move |cx| {
9909 let mut tasks = vec![];
9910 this.update(cx, |this, cx| {
9911 let local_store = this.as_local()?;
9912 let old_uri = old_uri?;
9913 let new_uri = new_uri?;
9914 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9915 let Some(filter) = local_store
9916 .language_server_paths_watched_for_rename
9917 .get(&language_server.server_id())
9918 else {
9919 continue;
9920 };
9921
9922 if filter.should_send_will_rename(&old_uri, is_dir) {
9923 let apply_edit = cx.spawn({
9924 let old_uri = old_uri.clone();
9925 let new_uri = new_uri.clone();
9926 let language_server = language_server.clone();
9927 async move |this, cx| {
9928 let edit = language_server
9929 .request::<WillRenameFiles>(RenameFilesParams {
9930 files: vec![FileRename { old_uri, new_uri }],
9931 })
9932 .await
9933 .into_response()
9934 .context("will rename files")
9935 .log_err()
9936 .flatten()?;
9937
9938 let transaction = LocalLspStore::deserialize_workspace_edit(
9939 this.upgrade()?,
9940 edit,
9941 false,
9942 language_server.clone(),
9943 cx,
9944 )
9945 .await
9946 .ok()?;
9947 Some(transaction)
9948 }
9949 });
9950 tasks.push(apply_edit);
9951 }
9952 }
9953 Some(())
9954 })
9955 .ok()
9956 .flatten();
9957 let mut merged_transaction = ProjectTransaction::default();
9958 for task in tasks {
9959 // Await on tasks sequentially so that the order of application of edits is deterministic
9960 // (at least with regards to the order of registration of language servers)
9961 if let Some(transaction) = task.await {
9962 for (buffer, buffer_transaction) in transaction.0 {
9963 merged_transaction.0.insert(buffer, buffer_transaction);
9964 }
9965 }
9966 }
9967 merged_transaction
9968 })
9969 }
9970
9971 fn lsp_notify_abs_paths_changed(
9972 &mut self,
9973 server_id: LanguageServerId,
9974 changes: Vec<PathEvent>,
9975 ) {
9976 maybe!({
9977 let server = self.language_server_for_id(server_id)?;
9978 let changes = changes
9979 .into_iter()
9980 .filter_map(|event| {
9981 let typ = match event.kind? {
9982 PathEventKind::Created => lsp::FileChangeType::CREATED,
9983 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9984 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9985 };
9986 Some(lsp::FileEvent {
9987 uri: file_path_to_lsp_url(&event.path).log_err()?,
9988 typ,
9989 })
9990 })
9991 .collect::<Vec<_>>();
9992 if !changes.is_empty() {
9993 server
9994 .notify::<lsp::notification::DidChangeWatchedFiles>(
9995 lsp::DidChangeWatchedFilesParams { changes },
9996 )
9997 .ok();
9998 }
9999 Some(())
10000 });
10001 }
10002
10003 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10004 self.as_local()?.language_server_for_id(id)
10005 }
10006
10007 fn on_lsp_progress(
10008 &mut self,
10009 progress_params: lsp::ProgressParams,
10010 language_server_id: LanguageServerId,
10011 disk_based_diagnostics_progress_token: Option<String>,
10012 cx: &mut Context<Self>,
10013 ) {
10014 match progress_params.value {
10015 lsp::ProgressParamsValue::WorkDone(progress) => {
10016 self.handle_work_done_progress(
10017 progress,
10018 language_server_id,
10019 disk_based_diagnostics_progress_token,
10020 ProgressToken::from_lsp(progress_params.token),
10021 cx,
10022 );
10023 }
10024 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10025 let registration_id = match progress_params.token {
10026 lsp::NumberOrString::Number(_) => None,
10027 lsp::NumberOrString::String(token) => token
10028 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10029 .map(|(_, id)| id.to_owned()),
10030 };
10031 if let Some(LanguageServerState::Running {
10032 workspace_diagnostics_refresh_tasks,
10033 ..
10034 }) = self
10035 .as_local_mut()
10036 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10037 && let Some(workspace_diagnostics) =
10038 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10039 {
10040 workspace_diagnostics.progress_tx.try_send(()).ok();
10041 self.apply_workspace_diagnostic_report(
10042 language_server_id,
10043 report,
10044 registration_id.map(SharedString::from),
10045 cx,
10046 )
10047 }
10048 }
10049 }
10050 }
10051
10052 fn handle_work_done_progress(
10053 &mut self,
10054 progress: lsp::WorkDoneProgress,
10055 language_server_id: LanguageServerId,
10056 disk_based_diagnostics_progress_token: Option<String>,
10057 token: ProgressToken,
10058 cx: &mut Context<Self>,
10059 ) {
10060 let language_server_status =
10061 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10062 status
10063 } else {
10064 return;
10065 };
10066
10067 if !language_server_status.progress_tokens.contains(&token) {
10068 return;
10069 }
10070
10071 let is_disk_based_diagnostics_progress =
10072 if let (Some(disk_based_token), ProgressToken::String(token)) =
10073 (&disk_based_diagnostics_progress_token, &token)
10074 {
10075 token.starts_with(disk_based_token)
10076 } else {
10077 false
10078 };
10079
10080 match progress {
10081 lsp::WorkDoneProgress::Begin(report) => {
10082 if is_disk_based_diagnostics_progress {
10083 self.disk_based_diagnostics_started(language_server_id, cx);
10084 }
10085 self.on_lsp_work_start(
10086 language_server_id,
10087 token.clone(),
10088 LanguageServerProgress {
10089 title: Some(report.title),
10090 is_disk_based_diagnostics_progress,
10091 is_cancellable: report.cancellable.unwrap_or(false),
10092 message: report.message.clone(),
10093 percentage: report.percentage.map(|p| p as usize),
10094 last_update_at: cx.background_executor().now(),
10095 },
10096 cx,
10097 );
10098 }
10099 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10100 language_server_id,
10101 token,
10102 LanguageServerProgress {
10103 title: None,
10104 is_disk_based_diagnostics_progress,
10105 is_cancellable: report.cancellable.unwrap_or(false),
10106 message: report.message,
10107 percentage: report.percentage.map(|p| p as usize),
10108 last_update_at: cx.background_executor().now(),
10109 },
10110 cx,
10111 ),
10112 lsp::WorkDoneProgress::End(_) => {
10113 language_server_status.progress_tokens.remove(&token);
10114 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10115 if is_disk_based_diagnostics_progress {
10116 self.disk_based_diagnostics_finished(language_server_id, cx);
10117 }
10118 }
10119 }
10120 }
10121
10122 fn on_lsp_work_start(
10123 &mut self,
10124 language_server_id: LanguageServerId,
10125 token: ProgressToken,
10126 progress: LanguageServerProgress,
10127 cx: &mut Context<Self>,
10128 ) {
10129 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10130 status.pending_work.insert(token.clone(), progress.clone());
10131 cx.notify();
10132 }
10133 cx.emit(LspStoreEvent::LanguageServerUpdate {
10134 language_server_id,
10135 name: self
10136 .language_server_adapter_for_id(language_server_id)
10137 .map(|adapter| adapter.name()),
10138 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10139 token: Some(token.to_proto()),
10140 title: progress.title,
10141 message: progress.message,
10142 percentage: progress.percentage.map(|p| p as u32),
10143 is_cancellable: Some(progress.is_cancellable),
10144 }),
10145 })
10146 }
10147
10148 fn on_lsp_work_progress(
10149 &mut self,
10150 language_server_id: LanguageServerId,
10151 token: ProgressToken,
10152 progress: LanguageServerProgress,
10153 cx: &mut Context<Self>,
10154 ) {
10155 let mut did_update = false;
10156 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10157 match status.pending_work.entry(token.clone()) {
10158 btree_map::Entry::Vacant(entry) => {
10159 entry.insert(progress.clone());
10160 did_update = true;
10161 }
10162 btree_map::Entry::Occupied(mut entry) => {
10163 let entry = entry.get_mut();
10164 if (progress.last_update_at - entry.last_update_at)
10165 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10166 {
10167 entry.last_update_at = progress.last_update_at;
10168 if progress.message.is_some() {
10169 entry.message = progress.message.clone();
10170 }
10171 if progress.percentage.is_some() {
10172 entry.percentage = progress.percentage;
10173 }
10174 if progress.is_cancellable != entry.is_cancellable {
10175 entry.is_cancellable = progress.is_cancellable;
10176 }
10177 did_update = true;
10178 }
10179 }
10180 }
10181 }
10182
10183 if did_update {
10184 cx.emit(LspStoreEvent::LanguageServerUpdate {
10185 language_server_id,
10186 name: self
10187 .language_server_adapter_for_id(language_server_id)
10188 .map(|adapter| adapter.name()),
10189 message: proto::update_language_server::Variant::WorkProgress(
10190 proto::LspWorkProgress {
10191 token: Some(token.to_proto()),
10192 message: progress.message,
10193 percentage: progress.percentage.map(|p| p as u32),
10194 is_cancellable: Some(progress.is_cancellable),
10195 },
10196 ),
10197 })
10198 }
10199 }
10200
10201 fn on_lsp_work_end(
10202 &mut self,
10203 language_server_id: LanguageServerId,
10204 token: ProgressToken,
10205 cx: &mut Context<Self>,
10206 ) {
10207 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10208 if let Some(work) = status.pending_work.remove(&token)
10209 && !work.is_disk_based_diagnostics_progress
10210 {
10211 cx.emit(LspStoreEvent::RefreshInlayHints {
10212 server_id: language_server_id,
10213 request_id: None,
10214 });
10215 }
10216 cx.notify();
10217 }
10218
10219 cx.emit(LspStoreEvent::LanguageServerUpdate {
10220 language_server_id,
10221 name: self
10222 .language_server_adapter_for_id(language_server_id)
10223 .map(|adapter| adapter.name()),
10224 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10225 token: Some(token.to_proto()),
10226 }),
10227 })
10228 }
10229
10230 pub async fn handle_resolve_completion_documentation(
10231 this: Entity<Self>,
10232 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10233 mut cx: AsyncApp,
10234 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10235 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10236
10237 let completion = this
10238 .read_with(&cx, |this, cx| {
10239 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10240 let server = this
10241 .language_server_for_id(id)
10242 .with_context(|| format!("No language server {id}"))?;
10243
10244 anyhow::Ok(cx.background_spawn(async move {
10245 let can_resolve = server
10246 .capabilities()
10247 .completion_provider
10248 .as_ref()
10249 .and_then(|options| options.resolve_provider)
10250 .unwrap_or(false);
10251 if can_resolve {
10252 server
10253 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10254 .await
10255 .into_response()
10256 .context("resolve completion item")
10257 } else {
10258 anyhow::Ok(lsp_completion)
10259 }
10260 }))
10261 })?
10262 .await?;
10263
10264 let mut documentation_is_markdown = false;
10265 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10266 let documentation = match completion.documentation {
10267 Some(lsp::Documentation::String(text)) => text,
10268
10269 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10270 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10271 value
10272 }
10273
10274 _ => String::new(),
10275 };
10276
10277 // If we have a new buffer_id, that means we're talking to a new client
10278 // and want to check for new text_edits in the completion too.
10279 let mut old_replace_start = None;
10280 let mut old_replace_end = None;
10281 let mut old_insert_start = None;
10282 let mut old_insert_end = None;
10283 let mut new_text = String::default();
10284 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10285 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10286 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10287 anyhow::Ok(buffer.read(cx).snapshot())
10288 })?;
10289
10290 if let Some(text_edit) = completion.text_edit.as_ref() {
10291 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10292
10293 if let Some(mut edit) = edit {
10294 LineEnding::normalize(&mut edit.new_text);
10295
10296 new_text = edit.new_text;
10297 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10298 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10299 if let Some(insert_range) = edit.insert_range {
10300 old_insert_start = Some(serialize_anchor(&insert_range.start));
10301 old_insert_end = Some(serialize_anchor(&insert_range.end));
10302 }
10303 }
10304 }
10305 }
10306
10307 Ok(proto::ResolveCompletionDocumentationResponse {
10308 documentation,
10309 documentation_is_markdown,
10310 old_replace_start,
10311 old_replace_end,
10312 new_text,
10313 lsp_completion,
10314 old_insert_start,
10315 old_insert_end,
10316 })
10317 }
10318
10319 async fn handle_on_type_formatting(
10320 this: Entity<Self>,
10321 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10322 mut cx: AsyncApp,
10323 ) -> Result<proto::OnTypeFormattingResponse> {
10324 let on_type_formatting = this.update(&mut cx, |this, cx| {
10325 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10326 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10327 let position = envelope
10328 .payload
10329 .position
10330 .and_then(deserialize_anchor)
10331 .context("invalid position")?;
10332 anyhow::Ok(this.apply_on_type_formatting(
10333 buffer,
10334 position,
10335 envelope.payload.trigger.clone(),
10336 cx,
10337 ))
10338 })?;
10339
10340 let transaction = on_type_formatting
10341 .await?
10342 .as_ref()
10343 .map(language::proto::serialize_transaction);
10344 Ok(proto::OnTypeFormattingResponse { transaction })
10345 }
10346
10347 async fn handle_refresh_inlay_hints(
10348 lsp_store: Entity<Self>,
10349 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10350 mut cx: AsyncApp,
10351 ) -> Result<proto::Ack> {
10352 lsp_store.update(&mut cx, |_, cx| {
10353 cx.emit(LspStoreEvent::RefreshInlayHints {
10354 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10355 request_id: envelope.payload.request_id.map(|id| id as usize),
10356 });
10357 });
10358 Ok(proto::Ack {})
10359 }
10360
10361 async fn handle_pull_workspace_diagnostics(
10362 lsp_store: Entity<Self>,
10363 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10364 mut cx: AsyncApp,
10365 ) -> Result<proto::Ack> {
10366 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10367 lsp_store.update(&mut cx, |lsp_store, _| {
10368 lsp_store.pull_workspace_diagnostics(server_id);
10369 });
10370 Ok(proto::Ack {})
10371 }
10372
10373 async fn handle_get_color_presentation(
10374 lsp_store: Entity<Self>,
10375 envelope: TypedEnvelope<proto::GetColorPresentation>,
10376 mut cx: AsyncApp,
10377 ) -> Result<proto::GetColorPresentationResponse> {
10378 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10379 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10380 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10381 })?;
10382
10383 let color = envelope
10384 .payload
10385 .color
10386 .context("invalid color resolve request")?;
10387 let start = color
10388 .lsp_range_start
10389 .context("invalid color resolve request")?;
10390 let end = color
10391 .lsp_range_end
10392 .context("invalid color resolve request")?;
10393
10394 let color = DocumentColor {
10395 lsp_range: lsp::Range {
10396 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10397 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10398 },
10399 color: lsp::Color {
10400 red: color.red,
10401 green: color.green,
10402 blue: color.blue,
10403 alpha: color.alpha,
10404 },
10405 resolved: false,
10406 color_presentations: Vec::new(),
10407 };
10408 let resolved_color = lsp_store
10409 .update(&mut cx, |lsp_store, cx| {
10410 lsp_store.resolve_color_presentation(
10411 color,
10412 buffer.clone(),
10413 LanguageServerId(envelope.payload.server_id as usize),
10414 cx,
10415 )
10416 })
10417 .await
10418 .context("resolving color presentation")?;
10419
10420 Ok(proto::GetColorPresentationResponse {
10421 presentations: resolved_color
10422 .color_presentations
10423 .into_iter()
10424 .map(|presentation| proto::ColorPresentation {
10425 label: presentation.label.to_string(),
10426 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10427 additional_text_edits: presentation
10428 .additional_text_edits
10429 .into_iter()
10430 .map(serialize_lsp_edit)
10431 .collect(),
10432 })
10433 .collect(),
10434 })
10435 }
10436
10437 async fn handle_resolve_inlay_hint(
10438 lsp_store: Entity<Self>,
10439 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10440 mut cx: AsyncApp,
10441 ) -> Result<proto::ResolveInlayHintResponse> {
10442 let proto_hint = envelope
10443 .payload
10444 .hint
10445 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10446 let hint = InlayHints::proto_to_project_hint(proto_hint)
10447 .context("resolved proto inlay hint conversion")?;
10448 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10449 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10450 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10451 })?;
10452 let response_hint = lsp_store
10453 .update(&mut cx, |lsp_store, cx| {
10454 lsp_store.resolve_inlay_hint(
10455 hint,
10456 buffer,
10457 LanguageServerId(envelope.payload.language_server_id as usize),
10458 cx,
10459 )
10460 })
10461 .await
10462 .context("inlay hints fetch")?;
10463 Ok(proto::ResolveInlayHintResponse {
10464 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10465 })
10466 }
10467
10468 async fn handle_refresh_code_lens(
10469 this: Entity<Self>,
10470 _: TypedEnvelope<proto::RefreshCodeLens>,
10471 mut cx: AsyncApp,
10472 ) -> Result<proto::Ack> {
10473 this.update(&mut cx, |_, cx| {
10474 cx.emit(LspStoreEvent::RefreshCodeLens);
10475 });
10476 Ok(proto::Ack {})
10477 }
10478
10479 async fn handle_open_buffer_for_symbol(
10480 this: Entity<Self>,
10481 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10482 mut cx: AsyncApp,
10483 ) -> Result<proto::OpenBufferForSymbolResponse> {
10484 let peer_id = envelope.original_sender_id().unwrap_or_default();
10485 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10486 let symbol = Self::deserialize_symbol(symbol)?;
10487 this.read_with(&cx, |this, _| {
10488 if let SymbolLocation::OutsideProject {
10489 abs_path,
10490 signature,
10491 } = &symbol.path
10492 {
10493 let new_signature = this.symbol_signature(&abs_path);
10494 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10495 }
10496 Ok(())
10497 })?;
10498 let buffer = this
10499 .update(&mut cx, |this, cx| {
10500 this.open_buffer_for_symbol(
10501 &Symbol {
10502 language_server_name: symbol.language_server_name,
10503 source_worktree_id: symbol.source_worktree_id,
10504 source_language_server_id: symbol.source_language_server_id,
10505 path: symbol.path,
10506 name: symbol.name,
10507 kind: symbol.kind,
10508 range: symbol.range,
10509 label: CodeLabel::default(),
10510 },
10511 cx,
10512 )
10513 })
10514 .await?;
10515
10516 this.update(&mut cx, |this, cx| {
10517 let is_private = buffer
10518 .read(cx)
10519 .file()
10520 .map(|f| f.is_private())
10521 .unwrap_or_default();
10522 if is_private {
10523 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10524 } else {
10525 this.buffer_store
10526 .update(cx, |buffer_store, cx| {
10527 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10528 })
10529 .detach_and_log_err(cx);
10530 let buffer_id = buffer.read(cx).remote_id().to_proto();
10531 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10532 }
10533 })
10534 }
10535
10536 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10537 let mut hasher = Sha256::new();
10538 hasher.update(abs_path.to_string_lossy().as_bytes());
10539 hasher.update(self.nonce.to_be_bytes());
10540 hasher.finalize().as_slice().try_into().unwrap()
10541 }
10542
10543 pub async fn handle_get_project_symbols(
10544 this: Entity<Self>,
10545 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10546 mut cx: AsyncApp,
10547 ) -> Result<proto::GetProjectSymbolsResponse> {
10548 let symbols = this
10549 .update(&mut cx, |this, cx| {
10550 this.symbols(&envelope.payload.query, cx)
10551 })
10552 .await?;
10553
10554 Ok(proto::GetProjectSymbolsResponse {
10555 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10556 })
10557 }
10558
10559 pub async fn handle_restart_language_servers(
10560 this: Entity<Self>,
10561 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10562 mut cx: AsyncApp,
10563 ) -> Result<proto::Ack> {
10564 this.update(&mut cx, |lsp_store, cx| {
10565 let buffers =
10566 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10567 lsp_store.restart_language_servers_for_buffers(
10568 buffers,
10569 envelope
10570 .payload
10571 .only_servers
10572 .into_iter()
10573 .filter_map(|selector| {
10574 Some(match selector.selector? {
10575 proto::language_server_selector::Selector::ServerId(server_id) => {
10576 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10577 }
10578 proto::language_server_selector::Selector::Name(name) => {
10579 LanguageServerSelector::Name(LanguageServerName(
10580 SharedString::from(name),
10581 ))
10582 }
10583 })
10584 })
10585 .collect(),
10586 cx,
10587 );
10588 });
10589
10590 Ok(proto::Ack {})
10591 }
10592
10593 pub async fn handle_stop_language_servers(
10594 lsp_store: Entity<Self>,
10595 envelope: TypedEnvelope<proto::StopLanguageServers>,
10596 mut cx: AsyncApp,
10597 ) -> Result<proto::Ack> {
10598 lsp_store.update(&mut cx, |lsp_store, cx| {
10599 if envelope.payload.all
10600 && envelope.payload.also_servers.is_empty()
10601 && envelope.payload.buffer_ids.is_empty()
10602 {
10603 lsp_store.stop_all_language_servers(cx);
10604 } else {
10605 let buffers =
10606 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10607 lsp_store
10608 .stop_language_servers_for_buffers(
10609 buffers,
10610 envelope
10611 .payload
10612 .also_servers
10613 .into_iter()
10614 .filter_map(|selector| {
10615 Some(match selector.selector? {
10616 proto::language_server_selector::Selector::ServerId(
10617 server_id,
10618 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10619 server_id,
10620 )),
10621 proto::language_server_selector::Selector::Name(name) => {
10622 LanguageServerSelector::Name(LanguageServerName(
10623 SharedString::from(name),
10624 ))
10625 }
10626 })
10627 })
10628 .collect(),
10629 cx,
10630 )
10631 .detach_and_log_err(cx);
10632 }
10633 });
10634
10635 Ok(proto::Ack {})
10636 }
10637
10638 pub async fn handle_cancel_language_server_work(
10639 lsp_store: Entity<Self>,
10640 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10641 mut cx: AsyncApp,
10642 ) -> Result<proto::Ack> {
10643 lsp_store.update(&mut cx, |lsp_store, cx| {
10644 if let Some(work) = envelope.payload.work {
10645 match work {
10646 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10647 let buffers =
10648 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10649 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10650 }
10651 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10652 let server_id = LanguageServerId::from_proto(work.language_server_id);
10653 let token = work
10654 .token
10655 .map(|token| {
10656 ProgressToken::from_proto(token)
10657 .context("invalid work progress token")
10658 })
10659 .transpose()?;
10660 lsp_store.cancel_language_server_work(server_id, token, cx);
10661 }
10662 }
10663 }
10664 anyhow::Ok(())
10665 })?;
10666
10667 Ok(proto::Ack {})
10668 }
10669
10670 fn buffer_ids_to_buffers(
10671 &mut self,
10672 buffer_ids: impl Iterator<Item = u64>,
10673 cx: &mut Context<Self>,
10674 ) -> Vec<Entity<Buffer>> {
10675 buffer_ids
10676 .into_iter()
10677 .flat_map(|buffer_id| {
10678 self.buffer_store
10679 .read(cx)
10680 .get(BufferId::new(buffer_id).log_err()?)
10681 })
10682 .collect::<Vec<_>>()
10683 }
10684
10685 async fn handle_apply_additional_edits_for_completion(
10686 this: Entity<Self>,
10687 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10688 mut cx: AsyncApp,
10689 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10690 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10691 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10692 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10693 let completion = Self::deserialize_completion(
10694 envelope.payload.completion.context("invalid completion")?,
10695 )?;
10696 anyhow::Ok((buffer, completion))
10697 })?;
10698
10699 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10700 this.apply_additional_edits_for_completion(
10701 buffer,
10702 Rc::new(RefCell::new(Box::new([Completion {
10703 replace_range: completion.replace_range,
10704 new_text: completion.new_text,
10705 source: completion.source,
10706 documentation: None,
10707 label: CodeLabel::default(),
10708 match_start: None,
10709 snippet_deduplication_key: None,
10710 insert_text_mode: None,
10711 icon_path: None,
10712 confirm: None,
10713 }]))),
10714 0,
10715 false,
10716 cx,
10717 )
10718 });
10719
10720 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10721 transaction: apply_additional_edits
10722 .await?
10723 .as_ref()
10724 .map(language::proto::serialize_transaction),
10725 })
10726 }
10727
10728 pub fn last_formatting_failure(&self) -> Option<&str> {
10729 self.last_formatting_failure.as_deref()
10730 }
10731
10732 pub fn reset_last_formatting_failure(&mut self) {
10733 self.last_formatting_failure = None;
10734 }
10735
10736 pub fn environment_for_buffer(
10737 &self,
10738 buffer: &Entity<Buffer>,
10739 cx: &mut Context<Self>,
10740 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10741 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10742 environment.update(cx, |env, cx| {
10743 env.buffer_environment(buffer, &self.worktree_store, cx)
10744 })
10745 } else {
10746 Task::ready(None).shared()
10747 }
10748 }
10749
10750 pub fn format(
10751 &mut self,
10752 buffers: HashSet<Entity<Buffer>>,
10753 target: LspFormatTarget,
10754 push_to_history: bool,
10755 trigger: FormatTrigger,
10756 cx: &mut Context<Self>,
10757 ) -> Task<anyhow::Result<ProjectTransaction>> {
10758 let logger = zlog::scoped!("format");
10759 if self.as_local().is_some() {
10760 zlog::trace!(logger => "Formatting locally");
10761 let logger = zlog::scoped!(logger => "local");
10762 let buffers = buffers
10763 .into_iter()
10764 .map(|buffer_handle| {
10765 let buffer = buffer_handle.read(cx);
10766 let buffer_abs_path = File::from_dyn(buffer.file())
10767 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10768
10769 (buffer_handle, buffer_abs_path, buffer.remote_id())
10770 })
10771 .collect::<Vec<_>>();
10772
10773 cx.spawn(async move |lsp_store, cx| {
10774 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10775
10776 for (handle, abs_path, id) in buffers {
10777 let env = lsp_store
10778 .update(cx, |lsp_store, cx| {
10779 lsp_store.environment_for_buffer(&handle, cx)
10780 })?
10781 .await;
10782
10783 let ranges = match &target {
10784 LspFormatTarget::Buffers => None,
10785 LspFormatTarget::Ranges(ranges) => {
10786 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10787 }
10788 };
10789
10790 formattable_buffers.push(FormattableBuffer {
10791 handle,
10792 abs_path,
10793 env,
10794 ranges,
10795 });
10796 }
10797 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10798
10799 let format_timer = zlog::time!(logger => "Formatting buffers");
10800 let result = LocalLspStore::format_locally(
10801 lsp_store.clone(),
10802 formattable_buffers,
10803 push_to_history,
10804 trigger,
10805 logger,
10806 cx,
10807 )
10808 .await;
10809 format_timer.end();
10810
10811 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10812
10813 lsp_store.update(cx, |lsp_store, _| {
10814 lsp_store.update_last_formatting_failure(&result);
10815 })?;
10816
10817 result
10818 })
10819 } else if let Some((client, project_id)) = self.upstream_client() {
10820 zlog::trace!(logger => "Formatting remotely");
10821 let logger = zlog::scoped!(logger => "remote");
10822
10823 let buffer_ranges = match &target {
10824 LspFormatTarget::Buffers => Vec::new(),
10825 LspFormatTarget::Ranges(ranges) => ranges
10826 .iter()
10827 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10828 buffer_id: buffer_id.to_proto(),
10829 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10830 })
10831 .collect(),
10832 };
10833
10834 let buffer_store = self.buffer_store();
10835 cx.spawn(async move |lsp_store, cx| {
10836 zlog::trace!(logger => "Sending remote format request");
10837 let request_timer = zlog::time!(logger => "remote format request");
10838 let result = client
10839 .request(proto::FormatBuffers {
10840 project_id,
10841 trigger: trigger as i32,
10842 buffer_ids: buffers
10843 .iter()
10844 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10845 .collect(),
10846 buffer_ranges,
10847 })
10848 .await
10849 .and_then(|result| result.transaction.context("missing transaction"));
10850 request_timer.end();
10851
10852 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10853
10854 lsp_store.update(cx, |lsp_store, _| {
10855 lsp_store.update_last_formatting_failure(&result);
10856 })?;
10857
10858 let transaction_response = result?;
10859 let _timer = zlog::time!(logger => "deserializing project transaction");
10860 buffer_store
10861 .update(cx, |buffer_store, cx| {
10862 buffer_store.deserialize_project_transaction(
10863 transaction_response,
10864 push_to_history,
10865 cx,
10866 )
10867 })
10868 .await
10869 })
10870 } else {
10871 zlog::trace!(logger => "Not formatting");
10872 Task::ready(Ok(ProjectTransaction::default()))
10873 }
10874 }
10875
10876 async fn handle_format_buffers(
10877 this: Entity<Self>,
10878 envelope: TypedEnvelope<proto::FormatBuffers>,
10879 mut cx: AsyncApp,
10880 ) -> Result<proto::FormatBuffersResponse> {
10881 let sender_id = envelope.original_sender_id().unwrap_or_default();
10882 let format = this.update(&mut cx, |this, cx| {
10883 let mut buffers = HashSet::default();
10884 for buffer_id in &envelope.payload.buffer_ids {
10885 let buffer_id = BufferId::new(*buffer_id)?;
10886 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10887 }
10888
10889 let target = if envelope.payload.buffer_ranges.is_empty() {
10890 LspFormatTarget::Buffers
10891 } else {
10892 let mut ranges_map = BTreeMap::new();
10893 for buffer_range in &envelope.payload.buffer_ranges {
10894 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10895 let ranges: Result<Vec<_>> = buffer_range
10896 .ranges
10897 .iter()
10898 .map(|range| {
10899 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10900 })
10901 .collect();
10902 ranges_map.insert(buffer_id, ranges?);
10903 }
10904 LspFormatTarget::Ranges(ranges_map)
10905 };
10906
10907 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10908 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10909 })?;
10910
10911 let project_transaction = format.await?;
10912 let project_transaction = this.update(&mut cx, |this, cx| {
10913 this.buffer_store.update(cx, |buffer_store, cx| {
10914 buffer_store.serialize_project_transaction_for_peer(
10915 project_transaction,
10916 sender_id,
10917 cx,
10918 )
10919 })
10920 });
10921 Ok(proto::FormatBuffersResponse {
10922 transaction: Some(project_transaction),
10923 })
10924 }
10925
10926 async fn handle_apply_code_action_kind(
10927 this: Entity<Self>,
10928 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10929 mut cx: AsyncApp,
10930 ) -> Result<proto::ApplyCodeActionKindResponse> {
10931 let sender_id = envelope.original_sender_id().unwrap_or_default();
10932 let format = this.update(&mut cx, |this, cx| {
10933 let mut buffers = HashSet::default();
10934 for buffer_id in &envelope.payload.buffer_ids {
10935 let buffer_id = BufferId::new(*buffer_id)?;
10936 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10937 }
10938 let kind = match envelope.payload.kind.as_str() {
10939 "" => CodeActionKind::EMPTY,
10940 "quickfix" => CodeActionKind::QUICKFIX,
10941 "refactor" => CodeActionKind::REFACTOR,
10942 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10943 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10944 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10945 "source" => CodeActionKind::SOURCE,
10946 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10947 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10948 _ => anyhow::bail!(
10949 "Invalid code action kind {}",
10950 envelope.payload.kind.as_str()
10951 ),
10952 };
10953 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10954 })?;
10955
10956 let project_transaction = format.await?;
10957 let project_transaction = this.update(&mut cx, |this, cx| {
10958 this.buffer_store.update(cx, |buffer_store, cx| {
10959 buffer_store.serialize_project_transaction_for_peer(
10960 project_transaction,
10961 sender_id,
10962 cx,
10963 )
10964 })
10965 });
10966 Ok(proto::ApplyCodeActionKindResponse {
10967 transaction: Some(project_transaction),
10968 })
10969 }
10970
10971 async fn shutdown_language_server(
10972 server_state: Option<LanguageServerState>,
10973 name: LanguageServerName,
10974 cx: &mut AsyncApp,
10975 ) {
10976 let server = match server_state {
10977 Some(LanguageServerState::Starting { startup, .. }) => {
10978 let mut timer = cx
10979 .background_executor()
10980 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10981 .fuse();
10982
10983 select! {
10984 server = startup.fuse() => server,
10985 () = timer => {
10986 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10987 None
10988 },
10989 }
10990 }
10991
10992 Some(LanguageServerState::Running { server, .. }) => Some(server),
10993
10994 None => None,
10995 };
10996
10997 if let Some(server) = server
10998 && let Some(shutdown) = server.shutdown()
10999 {
11000 shutdown.await;
11001 }
11002 }
11003
11004 // Returns a list of all of the worktrees which no longer have a language server and the root path
11005 // for the stopped server
11006 fn stop_local_language_server(
11007 &mut self,
11008 server_id: LanguageServerId,
11009 cx: &mut Context<Self>,
11010 ) -> Task<()> {
11011 let local = match &mut self.mode {
11012 LspStoreMode::Local(local) => local,
11013 _ => {
11014 return Task::ready(());
11015 }
11016 };
11017
11018 // Remove this server ID from all entries in the given worktree.
11019 local
11020 .language_server_ids
11021 .retain(|_, state| state.id != server_id);
11022 self.buffer_store.update(cx, |buffer_store, cx| {
11023 for buffer in buffer_store.buffers() {
11024 buffer.update(cx, |buffer, cx| {
11025 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
11026 buffer.set_completion_triggers(server_id, Default::default(), cx);
11027 });
11028 }
11029 });
11030
11031 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
11032 summaries.retain(|path, summaries_by_server_id| {
11033 if summaries_by_server_id.remove(&server_id).is_some() {
11034 if let Some((client, project_id)) = self.downstream_client.clone() {
11035 client
11036 .send(proto::UpdateDiagnosticSummary {
11037 project_id,
11038 worktree_id: worktree_id.to_proto(),
11039 summary: Some(proto::DiagnosticSummary {
11040 path: path.as_ref().to_proto(),
11041 language_server_id: server_id.0 as u64,
11042 error_count: 0,
11043 warning_count: 0,
11044 }),
11045 more_summaries: Vec::new(),
11046 })
11047 .log_err();
11048 }
11049 !summaries_by_server_id.is_empty()
11050 } else {
11051 true
11052 }
11053 });
11054 }
11055
11056 let local = self.as_local_mut().unwrap();
11057 for diagnostics in local.diagnostics.values_mut() {
11058 diagnostics.retain(|_, diagnostics_by_server_id| {
11059 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11060 diagnostics_by_server_id.remove(ix);
11061 !diagnostics_by_server_id.is_empty()
11062 } else {
11063 true
11064 }
11065 });
11066 }
11067 local.language_server_watched_paths.remove(&server_id);
11068
11069 let server_state = local.language_servers.remove(&server_id);
11070 self.cleanup_lsp_data(server_id);
11071 let name = self
11072 .language_server_statuses
11073 .remove(&server_id)
11074 .map(|status| status.name)
11075 .or_else(|| {
11076 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11077 Some(adapter.name())
11078 } else {
11079 None
11080 }
11081 });
11082
11083 if let Some(name) = name {
11084 log::info!("stopping language server {name}");
11085 self.languages
11086 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11087 cx.notify();
11088
11089 return cx.spawn(async move |lsp_store, cx| {
11090 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11091 lsp_store
11092 .update(cx, |lsp_store, cx| {
11093 lsp_store
11094 .languages
11095 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11096 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11097 cx.notify();
11098 })
11099 .ok();
11100 });
11101 }
11102
11103 if server_state.is_some() {
11104 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11105 }
11106 Task::ready(())
11107 }
11108
11109 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11110 self.shutdown_all_language_servers(cx).detach();
11111 }
11112
11113 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11114 if let Some((client, project_id)) = self.upstream_client() {
11115 let request = client.request(proto::StopLanguageServers {
11116 project_id,
11117 buffer_ids: Vec::new(),
11118 also_servers: Vec::new(),
11119 all: true,
11120 });
11121 cx.background_spawn(async move {
11122 request.await.ok();
11123 })
11124 } else {
11125 let Some(local) = self.as_local_mut() else {
11126 return Task::ready(());
11127 };
11128 let language_servers_to_stop = local
11129 .language_server_ids
11130 .values()
11131 .map(|state| state.id)
11132 .collect();
11133 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11134 let tasks = language_servers_to_stop
11135 .into_iter()
11136 .map(|server| self.stop_local_language_server(server, cx))
11137 .collect::<Vec<_>>();
11138 cx.background_spawn(async move {
11139 futures::future::join_all(tasks).await;
11140 })
11141 }
11142 }
11143
11144 pub fn restart_language_servers_for_buffers(
11145 &mut self,
11146 buffers: Vec<Entity<Buffer>>,
11147 only_restart_servers: HashSet<LanguageServerSelector>,
11148 cx: &mut Context<Self>,
11149 ) {
11150 if let Some((client, project_id)) = self.upstream_client() {
11151 let request = client.request(proto::RestartLanguageServers {
11152 project_id,
11153 buffer_ids: buffers
11154 .into_iter()
11155 .map(|b| b.read(cx).remote_id().to_proto())
11156 .collect(),
11157 only_servers: only_restart_servers
11158 .into_iter()
11159 .map(|selector| {
11160 let selector = match selector {
11161 LanguageServerSelector::Id(language_server_id) => {
11162 proto::language_server_selector::Selector::ServerId(
11163 language_server_id.to_proto(),
11164 )
11165 }
11166 LanguageServerSelector::Name(language_server_name) => {
11167 proto::language_server_selector::Selector::Name(
11168 language_server_name.to_string(),
11169 )
11170 }
11171 };
11172 proto::LanguageServerSelector {
11173 selector: Some(selector),
11174 }
11175 })
11176 .collect(),
11177 all: false,
11178 });
11179 cx.background_spawn(request).detach_and_log_err(cx);
11180 } else {
11181 let stop_task = if only_restart_servers.is_empty() {
11182 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11183 } else {
11184 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11185 };
11186 cx.spawn(async move |lsp_store, cx| {
11187 stop_task.await;
11188 lsp_store.update(cx, |lsp_store, cx| {
11189 for buffer in buffers {
11190 lsp_store.register_buffer_with_language_servers(
11191 &buffer,
11192 only_restart_servers.clone(),
11193 true,
11194 cx,
11195 );
11196 }
11197 })
11198 })
11199 .detach();
11200 }
11201 }
11202
11203 pub fn stop_language_servers_for_buffers(
11204 &mut self,
11205 buffers: Vec<Entity<Buffer>>,
11206 also_stop_servers: HashSet<LanguageServerSelector>,
11207 cx: &mut Context<Self>,
11208 ) -> Task<Result<()>> {
11209 if let Some((client, project_id)) = self.upstream_client() {
11210 let request = client.request(proto::StopLanguageServers {
11211 project_id,
11212 buffer_ids: buffers
11213 .into_iter()
11214 .map(|b| b.read(cx).remote_id().to_proto())
11215 .collect(),
11216 also_servers: also_stop_servers
11217 .into_iter()
11218 .map(|selector| {
11219 let selector = match selector {
11220 LanguageServerSelector::Id(language_server_id) => {
11221 proto::language_server_selector::Selector::ServerId(
11222 language_server_id.to_proto(),
11223 )
11224 }
11225 LanguageServerSelector::Name(language_server_name) => {
11226 proto::language_server_selector::Selector::Name(
11227 language_server_name.to_string(),
11228 )
11229 }
11230 };
11231 proto::LanguageServerSelector {
11232 selector: Some(selector),
11233 }
11234 })
11235 .collect(),
11236 all: false,
11237 });
11238 cx.background_spawn(async move {
11239 let _ = request.await?;
11240 Ok(())
11241 })
11242 } else {
11243 let task =
11244 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11245 cx.background_spawn(async move {
11246 task.await;
11247 Ok(())
11248 })
11249 }
11250 }
11251
11252 fn stop_local_language_servers_for_buffers(
11253 &mut self,
11254 buffers: &[Entity<Buffer>],
11255 also_stop_servers: HashSet<LanguageServerSelector>,
11256 cx: &mut Context<Self>,
11257 ) -> Task<()> {
11258 let Some(local) = self.as_local_mut() else {
11259 return Task::ready(());
11260 };
11261 let mut language_server_names_to_stop = BTreeSet::default();
11262 let mut language_servers_to_stop = also_stop_servers
11263 .into_iter()
11264 .flat_map(|selector| match selector {
11265 LanguageServerSelector::Id(id) => Some(id),
11266 LanguageServerSelector::Name(name) => {
11267 language_server_names_to_stop.insert(name);
11268 None
11269 }
11270 })
11271 .collect::<BTreeSet<_>>();
11272
11273 let mut covered_worktrees = HashSet::default();
11274 for buffer in buffers {
11275 buffer.update(cx, |buffer, cx| {
11276 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11277 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11278 && covered_worktrees.insert(worktree_id)
11279 {
11280 language_server_names_to_stop.retain(|name| {
11281 let old_ids_count = language_servers_to_stop.len();
11282 let all_language_servers_with_this_name = local
11283 .language_server_ids
11284 .iter()
11285 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11286 language_servers_to_stop.extend(all_language_servers_with_this_name);
11287 old_ids_count == language_servers_to_stop.len()
11288 });
11289 }
11290 });
11291 }
11292 for name in language_server_names_to_stop {
11293 language_servers_to_stop.extend(
11294 local
11295 .language_server_ids
11296 .iter()
11297 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11298 );
11299 }
11300
11301 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11302 let tasks = language_servers_to_stop
11303 .into_iter()
11304 .map(|server| self.stop_local_language_server(server, cx))
11305 .collect::<Vec<_>>();
11306
11307 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11308 }
11309
11310 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11311 let (worktree, relative_path) =
11312 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11313
11314 let project_path = ProjectPath {
11315 worktree_id: worktree.read(cx).id(),
11316 path: relative_path,
11317 };
11318
11319 Some(
11320 self.buffer_store()
11321 .read(cx)
11322 .get_by_path(&project_path)?
11323 .read(cx),
11324 )
11325 }
11326
11327 #[cfg(any(test, feature = "test-support"))]
11328 pub fn update_diagnostics(
11329 &mut self,
11330 server_id: LanguageServerId,
11331 diagnostics: lsp::PublishDiagnosticsParams,
11332 result_id: Option<SharedString>,
11333 source_kind: DiagnosticSourceKind,
11334 disk_based_sources: &[String],
11335 cx: &mut Context<Self>,
11336 ) -> Result<()> {
11337 self.merge_lsp_diagnostics(
11338 source_kind,
11339 vec![DocumentDiagnosticsUpdate {
11340 diagnostics,
11341 result_id,
11342 server_id,
11343 disk_based_sources: Cow::Borrowed(disk_based_sources),
11344 registration_id: None,
11345 }],
11346 |_, _, _| false,
11347 cx,
11348 )
11349 }
11350
11351 pub fn merge_lsp_diagnostics(
11352 &mut self,
11353 source_kind: DiagnosticSourceKind,
11354 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11355 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11356 cx: &mut Context<Self>,
11357 ) -> Result<()> {
11358 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11359 let updates = lsp_diagnostics
11360 .into_iter()
11361 .filter_map(|update| {
11362 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11363 Some(DocumentDiagnosticsUpdate {
11364 diagnostics: self.lsp_to_document_diagnostics(
11365 abs_path,
11366 source_kind,
11367 update.server_id,
11368 update.diagnostics,
11369 &update.disk_based_sources,
11370 update.registration_id.clone(),
11371 ),
11372 result_id: update.result_id,
11373 server_id: update.server_id,
11374 disk_based_sources: update.disk_based_sources,
11375 registration_id: update.registration_id,
11376 })
11377 })
11378 .collect();
11379 self.merge_diagnostic_entries(updates, merge, cx)?;
11380 Ok(())
11381 }
11382
11383 fn lsp_to_document_diagnostics(
11384 &mut self,
11385 document_abs_path: PathBuf,
11386 source_kind: DiagnosticSourceKind,
11387 server_id: LanguageServerId,
11388 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11389 disk_based_sources: &[String],
11390 registration_id: Option<SharedString>,
11391 ) -> DocumentDiagnostics {
11392 let mut diagnostics = Vec::default();
11393 let mut primary_diagnostic_group_ids = HashMap::default();
11394 let mut sources_by_group_id = HashMap::default();
11395 let mut supporting_diagnostics = HashMap::default();
11396
11397 let adapter = self.language_server_adapter_for_id(server_id);
11398
11399 // Ensure that primary diagnostics are always the most severe
11400 lsp_diagnostics
11401 .diagnostics
11402 .sort_by_key(|item| item.severity);
11403
11404 for diagnostic in &lsp_diagnostics.diagnostics {
11405 let source = diagnostic.source.as_ref();
11406 let range = range_from_lsp(diagnostic.range);
11407 let is_supporting = diagnostic
11408 .related_information
11409 .as_ref()
11410 .is_some_and(|infos| {
11411 infos.iter().any(|info| {
11412 primary_diagnostic_group_ids.contains_key(&(
11413 source,
11414 diagnostic.code.clone(),
11415 range_from_lsp(info.location.range),
11416 ))
11417 })
11418 });
11419
11420 let is_unnecessary = diagnostic
11421 .tags
11422 .as_ref()
11423 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11424
11425 let underline = self
11426 .language_server_adapter_for_id(server_id)
11427 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11428
11429 if is_supporting {
11430 supporting_diagnostics.insert(
11431 (source, diagnostic.code.clone(), range),
11432 (diagnostic.severity, is_unnecessary),
11433 );
11434 } else {
11435 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11436 let is_disk_based =
11437 source.is_some_and(|source| disk_based_sources.contains(source));
11438
11439 sources_by_group_id.insert(group_id, source);
11440 primary_diagnostic_group_ids
11441 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11442
11443 diagnostics.push(DiagnosticEntry {
11444 range,
11445 diagnostic: Diagnostic {
11446 source: diagnostic.source.clone(),
11447 source_kind,
11448 code: diagnostic.code.clone(),
11449 code_description: diagnostic
11450 .code_description
11451 .as_ref()
11452 .and_then(|d| d.href.clone()),
11453 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11454 markdown: adapter.as_ref().and_then(|adapter| {
11455 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11456 }),
11457 message: diagnostic.message.trim().to_string(),
11458 group_id,
11459 is_primary: true,
11460 is_disk_based,
11461 is_unnecessary,
11462 underline,
11463 data: diagnostic.data.clone(),
11464 registration_id: registration_id.clone(),
11465 },
11466 });
11467 if let Some(infos) = &diagnostic.related_information {
11468 for info in infos {
11469 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11470 let range = range_from_lsp(info.location.range);
11471 diagnostics.push(DiagnosticEntry {
11472 range,
11473 diagnostic: Diagnostic {
11474 source: diagnostic.source.clone(),
11475 source_kind,
11476 code: diagnostic.code.clone(),
11477 code_description: diagnostic
11478 .code_description
11479 .as_ref()
11480 .and_then(|d| d.href.clone()),
11481 severity: DiagnosticSeverity::INFORMATION,
11482 markdown: adapter.as_ref().and_then(|adapter| {
11483 adapter.diagnostic_message_to_markdown(&info.message)
11484 }),
11485 message: info.message.trim().to_string(),
11486 group_id,
11487 is_primary: false,
11488 is_disk_based,
11489 is_unnecessary: false,
11490 underline,
11491 data: diagnostic.data.clone(),
11492 registration_id: registration_id.clone(),
11493 },
11494 });
11495 }
11496 }
11497 }
11498 }
11499 }
11500
11501 for entry in &mut diagnostics {
11502 let diagnostic = &mut entry.diagnostic;
11503 if !diagnostic.is_primary {
11504 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11505 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11506 source,
11507 diagnostic.code.clone(),
11508 entry.range.clone(),
11509 )) {
11510 if let Some(severity) = severity {
11511 diagnostic.severity = severity;
11512 }
11513 diagnostic.is_unnecessary = is_unnecessary;
11514 }
11515 }
11516 }
11517
11518 DocumentDiagnostics {
11519 diagnostics,
11520 document_abs_path,
11521 version: lsp_diagnostics.version,
11522 }
11523 }
11524
11525 fn insert_newly_running_language_server(
11526 &mut self,
11527 adapter: Arc<CachedLspAdapter>,
11528 language_server: Arc<LanguageServer>,
11529 server_id: LanguageServerId,
11530 key: LanguageServerSeed,
11531 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11532 cx: &mut Context<Self>,
11533 ) {
11534 let Some(local) = self.as_local_mut() else {
11535 return;
11536 };
11537 // If the language server for this key doesn't match the server id, don't store the
11538 // server. Which will cause it to be dropped, killing the process
11539 if local
11540 .language_server_ids
11541 .get(&key)
11542 .map(|state| state.id != server_id)
11543 .unwrap_or(false)
11544 {
11545 return;
11546 }
11547
11548 // Update language_servers collection with Running variant of LanguageServerState
11549 // indicating that the server is up and running and ready
11550 let workspace_folders = workspace_folders.lock().clone();
11551 language_server.set_workspace_folders(workspace_folders);
11552
11553 let workspace_diagnostics_refresh_tasks = language_server
11554 .capabilities()
11555 .diagnostic_provider
11556 .and_then(|provider| {
11557 local
11558 .language_server_dynamic_registrations
11559 .entry(server_id)
11560 .or_default()
11561 .diagnostics
11562 .entry(None)
11563 .or_insert(provider.clone());
11564 let workspace_refresher =
11565 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11566
11567 Some((None, workspace_refresher))
11568 })
11569 .into_iter()
11570 .collect();
11571 local.language_servers.insert(
11572 server_id,
11573 LanguageServerState::Running {
11574 workspace_diagnostics_refresh_tasks,
11575 adapter: adapter.clone(),
11576 server: language_server.clone(),
11577 simulate_disk_based_diagnostics_completion: None,
11578 },
11579 );
11580 local
11581 .languages
11582 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11583 if let Some(file_ops_caps) = language_server
11584 .capabilities()
11585 .workspace
11586 .as_ref()
11587 .and_then(|ws| ws.file_operations.as_ref())
11588 {
11589 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11590 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11591 if did_rename_caps.or(will_rename_caps).is_some() {
11592 let watcher = RenamePathsWatchedForServer::default()
11593 .with_did_rename_patterns(did_rename_caps)
11594 .with_will_rename_patterns(will_rename_caps);
11595 local
11596 .language_server_paths_watched_for_rename
11597 .insert(server_id, watcher);
11598 }
11599 }
11600
11601 self.language_server_statuses.insert(
11602 server_id,
11603 LanguageServerStatus {
11604 name: language_server.name(),
11605 server_version: language_server.version(),
11606 pending_work: Default::default(),
11607 has_pending_diagnostic_updates: false,
11608 progress_tokens: Default::default(),
11609 worktree: Some(key.worktree_id),
11610 binary: Some(language_server.binary().clone()),
11611 configuration: Some(language_server.configuration().clone()),
11612 workspace_folders: language_server.workspace_folders(),
11613 },
11614 );
11615
11616 cx.emit(LspStoreEvent::LanguageServerAdded(
11617 server_id,
11618 language_server.name(),
11619 Some(key.worktree_id),
11620 ));
11621
11622 let server_capabilities = language_server.capabilities();
11623 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11624 downstream_client
11625 .send(proto::StartLanguageServer {
11626 project_id: *project_id,
11627 server: Some(proto::LanguageServer {
11628 id: server_id.to_proto(),
11629 name: language_server.name().to_string(),
11630 worktree_id: Some(key.worktree_id.to_proto()),
11631 }),
11632 capabilities: serde_json::to_string(&server_capabilities)
11633 .expect("serializing server LSP capabilities"),
11634 })
11635 .log_err();
11636 }
11637 self.lsp_server_capabilities
11638 .insert(server_id, server_capabilities);
11639
11640 // Tell the language server about every open buffer in the worktree that matches the language.
11641 // Also check for buffers in worktrees that reused this server
11642 let mut worktrees_using_server = vec![key.worktree_id];
11643 if let Some(local) = self.as_local() {
11644 // Find all worktrees that have this server in their language server tree
11645 for (worktree_id, servers) in &local.lsp_tree.instances {
11646 if *worktree_id != key.worktree_id {
11647 for server_map in servers.roots.values() {
11648 if server_map
11649 .values()
11650 .any(|(node, _)| node.id() == Some(server_id))
11651 {
11652 worktrees_using_server.push(*worktree_id);
11653 }
11654 }
11655 }
11656 }
11657 }
11658
11659 let mut buffer_paths_registered = Vec::new();
11660 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11661 let mut lsp_adapters = HashMap::default();
11662 for buffer_handle in buffer_store.buffers() {
11663 let buffer = buffer_handle.read(cx);
11664 let file = match File::from_dyn(buffer.file()) {
11665 Some(file) => file,
11666 None => continue,
11667 };
11668 let language = match buffer.language() {
11669 Some(language) => language,
11670 None => continue,
11671 };
11672
11673 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11674 || !lsp_adapters
11675 .entry(language.name())
11676 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11677 .iter()
11678 .any(|a| a.name == key.name)
11679 {
11680 continue;
11681 }
11682 // didOpen
11683 let file = match file.as_local() {
11684 Some(file) => file,
11685 None => continue,
11686 };
11687
11688 let local = self.as_local_mut().unwrap();
11689
11690 let buffer_id = buffer.remote_id();
11691 if local.registered_buffers.contains_key(&buffer_id) {
11692 let versions = local
11693 .buffer_snapshots
11694 .entry(buffer_id)
11695 .or_default()
11696 .entry(server_id)
11697 .and_modify(|_| {
11698 assert!(
11699 false,
11700 "There should not be an existing snapshot for a newly inserted buffer"
11701 )
11702 })
11703 .or_insert_with(|| {
11704 vec![LspBufferSnapshot {
11705 version: 0,
11706 snapshot: buffer.text_snapshot(),
11707 }]
11708 });
11709
11710 let snapshot = versions.last().unwrap();
11711 let version = snapshot.version;
11712 let initial_snapshot = &snapshot.snapshot;
11713 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11714 language_server.register_buffer(
11715 uri,
11716 adapter.language_id(&language.name()),
11717 version,
11718 initial_snapshot.text(),
11719 );
11720 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11721 local
11722 .buffers_opened_in_servers
11723 .entry(buffer_id)
11724 .or_default()
11725 .insert(server_id);
11726 }
11727 buffer_handle.update(cx, |buffer, cx| {
11728 buffer.set_completion_triggers(
11729 server_id,
11730 language_server
11731 .capabilities()
11732 .completion_provider
11733 .as_ref()
11734 .and_then(|provider| {
11735 provider
11736 .trigger_characters
11737 .as_ref()
11738 .map(|characters| characters.iter().cloned().collect())
11739 })
11740 .unwrap_or_default(),
11741 cx,
11742 )
11743 });
11744 }
11745 });
11746
11747 for (buffer_id, abs_path) in buffer_paths_registered {
11748 cx.emit(LspStoreEvent::LanguageServerUpdate {
11749 language_server_id: server_id,
11750 name: Some(adapter.name()),
11751 message: proto::update_language_server::Variant::RegisteredForBuffer(
11752 proto::RegisteredForBuffer {
11753 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11754 buffer_id: buffer_id.to_proto(),
11755 },
11756 ),
11757 });
11758 }
11759
11760 cx.notify();
11761 }
11762
11763 pub fn language_servers_running_disk_based_diagnostics(
11764 &self,
11765 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11766 self.language_server_statuses
11767 .iter()
11768 .filter_map(|(id, status)| {
11769 if status.has_pending_diagnostic_updates {
11770 Some(*id)
11771 } else {
11772 None
11773 }
11774 })
11775 }
11776
11777 pub(crate) fn cancel_language_server_work_for_buffers(
11778 &mut self,
11779 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11780 cx: &mut Context<Self>,
11781 ) {
11782 if let Some((client, project_id)) = self.upstream_client() {
11783 let request = client.request(proto::CancelLanguageServerWork {
11784 project_id,
11785 work: Some(proto::cancel_language_server_work::Work::Buffers(
11786 proto::cancel_language_server_work::Buffers {
11787 buffer_ids: buffers
11788 .into_iter()
11789 .map(|b| b.read(cx).remote_id().to_proto())
11790 .collect(),
11791 },
11792 )),
11793 });
11794 cx.background_spawn(request).detach_and_log_err(cx);
11795 } else if let Some(local) = self.as_local() {
11796 let servers = buffers
11797 .into_iter()
11798 .flat_map(|buffer| {
11799 buffer.update(cx, |buffer, cx| {
11800 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11801 })
11802 })
11803 .collect::<HashSet<_>>();
11804 for server_id in servers {
11805 self.cancel_language_server_work(server_id, None, cx);
11806 }
11807 }
11808 }
11809
11810 pub(crate) fn cancel_language_server_work(
11811 &mut self,
11812 server_id: LanguageServerId,
11813 token_to_cancel: Option<ProgressToken>,
11814 cx: &mut Context<Self>,
11815 ) {
11816 if let Some(local) = self.as_local() {
11817 let status = self.language_server_statuses.get(&server_id);
11818 let server = local.language_servers.get(&server_id);
11819 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11820 {
11821 for (token, progress) in &status.pending_work {
11822 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11823 && token != token_to_cancel
11824 {
11825 continue;
11826 }
11827 if progress.is_cancellable {
11828 server
11829 .notify::<lsp::notification::WorkDoneProgressCancel>(
11830 WorkDoneProgressCancelParams {
11831 token: token.to_lsp(),
11832 },
11833 )
11834 .ok();
11835 }
11836 }
11837 }
11838 } else if let Some((client, project_id)) = self.upstream_client() {
11839 let request = client.request(proto::CancelLanguageServerWork {
11840 project_id,
11841 work: Some(
11842 proto::cancel_language_server_work::Work::LanguageServerWork(
11843 proto::cancel_language_server_work::LanguageServerWork {
11844 language_server_id: server_id.to_proto(),
11845 token: token_to_cancel.map(|token| token.to_proto()),
11846 },
11847 ),
11848 ),
11849 });
11850 cx.background_spawn(request).detach_and_log_err(cx);
11851 }
11852 }
11853
11854 fn register_supplementary_language_server(
11855 &mut self,
11856 id: LanguageServerId,
11857 name: LanguageServerName,
11858 server: Arc<LanguageServer>,
11859 cx: &mut Context<Self>,
11860 ) {
11861 if let Some(local) = self.as_local_mut() {
11862 local
11863 .supplementary_language_servers
11864 .insert(id, (name.clone(), server));
11865 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11866 }
11867 }
11868
11869 fn unregister_supplementary_language_server(
11870 &mut self,
11871 id: LanguageServerId,
11872 cx: &mut Context<Self>,
11873 ) {
11874 if let Some(local) = self.as_local_mut() {
11875 local.supplementary_language_servers.remove(&id);
11876 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11877 }
11878 }
11879
11880 pub(crate) fn supplementary_language_servers(
11881 &self,
11882 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11883 self.as_local().into_iter().flat_map(|local| {
11884 local
11885 .supplementary_language_servers
11886 .iter()
11887 .map(|(id, (name, _))| (*id, name.clone()))
11888 })
11889 }
11890
11891 pub fn language_server_adapter_for_id(
11892 &self,
11893 id: LanguageServerId,
11894 ) -> Option<Arc<CachedLspAdapter>> {
11895 self.as_local()
11896 .and_then(|local| local.language_servers.get(&id))
11897 .and_then(|language_server_state| match language_server_state {
11898 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11899 _ => None,
11900 })
11901 }
11902
11903 pub(super) fn update_local_worktree_language_servers(
11904 &mut self,
11905 worktree_handle: &Entity<Worktree>,
11906 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11907 cx: &mut Context<Self>,
11908 ) {
11909 if changes.is_empty() {
11910 return;
11911 }
11912
11913 let Some(local) = self.as_local() else { return };
11914
11915 local.prettier_store.update(cx, |prettier_store, cx| {
11916 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11917 });
11918
11919 let worktree_id = worktree_handle.read(cx).id();
11920 let mut language_server_ids = local
11921 .language_server_ids
11922 .iter()
11923 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11924 .collect::<Vec<_>>();
11925 language_server_ids.sort();
11926 language_server_ids.dedup();
11927
11928 // let abs_path = worktree_handle.read(cx).abs_path();
11929 for server_id in &language_server_ids {
11930 if let Some(LanguageServerState::Running { server, .. }) =
11931 local.language_servers.get(server_id)
11932 && let Some(watched_paths) = local
11933 .language_server_watched_paths
11934 .get(server_id)
11935 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11936 {
11937 let params = lsp::DidChangeWatchedFilesParams {
11938 changes: changes
11939 .iter()
11940 .filter_map(|(path, _, change)| {
11941 if !watched_paths.is_match(path.as_std_path()) {
11942 return None;
11943 }
11944 let typ = match change {
11945 PathChange::Loaded => return None,
11946 PathChange::Added => lsp::FileChangeType::CREATED,
11947 PathChange::Removed => lsp::FileChangeType::DELETED,
11948 PathChange::Updated => lsp::FileChangeType::CHANGED,
11949 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11950 };
11951 let uri = lsp::Uri::from_file_path(
11952 worktree_handle.read(cx).absolutize(&path),
11953 )
11954 .ok()?;
11955 Some(lsp::FileEvent { uri, typ })
11956 })
11957 .collect(),
11958 };
11959 if !params.changes.is_empty() {
11960 server
11961 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11962 .ok();
11963 }
11964 }
11965 }
11966 for (path, _, _) in changes {
11967 if let Some(file_name) = path.file_name()
11968 && local.watched_manifest_filenames.contains(file_name)
11969 {
11970 self.request_workspace_config_refresh();
11971 break;
11972 }
11973 }
11974 }
11975
11976 pub fn wait_for_remote_buffer(
11977 &mut self,
11978 id: BufferId,
11979 cx: &mut Context<Self>,
11980 ) -> Task<Result<Entity<Buffer>>> {
11981 self.buffer_store.update(cx, |buffer_store, cx| {
11982 buffer_store.wait_for_remote_buffer(id, cx)
11983 })
11984 }
11985
11986 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11987 let mut result = proto::Symbol {
11988 language_server_name: symbol.language_server_name.0.to_string(),
11989 source_worktree_id: symbol.source_worktree_id.to_proto(),
11990 language_server_id: symbol.source_language_server_id.to_proto(),
11991 name: symbol.name.clone(),
11992 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11993 start: Some(proto::PointUtf16 {
11994 row: symbol.range.start.0.row,
11995 column: symbol.range.start.0.column,
11996 }),
11997 end: Some(proto::PointUtf16 {
11998 row: symbol.range.end.0.row,
11999 column: symbol.range.end.0.column,
12000 }),
12001 worktree_id: Default::default(),
12002 path: Default::default(),
12003 signature: Default::default(),
12004 };
12005 match &symbol.path {
12006 SymbolLocation::InProject(path) => {
12007 result.worktree_id = path.worktree_id.to_proto();
12008 result.path = path.path.to_proto();
12009 }
12010 SymbolLocation::OutsideProject {
12011 abs_path,
12012 signature,
12013 } => {
12014 result.path = abs_path.to_string_lossy().into_owned();
12015 result.signature = signature.to_vec();
12016 }
12017 }
12018 result
12019 }
12020
12021 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
12022 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
12023 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
12024 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
12025
12026 let path = if serialized_symbol.signature.is_empty() {
12027 SymbolLocation::InProject(ProjectPath {
12028 worktree_id,
12029 path: RelPath::from_proto(&serialized_symbol.path)
12030 .context("invalid symbol path")?,
12031 })
12032 } else {
12033 SymbolLocation::OutsideProject {
12034 abs_path: Path::new(&serialized_symbol.path).into(),
12035 signature: serialized_symbol
12036 .signature
12037 .try_into()
12038 .map_err(|_| anyhow!("invalid signature"))?,
12039 }
12040 };
12041
12042 let start = serialized_symbol.start.context("invalid start")?;
12043 let end = serialized_symbol.end.context("invalid end")?;
12044 Ok(CoreSymbol {
12045 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
12046 source_worktree_id,
12047 source_language_server_id: LanguageServerId::from_proto(
12048 serialized_symbol.language_server_id,
12049 ),
12050 path,
12051 name: serialized_symbol.name,
12052 range: Unclipped(PointUtf16::new(start.row, start.column))
12053 ..Unclipped(PointUtf16::new(end.row, end.column)),
12054 kind,
12055 })
12056 }
12057
12058 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12059 let mut serialized_completion = proto::Completion {
12060 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12061 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12062 new_text: completion.new_text.clone(),
12063 ..proto::Completion::default()
12064 };
12065 match &completion.source {
12066 CompletionSource::Lsp {
12067 insert_range,
12068 server_id,
12069 lsp_completion,
12070 lsp_defaults,
12071 resolved,
12072 } => {
12073 let (old_insert_start, old_insert_end) = insert_range
12074 .as_ref()
12075 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12076 .unzip();
12077
12078 serialized_completion.old_insert_start = old_insert_start;
12079 serialized_completion.old_insert_end = old_insert_end;
12080 serialized_completion.source = proto::completion::Source::Lsp as i32;
12081 serialized_completion.server_id = server_id.0 as u64;
12082 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12083 serialized_completion.lsp_defaults = lsp_defaults
12084 .as_deref()
12085 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12086 serialized_completion.resolved = *resolved;
12087 }
12088 CompletionSource::BufferWord {
12089 word_range,
12090 resolved,
12091 } => {
12092 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12093 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12094 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12095 serialized_completion.resolved = *resolved;
12096 }
12097 CompletionSource::Custom => {
12098 serialized_completion.source = proto::completion::Source::Custom as i32;
12099 serialized_completion.resolved = true;
12100 }
12101 CompletionSource::Dap { sort_text } => {
12102 serialized_completion.source = proto::completion::Source::Dap as i32;
12103 serialized_completion.sort_text = Some(sort_text.clone());
12104 }
12105 }
12106
12107 serialized_completion
12108 }
12109
12110 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12111 let old_replace_start = completion
12112 .old_replace_start
12113 .and_then(deserialize_anchor)
12114 .context("invalid old start")?;
12115 let old_replace_end = completion
12116 .old_replace_end
12117 .and_then(deserialize_anchor)
12118 .context("invalid old end")?;
12119 let insert_range = {
12120 match completion.old_insert_start.zip(completion.old_insert_end) {
12121 Some((start, end)) => {
12122 let start = deserialize_anchor(start).context("invalid insert old start")?;
12123 let end = deserialize_anchor(end).context("invalid insert old end")?;
12124 Some(start..end)
12125 }
12126 None => None,
12127 }
12128 };
12129 Ok(CoreCompletion {
12130 replace_range: old_replace_start..old_replace_end,
12131 new_text: completion.new_text,
12132 source: match proto::completion::Source::from_i32(completion.source) {
12133 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12134 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12135 insert_range,
12136 server_id: LanguageServerId::from_proto(completion.server_id),
12137 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12138 lsp_defaults: completion
12139 .lsp_defaults
12140 .as_deref()
12141 .map(serde_json::from_slice)
12142 .transpose()?,
12143 resolved: completion.resolved,
12144 },
12145 Some(proto::completion::Source::BufferWord) => {
12146 let word_range = completion
12147 .buffer_word_start
12148 .and_then(deserialize_anchor)
12149 .context("invalid buffer word start")?
12150 ..completion
12151 .buffer_word_end
12152 .and_then(deserialize_anchor)
12153 .context("invalid buffer word end")?;
12154 CompletionSource::BufferWord {
12155 word_range,
12156 resolved: completion.resolved,
12157 }
12158 }
12159 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12160 sort_text: completion
12161 .sort_text
12162 .context("expected sort text to exist")?,
12163 },
12164 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12165 },
12166 })
12167 }
12168
12169 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12170 let (kind, lsp_action) = match &action.lsp_action {
12171 LspAction::Action(code_action) => (
12172 proto::code_action::Kind::Action as i32,
12173 serde_json::to_vec(code_action).unwrap(),
12174 ),
12175 LspAction::Command(command) => (
12176 proto::code_action::Kind::Command as i32,
12177 serde_json::to_vec(command).unwrap(),
12178 ),
12179 LspAction::CodeLens(code_lens) => (
12180 proto::code_action::Kind::CodeLens as i32,
12181 serde_json::to_vec(code_lens).unwrap(),
12182 ),
12183 };
12184
12185 proto::CodeAction {
12186 server_id: action.server_id.0 as u64,
12187 start: Some(serialize_anchor(&action.range.start)),
12188 end: Some(serialize_anchor(&action.range.end)),
12189 lsp_action,
12190 kind,
12191 resolved: action.resolved,
12192 }
12193 }
12194
12195 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12196 let start = action
12197 .start
12198 .and_then(deserialize_anchor)
12199 .context("invalid start")?;
12200 let end = action
12201 .end
12202 .and_then(deserialize_anchor)
12203 .context("invalid end")?;
12204 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12205 Some(proto::code_action::Kind::Action) => {
12206 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12207 }
12208 Some(proto::code_action::Kind::Command) => {
12209 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12210 }
12211 Some(proto::code_action::Kind::CodeLens) => {
12212 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12213 }
12214 None => anyhow::bail!("Unknown action kind {}", action.kind),
12215 };
12216 Ok(CodeAction {
12217 server_id: LanguageServerId(action.server_id as usize),
12218 range: start..end,
12219 resolved: action.resolved,
12220 lsp_action,
12221 })
12222 }
12223
12224 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12225 match &formatting_result {
12226 Ok(_) => self.last_formatting_failure = None,
12227 Err(error) => {
12228 let error_string = format!("{error:#}");
12229 log::error!("Formatting failed: {error_string}");
12230 self.last_formatting_failure
12231 .replace(error_string.lines().join(" "));
12232 }
12233 }
12234 }
12235
12236 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12237 self.lsp_server_capabilities.remove(&for_server);
12238 for lsp_data in self.lsp_data.values_mut() {
12239 lsp_data.remove_server_data(for_server);
12240 }
12241 if let Some(local) = self.as_local_mut() {
12242 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12243 local
12244 .workspace_pull_diagnostics_result_ids
12245 .remove(&for_server);
12246 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12247 buffer_servers.remove(&for_server);
12248 }
12249 }
12250 }
12251
12252 pub fn result_id_for_buffer_pull(
12253 &self,
12254 server_id: LanguageServerId,
12255 buffer_id: BufferId,
12256 registration_id: &Option<SharedString>,
12257 cx: &App,
12258 ) -> Option<SharedString> {
12259 let abs_path = self
12260 .buffer_store
12261 .read(cx)
12262 .get(buffer_id)
12263 .and_then(|b| File::from_dyn(b.read(cx).file()))
12264 .map(|f| f.abs_path(cx))?;
12265 self.as_local()?
12266 .buffer_pull_diagnostics_result_ids
12267 .get(&server_id)?
12268 .get(registration_id)?
12269 .get(&abs_path)?
12270 .clone()
12271 }
12272
12273 /// Gets all result_ids for a workspace diagnostics pull request.
12274 /// 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.
12275 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12276 pub fn result_ids_for_workspace_refresh(
12277 &self,
12278 server_id: LanguageServerId,
12279 registration_id: &Option<SharedString>,
12280 ) -> HashMap<PathBuf, SharedString> {
12281 let Some(local) = self.as_local() else {
12282 return HashMap::default();
12283 };
12284 local
12285 .workspace_pull_diagnostics_result_ids
12286 .get(&server_id)
12287 .into_iter()
12288 .filter_map(|diagnostics| diagnostics.get(registration_id))
12289 .flatten()
12290 .filter_map(|(abs_path, result_id)| {
12291 let result_id = local
12292 .buffer_pull_diagnostics_result_ids
12293 .get(&server_id)
12294 .and_then(|buffer_ids_result_ids| {
12295 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12296 })
12297 .cloned()
12298 .flatten()
12299 .or_else(|| result_id.clone())?;
12300 Some((abs_path.clone(), result_id))
12301 })
12302 .collect()
12303 }
12304
12305 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12306 if let Some(LanguageServerState::Running {
12307 workspace_diagnostics_refresh_tasks,
12308 ..
12309 }) = self
12310 .as_local_mut()
12311 .and_then(|local| local.language_servers.get_mut(&server_id))
12312 {
12313 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12314 diagnostics.refresh_tx.try_send(()).ok();
12315 }
12316 }
12317 }
12318
12319 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12320 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12321 /// which requires refreshing both workspace and document diagnostics.
12322 pub fn pull_document_diagnostics_for_server(
12323 &mut self,
12324 server_id: LanguageServerId,
12325 source_buffer_id: Option<BufferId>,
12326 cx: &mut Context<Self>,
12327 ) -> Shared<Task<()>> {
12328 let Some(local) = self.as_local_mut() else {
12329 return Task::ready(()).shared();
12330 };
12331 let mut buffers_to_refresh = HashSet::default();
12332 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12333 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12334 buffers_to_refresh.insert(*buffer_id);
12335 }
12336 }
12337
12338 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12339 }
12340
12341 pub fn pull_document_diagnostics_for_buffer_edit(
12342 &mut self,
12343 buffer_id: BufferId,
12344 cx: &mut Context<Self>,
12345 ) {
12346 let Some(local) = self.as_local_mut() else {
12347 return;
12348 };
12349 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12350 else {
12351 return;
12352 };
12353 for server_id in languages_servers {
12354 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12355 }
12356 }
12357
12358 fn apply_workspace_diagnostic_report(
12359 &mut self,
12360 server_id: LanguageServerId,
12361 report: lsp::WorkspaceDiagnosticReportResult,
12362 registration_id: Option<SharedString>,
12363 cx: &mut Context<Self>,
12364 ) {
12365 let mut workspace_diagnostics =
12366 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12367 report,
12368 server_id,
12369 registration_id,
12370 );
12371 workspace_diagnostics.retain(|d| match &d.diagnostics {
12372 LspPullDiagnostics::Response {
12373 server_id,
12374 registration_id,
12375 ..
12376 } => self.diagnostic_registration_exists(*server_id, registration_id),
12377 LspPullDiagnostics::Default => false,
12378 });
12379 let mut unchanged_buffers = HashMap::default();
12380 let workspace_diagnostics_updates = workspace_diagnostics
12381 .into_iter()
12382 .filter_map(
12383 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12384 LspPullDiagnostics::Response {
12385 server_id,
12386 uri,
12387 diagnostics,
12388 registration_id,
12389 } => Some((
12390 server_id,
12391 uri,
12392 diagnostics,
12393 workspace_diagnostics.version,
12394 registration_id,
12395 )),
12396 LspPullDiagnostics::Default => None,
12397 },
12398 )
12399 .fold(
12400 HashMap::default(),
12401 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12402 let (result_id, diagnostics) = match diagnostics {
12403 PulledDiagnostics::Unchanged { result_id } => {
12404 unchanged_buffers
12405 .entry(new_registration_id.clone())
12406 .or_insert_with(HashSet::default)
12407 .insert(uri.clone());
12408 (Some(result_id), Vec::new())
12409 }
12410 PulledDiagnostics::Changed {
12411 result_id,
12412 diagnostics,
12413 } => (result_id, diagnostics),
12414 };
12415 let disk_based_sources = Cow::Owned(
12416 self.language_server_adapter_for_id(server_id)
12417 .as_ref()
12418 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12419 .unwrap_or(&[])
12420 .to_vec(),
12421 );
12422
12423 let Some(abs_path) = uri.to_file_path().ok() else {
12424 return acc;
12425 };
12426 let Some((worktree, relative_path)) =
12427 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12428 else {
12429 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12430 return acc;
12431 };
12432 let worktree_id = worktree.read(cx).id();
12433 let project_path = ProjectPath {
12434 worktree_id,
12435 path: relative_path,
12436 };
12437 if let Some(local_lsp_store) = self.as_local_mut() {
12438 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12439 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12440 }
12441 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12442 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12443 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12444 acc.entry(server_id)
12445 .or_insert_with(HashMap::default)
12446 .entry(new_registration_id.clone())
12447 .or_insert_with(Vec::new)
12448 .push(DocumentDiagnosticsUpdate {
12449 server_id,
12450 diagnostics: lsp::PublishDiagnosticsParams {
12451 uri,
12452 diagnostics,
12453 version,
12454 },
12455 result_id,
12456 disk_based_sources,
12457 registration_id: new_registration_id,
12458 });
12459 }
12460 acc
12461 },
12462 );
12463
12464 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12465 for (registration_id, diagnostic_updates) in diagnostic_updates {
12466 self.merge_lsp_diagnostics(
12467 DiagnosticSourceKind::Pulled,
12468 diagnostic_updates,
12469 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12470 DiagnosticSourceKind::Pulled => {
12471 old_diagnostic.registration_id != registration_id
12472 || unchanged_buffers
12473 .get(&old_diagnostic.registration_id)
12474 .is_some_and(|unchanged_buffers| {
12475 unchanged_buffers.contains(&document_uri)
12476 })
12477 }
12478 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12479 },
12480 cx,
12481 )
12482 .log_err();
12483 }
12484 }
12485 }
12486
12487 fn register_server_capabilities(
12488 &mut self,
12489 server_id: LanguageServerId,
12490 params: lsp::RegistrationParams,
12491 cx: &mut Context<Self>,
12492 ) -> anyhow::Result<()> {
12493 let server = self
12494 .language_server_for_id(server_id)
12495 .with_context(|| format!("no server {server_id} found"))?;
12496 for reg in params.registrations {
12497 match reg.method.as_str() {
12498 "workspace/didChangeWatchedFiles" => {
12499 if let Some(options) = reg.register_options {
12500 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12501 let caps = serde_json::from_value(options)?;
12502 local_lsp_store
12503 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12504 true
12505 } else {
12506 false
12507 };
12508 if notify {
12509 notify_server_capabilities_updated(&server, cx);
12510 }
12511 }
12512 }
12513 "workspace/didChangeConfiguration" => {
12514 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12515 }
12516 "workspace/didChangeWorkspaceFolders" => {
12517 // In this case register options is an empty object, we can ignore it
12518 let caps = lsp::WorkspaceFoldersServerCapabilities {
12519 supported: Some(true),
12520 change_notifications: Some(OneOf::Right(reg.id)),
12521 };
12522 server.update_capabilities(|capabilities| {
12523 capabilities
12524 .workspace
12525 .get_or_insert_default()
12526 .workspace_folders = Some(caps);
12527 });
12528 notify_server_capabilities_updated(&server, cx);
12529 }
12530 "workspace/symbol" => {
12531 let options = parse_register_capabilities(reg)?;
12532 server.update_capabilities(|capabilities| {
12533 capabilities.workspace_symbol_provider = Some(options);
12534 });
12535 notify_server_capabilities_updated(&server, cx);
12536 }
12537 "workspace/fileOperations" => {
12538 if let Some(options) = reg.register_options {
12539 let caps = serde_json::from_value(options)?;
12540 server.update_capabilities(|capabilities| {
12541 capabilities
12542 .workspace
12543 .get_or_insert_default()
12544 .file_operations = Some(caps);
12545 });
12546 notify_server_capabilities_updated(&server, cx);
12547 }
12548 }
12549 "workspace/executeCommand" => {
12550 if let Some(options) = reg.register_options {
12551 let options = serde_json::from_value(options)?;
12552 server.update_capabilities(|capabilities| {
12553 capabilities.execute_command_provider = Some(options);
12554 });
12555 notify_server_capabilities_updated(&server, cx);
12556 }
12557 }
12558 "textDocument/rangeFormatting" => {
12559 let options = parse_register_capabilities(reg)?;
12560 server.update_capabilities(|capabilities| {
12561 capabilities.document_range_formatting_provider = Some(options);
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 "textDocument/onTypeFormatting" => {
12566 if let Some(options) = reg
12567 .register_options
12568 .map(serde_json::from_value)
12569 .transpose()?
12570 {
12571 server.update_capabilities(|capabilities| {
12572 capabilities.document_on_type_formatting_provider = Some(options);
12573 });
12574 notify_server_capabilities_updated(&server, cx);
12575 }
12576 }
12577 "textDocument/formatting" => {
12578 let options = parse_register_capabilities(reg)?;
12579 server.update_capabilities(|capabilities| {
12580 capabilities.document_formatting_provider = Some(options);
12581 });
12582 notify_server_capabilities_updated(&server, cx);
12583 }
12584 "textDocument/rename" => {
12585 let options = parse_register_capabilities(reg)?;
12586 server.update_capabilities(|capabilities| {
12587 capabilities.rename_provider = Some(options);
12588 });
12589 notify_server_capabilities_updated(&server, cx);
12590 }
12591 "textDocument/inlayHint" => {
12592 let options = parse_register_capabilities(reg)?;
12593 server.update_capabilities(|capabilities| {
12594 capabilities.inlay_hint_provider = Some(options);
12595 });
12596 notify_server_capabilities_updated(&server, cx);
12597 }
12598 "textDocument/documentSymbol" => {
12599 let options = parse_register_capabilities(reg)?;
12600 server.update_capabilities(|capabilities| {
12601 capabilities.document_symbol_provider = Some(options);
12602 });
12603 notify_server_capabilities_updated(&server, cx);
12604 }
12605 "textDocument/codeAction" => {
12606 let options = parse_register_capabilities(reg)?;
12607 let provider = match options {
12608 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12609 OneOf::Right(caps) => caps,
12610 };
12611 server.update_capabilities(|capabilities| {
12612 capabilities.code_action_provider = Some(provider);
12613 });
12614 notify_server_capabilities_updated(&server, cx);
12615 }
12616 "textDocument/definition" => {
12617 let options = parse_register_capabilities(reg)?;
12618 server.update_capabilities(|capabilities| {
12619 capabilities.definition_provider = Some(options);
12620 });
12621 notify_server_capabilities_updated(&server, cx);
12622 }
12623 "textDocument/completion" => {
12624 if let Some(caps) = reg
12625 .register_options
12626 .map(serde_json::from_value::<CompletionOptions>)
12627 .transpose()?
12628 {
12629 server.update_capabilities(|capabilities| {
12630 capabilities.completion_provider = Some(caps.clone());
12631 });
12632
12633 if let Some(local) = self.as_local() {
12634 let mut buffers_with_language_server = Vec::new();
12635 for handle in self.buffer_store.read(cx).buffers() {
12636 let buffer_id = handle.read(cx).remote_id();
12637 if local
12638 .buffers_opened_in_servers
12639 .get(&buffer_id)
12640 .filter(|s| s.contains(&server_id))
12641 .is_some()
12642 {
12643 buffers_with_language_server.push(handle);
12644 }
12645 }
12646 let triggers = caps
12647 .trigger_characters
12648 .unwrap_or_default()
12649 .into_iter()
12650 .collect::<BTreeSet<_>>();
12651 for handle in buffers_with_language_server {
12652 let triggers = triggers.clone();
12653 let _ = handle.update(cx, move |buffer, cx| {
12654 buffer.set_completion_triggers(server_id, triggers, cx);
12655 });
12656 }
12657 }
12658 notify_server_capabilities_updated(&server, cx);
12659 }
12660 }
12661 "textDocument/hover" => {
12662 let options = parse_register_capabilities(reg)?;
12663 let provider = match options {
12664 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12665 OneOf::Right(caps) => caps,
12666 };
12667 server.update_capabilities(|capabilities| {
12668 capabilities.hover_provider = Some(provider);
12669 });
12670 notify_server_capabilities_updated(&server, cx);
12671 }
12672 "textDocument/signatureHelp" => {
12673 if let Some(caps) = reg
12674 .register_options
12675 .map(serde_json::from_value)
12676 .transpose()?
12677 {
12678 server.update_capabilities(|capabilities| {
12679 capabilities.signature_help_provider = Some(caps);
12680 });
12681 notify_server_capabilities_updated(&server, cx);
12682 }
12683 }
12684 "textDocument/didChange" => {
12685 if let Some(sync_kind) = reg
12686 .register_options
12687 .and_then(|opts| opts.get("syncKind").cloned())
12688 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12689 .transpose()?
12690 {
12691 server.update_capabilities(|capabilities| {
12692 let mut sync_options =
12693 Self::take_text_document_sync_options(capabilities);
12694 sync_options.change = Some(sync_kind);
12695 capabilities.text_document_sync =
12696 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12697 });
12698 notify_server_capabilities_updated(&server, cx);
12699 }
12700 }
12701 "textDocument/didSave" => {
12702 if let Some(include_text) = reg
12703 .register_options
12704 .map(|opts| {
12705 let transpose = opts
12706 .get("includeText")
12707 .cloned()
12708 .map(serde_json::from_value::<Option<bool>>)
12709 .transpose();
12710 match transpose {
12711 Ok(value) => Ok(value.flatten()),
12712 Err(e) => Err(e),
12713 }
12714 })
12715 .transpose()?
12716 {
12717 server.update_capabilities(|capabilities| {
12718 let mut sync_options =
12719 Self::take_text_document_sync_options(capabilities);
12720 sync_options.save =
12721 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12722 include_text,
12723 }));
12724 capabilities.text_document_sync =
12725 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12726 });
12727 notify_server_capabilities_updated(&server, cx);
12728 }
12729 }
12730 "textDocument/codeLens" => {
12731 if let Some(caps) = reg
12732 .register_options
12733 .map(serde_json::from_value)
12734 .transpose()?
12735 {
12736 server.update_capabilities(|capabilities| {
12737 capabilities.code_lens_provider = Some(caps);
12738 });
12739 notify_server_capabilities_updated(&server, cx);
12740 }
12741 }
12742 "textDocument/diagnostic" => {
12743 if let Some(caps) = reg
12744 .register_options
12745 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12746 .transpose()?
12747 {
12748 let local = self
12749 .as_local_mut()
12750 .context("Expected LSP Store to be local")?;
12751 let state = local
12752 .language_servers
12753 .get_mut(&server_id)
12754 .context("Could not obtain Language Servers state")?;
12755 local
12756 .language_server_dynamic_registrations
12757 .entry(server_id)
12758 .or_default()
12759 .diagnostics
12760 .insert(Some(reg.id.clone()), caps.clone());
12761
12762 let supports_workspace_diagnostics =
12763 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12764 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12765 diagnostic_options.workspace_diagnostics
12766 }
12767 DiagnosticServerCapabilities::RegistrationOptions(
12768 diagnostic_registration_options,
12769 ) => {
12770 diagnostic_registration_options
12771 .diagnostic_options
12772 .workspace_diagnostics
12773 }
12774 };
12775
12776 if supports_workspace_diagnostics(&caps) {
12777 if let LanguageServerState::Running {
12778 workspace_diagnostics_refresh_tasks,
12779 ..
12780 } = state
12781 && let Some(task) = lsp_workspace_diagnostics_refresh(
12782 Some(reg.id.clone()),
12783 caps.clone(),
12784 server.clone(),
12785 cx,
12786 )
12787 {
12788 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12789 }
12790 }
12791
12792 server.update_capabilities(|capabilities| {
12793 capabilities.diagnostic_provider = Some(caps);
12794 });
12795
12796 notify_server_capabilities_updated(&server, cx);
12797
12798 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12799 }
12800 }
12801 "textDocument/documentColor" => {
12802 let options = parse_register_capabilities(reg)?;
12803 let provider = match options {
12804 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12805 OneOf::Right(caps) => caps,
12806 };
12807 server.update_capabilities(|capabilities| {
12808 capabilities.color_provider = Some(provider);
12809 });
12810 notify_server_capabilities_updated(&server, cx);
12811 }
12812 _ => log::warn!("unhandled capability registration: {reg:?}"),
12813 }
12814 }
12815
12816 Ok(())
12817 }
12818
12819 fn unregister_server_capabilities(
12820 &mut self,
12821 server_id: LanguageServerId,
12822 params: lsp::UnregistrationParams,
12823 cx: &mut Context<Self>,
12824 ) -> anyhow::Result<()> {
12825 let server = self
12826 .language_server_for_id(server_id)
12827 .with_context(|| format!("no server {server_id} found"))?;
12828 for unreg in params.unregisterations.iter() {
12829 match unreg.method.as_str() {
12830 "workspace/didChangeWatchedFiles" => {
12831 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12832 local_lsp_store
12833 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12834 true
12835 } else {
12836 false
12837 };
12838 if notify {
12839 notify_server_capabilities_updated(&server, cx);
12840 }
12841 }
12842 "workspace/didChangeConfiguration" => {
12843 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12844 }
12845 "workspace/didChangeWorkspaceFolders" => {
12846 server.update_capabilities(|capabilities| {
12847 capabilities
12848 .workspace
12849 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12850 workspace_folders: None,
12851 file_operations: None,
12852 })
12853 .workspace_folders = None;
12854 });
12855 notify_server_capabilities_updated(&server, cx);
12856 }
12857 "workspace/symbol" => {
12858 server.update_capabilities(|capabilities| {
12859 capabilities.workspace_symbol_provider = None
12860 });
12861 notify_server_capabilities_updated(&server, cx);
12862 }
12863 "workspace/fileOperations" => {
12864 server.update_capabilities(|capabilities| {
12865 capabilities
12866 .workspace
12867 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12868 workspace_folders: None,
12869 file_operations: None,
12870 })
12871 .file_operations = None;
12872 });
12873 notify_server_capabilities_updated(&server, cx);
12874 }
12875 "workspace/executeCommand" => {
12876 server.update_capabilities(|capabilities| {
12877 capabilities.execute_command_provider = None;
12878 });
12879 notify_server_capabilities_updated(&server, cx);
12880 }
12881 "textDocument/rangeFormatting" => {
12882 server.update_capabilities(|capabilities| {
12883 capabilities.document_range_formatting_provider = None
12884 });
12885 notify_server_capabilities_updated(&server, cx);
12886 }
12887 "textDocument/onTypeFormatting" => {
12888 server.update_capabilities(|capabilities| {
12889 capabilities.document_on_type_formatting_provider = None;
12890 });
12891 notify_server_capabilities_updated(&server, cx);
12892 }
12893 "textDocument/formatting" => {
12894 server.update_capabilities(|capabilities| {
12895 capabilities.document_formatting_provider = None;
12896 });
12897 notify_server_capabilities_updated(&server, cx);
12898 }
12899 "textDocument/rename" => {
12900 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12901 notify_server_capabilities_updated(&server, cx);
12902 }
12903 "textDocument/codeAction" => {
12904 server.update_capabilities(|capabilities| {
12905 capabilities.code_action_provider = None;
12906 });
12907 notify_server_capabilities_updated(&server, cx);
12908 }
12909 "textDocument/definition" => {
12910 server.update_capabilities(|capabilities| {
12911 capabilities.definition_provider = None;
12912 });
12913 notify_server_capabilities_updated(&server, cx);
12914 }
12915 "textDocument/completion" => {
12916 server.update_capabilities(|capabilities| {
12917 capabilities.completion_provider = None;
12918 });
12919 notify_server_capabilities_updated(&server, cx);
12920 }
12921 "textDocument/hover" => {
12922 server.update_capabilities(|capabilities| {
12923 capabilities.hover_provider = None;
12924 });
12925 notify_server_capabilities_updated(&server, cx);
12926 }
12927 "textDocument/signatureHelp" => {
12928 server.update_capabilities(|capabilities| {
12929 capabilities.signature_help_provider = None;
12930 });
12931 notify_server_capabilities_updated(&server, cx);
12932 }
12933 "textDocument/didChange" => {
12934 server.update_capabilities(|capabilities| {
12935 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12936 sync_options.change = None;
12937 capabilities.text_document_sync =
12938 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12939 });
12940 notify_server_capabilities_updated(&server, cx);
12941 }
12942 "textDocument/didSave" => {
12943 server.update_capabilities(|capabilities| {
12944 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12945 sync_options.save = None;
12946 capabilities.text_document_sync =
12947 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12948 });
12949 notify_server_capabilities_updated(&server, cx);
12950 }
12951 "textDocument/codeLens" => {
12952 server.update_capabilities(|capabilities| {
12953 capabilities.code_lens_provider = None;
12954 });
12955 notify_server_capabilities_updated(&server, cx);
12956 }
12957 "textDocument/diagnostic" => {
12958 let local = self
12959 .as_local_mut()
12960 .context("Expected LSP Store to be local")?;
12961
12962 let state = local
12963 .language_servers
12964 .get_mut(&server_id)
12965 .context("Could not obtain Language Servers state")?;
12966 let registrations = local
12967 .language_server_dynamic_registrations
12968 .get_mut(&server_id)
12969 .with_context(|| {
12970 format!("Expected dynamic registration to exist for server {server_id}")
12971 })?;
12972 registrations.diagnostics
12973 .remove(&Some(unreg.id.clone()))
12974 .with_context(|| format!(
12975 "Attempted to unregister non-existent diagnostic registration with ID {}",
12976 unreg.id)
12977 )?;
12978 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12979
12980 if let LanguageServerState::Running {
12981 workspace_diagnostics_refresh_tasks,
12982 ..
12983 } = state
12984 {
12985 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12986 }
12987
12988 self.clear_unregistered_diagnostics(
12989 server_id,
12990 SharedString::from(unreg.id.clone()),
12991 cx,
12992 )?;
12993
12994 if removed_last_diagnostic_provider {
12995 server.update_capabilities(|capabilities| {
12996 debug_assert!(capabilities.diagnostic_provider.is_some());
12997 capabilities.diagnostic_provider = None;
12998 });
12999 }
13000
13001 notify_server_capabilities_updated(&server, cx);
13002 }
13003 "textDocument/documentColor" => {
13004 server.update_capabilities(|capabilities| {
13005 capabilities.color_provider = None;
13006 });
13007 notify_server_capabilities_updated(&server, cx);
13008 }
13009 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
13010 }
13011 }
13012
13013 Ok(())
13014 }
13015
13016 fn clear_unregistered_diagnostics(
13017 &mut self,
13018 server_id: LanguageServerId,
13019 cleared_registration_id: SharedString,
13020 cx: &mut Context<Self>,
13021 ) -> anyhow::Result<()> {
13022 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
13023
13024 self.buffer_store.update(cx, |buffer_store, cx| {
13025 for buffer_handle in buffer_store.buffers() {
13026 let buffer = buffer_handle.read(cx);
13027 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
13028 let Some(abs_path) = abs_path else {
13029 continue;
13030 };
13031 affected_abs_paths.insert(abs_path);
13032 }
13033 });
13034
13035 let local = self.as_local().context("Expected LSP Store to be local")?;
13036 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13037 let Some(worktree) = self
13038 .worktree_store
13039 .read(cx)
13040 .worktree_for_id(*worktree_id, cx)
13041 else {
13042 continue;
13043 };
13044
13045 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13046 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13047 let has_matching_registration =
13048 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13049 entry.diagnostic.registration_id.as_ref()
13050 == Some(&cleared_registration_id)
13051 });
13052 if has_matching_registration {
13053 let abs_path = worktree.read(cx).absolutize(rel_path);
13054 affected_abs_paths.insert(abs_path);
13055 }
13056 }
13057 }
13058 }
13059
13060 if affected_abs_paths.is_empty() {
13061 return Ok(());
13062 }
13063
13064 // Send a fake diagnostic update which clears the state for the registration ID
13065 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13066 affected_abs_paths
13067 .into_iter()
13068 .map(|abs_path| DocumentDiagnosticsUpdate {
13069 diagnostics: DocumentDiagnostics {
13070 diagnostics: Vec::new(),
13071 document_abs_path: abs_path,
13072 version: None,
13073 },
13074 result_id: None,
13075 registration_id: Some(cleared_registration_id.clone()),
13076 server_id,
13077 disk_based_sources: Cow::Borrowed(&[]),
13078 })
13079 .collect();
13080
13081 let merge_registration_id = cleared_registration_id.clone();
13082 self.merge_diagnostic_entries(
13083 clears,
13084 move |_, diagnostic, _| {
13085 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13086 diagnostic.registration_id != Some(merge_registration_id.clone())
13087 } else {
13088 true
13089 }
13090 },
13091 cx,
13092 )?;
13093
13094 Ok(())
13095 }
13096
13097 async fn deduplicate_range_based_lsp_requests<T>(
13098 lsp_store: &Entity<Self>,
13099 server_id: Option<LanguageServerId>,
13100 lsp_request_id: LspRequestId,
13101 proto_request: &T::ProtoRequest,
13102 range: Range<Anchor>,
13103 cx: &mut AsyncApp,
13104 ) -> Result<()>
13105 where
13106 T: LspCommand,
13107 T::ProtoRequest: proto::LspRequestMessage,
13108 {
13109 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13110 let version = deserialize_version(proto_request.buffer_version());
13111 let buffer = lsp_store.update(cx, |this, cx| {
13112 this.buffer_store.read(cx).get_existing(buffer_id)
13113 })?;
13114 buffer
13115 .update(cx, |buffer, _| buffer.wait_for_version(version))
13116 .await?;
13117 lsp_store.update(cx, |lsp_store, cx| {
13118 let buffer_snapshot = buffer.read(cx).snapshot();
13119 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13120 let chunks_queried_for = lsp_data
13121 .inlay_hints
13122 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13123 .collect::<Vec<_>>();
13124 match chunks_queried_for.as_slice() {
13125 &[chunk] => {
13126 let key = LspKey {
13127 request_type: TypeId::of::<T>(),
13128 server_queried: server_id,
13129 };
13130 let previous_request = lsp_data
13131 .chunk_lsp_requests
13132 .entry(key)
13133 .or_default()
13134 .insert(chunk, lsp_request_id);
13135 if let Some((previous_request, running_requests)) =
13136 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13137 {
13138 running_requests.remove(&previous_request);
13139 }
13140 }
13141 _ambiguous_chunks => {
13142 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13143 // there, a buffer version-based check will be performed and outdated requests discarded.
13144 }
13145 }
13146 anyhow::Ok(())
13147 })?;
13148
13149 Ok(())
13150 }
13151
13152 async fn query_lsp_locally<T>(
13153 lsp_store: Entity<Self>,
13154 for_server_id: Option<LanguageServerId>,
13155 sender_id: proto::PeerId,
13156 lsp_request_id: LspRequestId,
13157 proto_request: T::ProtoRequest,
13158 position: Option<Anchor>,
13159 cx: &mut AsyncApp,
13160 ) -> Result<()>
13161 where
13162 T: LspCommand + Clone,
13163 T::ProtoRequest: proto::LspRequestMessage,
13164 <T::ProtoRequest as proto::RequestMessage>::Response:
13165 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13166 {
13167 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13168 let version = deserialize_version(proto_request.buffer_version());
13169 let buffer = lsp_store.update(cx, |this, cx| {
13170 this.buffer_store.read(cx).get_existing(buffer_id)
13171 })?;
13172 buffer
13173 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13174 .await?;
13175 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13176 let request =
13177 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13178 let key = LspKey {
13179 request_type: TypeId::of::<T>(),
13180 server_queried: for_server_id,
13181 };
13182 lsp_store.update(cx, |lsp_store, cx| {
13183 let request_task = match for_server_id {
13184 Some(server_id) => {
13185 let server_task = lsp_store.request_lsp(
13186 buffer.clone(),
13187 LanguageServerToQuery::Other(server_id),
13188 request.clone(),
13189 cx,
13190 );
13191 cx.background_spawn(async move {
13192 let mut responses = Vec::new();
13193 match server_task.await {
13194 Ok(response) => responses.push((server_id, response)),
13195 // rust-analyzer likes to error with this when its still loading up
13196 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13197 Err(e) => log::error!(
13198 "Error handling response for request {request:?}: {e:#}"
13199 ),
13200 }
13201 responses
13202 })
13203 }
13204 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13205 };
13206 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13207 if T::ProtoRequest::stop_previous_requests() {
13208 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13209 lsp_requests.clear();
13210 }
13211 }
13212 lsp_data.lsp_requests.entry(key).or_default().insert(
13213 lsp_request_id,
13214 cx.spawn(async move |lsp_store, cx| {
13215 let response = request_task.await;
13216 lsp_store
13217 .update(cx, |lsp_store, cx| {
13218 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13219 {
13220 let response = response
13221 .into_iter()
13222 .map(|(server_id, response)| {
13223 (
13224 server_id.to_proto(),
13225 T::response_to_proto(
13226 response,
13227 lsp_store,
13228 sender_id,
13229 &buffer_version,
13230 cx,
13231 )
13232 .into(),
13233 )
13234 })
13235 .collect::<HashMap<_, _>>();
13236 match client.send_lsp_response::<T::ProtoRequest>(
13237 project_id,
13238 lsp_request_id,
13239 response,
13240 ) {
13241 Ok(()) => {}
13242 Err(e) => {
13243 log::error!("Failed to send LSP response: {e:#}",)
13244 }
13245 }
13246 }
13247 })
13248 .ok();
13249 }),
13250 );
13251 });
13252 Ok(())
13253 }
13254
13255 fn take_text_document_sync_options(
13256 capabilities: &mut lsp::ServerCapabilities,
13257 ) -> lsp::TextDocumentSyncOptions {
13258 match capabilities.text_document_sync.take() {
13259 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13260 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13261 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13262 sync_options.change = Some(sync_kind);
13263 sync_options
13264 }
13265 None => lsp::TextDocumentSyncOptions::default(),
13266 }
13267 }
13268
13269 #[cfg(any(test, feature = "test-support"))]
13270 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13271 Some(
13272 self.lsp_data
13273 .get_mut(&buffer_id)?
13274 .code_lens
13275 .take()?
13276 .update
13277 .take()?
13278 .1,
13279 )
13280 }
13281
13282 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13283 self.downstream_client.clone()
13284 }
13285
13286 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13287 self.worktree_store.clone()
13288 }
13289
13290 /// Gets what's stored in the LSP data for the given buffer.
13291 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13292 self.lsp_data.get_mut(&buffer_id)
13293 }
13294
13295 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13296 /// new [`BufferLspData`] will be created to replace the previous state.
13297 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13298 let (buffer_id, buffer_version) =
13299 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13300 let lsp_data = self
13301 .lsp_data
13302 .entry(buffer_id)
13303 .or_insert_with(|| BufferLspData::new(buffer, cx));
13304 if buffer_version.changed_since(&lsp_data.buffer_version) {
13305 *lsp_data = BufferLspData::new(buffer, cx);
13306 }
13307 lsp_data
13308 }
13309}
13310
13311// Registration with registerOptions as null, should fallback to true.
13312// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13313fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13314 reg: lsp::Registration,
13315) -> Result<OneOf<bool, T>> {
13316 Ok(match reg.register_options {
13317 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13318 None => OneOf::Left(true),
13319 })
13320}
13321
13322fn subscribe_to_binary_statuses(
13323 languages: &Arc<LanguageRegistry>,
13324 cx: &mut Context<'_, LspStore>,
13325) -> Task<()> {
13326 let mut server_statuses = languages.language_server_binary_statuses();
13327 cx.spawn(async move |lsp_store, cx| {
13328 while let Some((server_name, binary_status)) = server_statuses.next().await {
13329 if lsp_store
13330 .update(cx, |_, cx| {
13331 let mut message = None;
13332 let binary_status = match binary_status {
13333 BinaryStatus::None => proto::ServerBinaryStatus::None,
13334 BinaryStatus::CheckingForUpdate => {
13335 proto::ServerBinaryStatus::CheckingForUpdate
13336 }
13337 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13338 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13339 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13340 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13341 BinaryStatus::Failed { error } => {
13342 message = Some(error);
13343 proto::ServerBinaryStatus::Failed
13344 }
13345 };
13346 cx.emit(LspStoreEvent::LanguageServerUpdate {
13347 // Binary updates are about the binary that might not have any language server id at that point.
13348 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13349 language_server_id: LanguageServerId(0),
13350 name: Some(server_name),
13351 message: proto::update_language_server::Variant::StatusUpdate(
13352 proto::StatusUpdate {
13353 message,
13354 status: Some(proto::status_update::Status::Binary(
13355 binary_status as i32,
13356 )),
13357 },
13358 ),
13359 });
13360 })
13361 .is_err()
13362 {
13363 break;
13364 }
13365 }
13366 })
13367}
13368
13369fn lsp_workspace_diagnostics_refresh(
13370 registration_id: Option<String>,
13371 options: DiagnosticServerCapabilities,
13372 server: Arc<LanguageServer>,
13373 cx: &mut Context<'_, LspStore>,
13374) -> Option<WorkspaceRefreshTask> {
13375 let identifier = workspace_diagnostic_identifier(&options)?;
13376 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13377
13378 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13379 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13380 refresh_tx.try_send(()).ok();
13381
13382 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13383 let mut attempts = 0;
13384 let max_attempts = 50;
13385 let mut requests = 0;
13386
13387 loop {
13388 let Some(()) = refresh_rx.recv().await else {
13389 return;
13390 };
13391
13392 'request: loop {
13393 requests += 1;
13394 if attempts > max_attempts {
13395 log::error!(
13396 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13397 );
13398 return;
13399 }
13400 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13401 cx.background_executor()
13402 .timer(Duration::from_millis(backoff_millis))
13403 .await;
13404 attempts += 1;
13405
13406 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13407 lsp_store
13408 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13409 .into_iter()
13410 .filter_map(|(abs_path, result_id)| {
13411 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13412 Some(lsp::PreviousResultId {
13413 uri,
13414 value: result_id.to_string(),
13415 })
13416 })
13417 .collect()
13418 }) else {
13419 return;
13420 };
13421
13422 let token = if let Some(registration_id) = ®istration_id {
13423 format!(
13424 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13425 server.server_id(),
13426 )
13427 } else {
13428 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13429 };
13430
13431 progress_rx.try_recv().ok();
13432 let timer =
13433 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13434 let progress = pin!(progress_rx.recv().fuse());
13435 let response_result = server
13436 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13437 lsp::WorkspaceDiagnosticParams {
13438 previous_result_ids,
13439 identifier: identifier.clone(),
13440 work_done_progress_params: Default::default(),
13441 partial_result_params: lsp::PartialResultParams {
13442 partial_result_token: Some(lsp::ProgressToken::String(token)),
13443 },
13444 },
13445 select(timer, progress).then(|either| match either {
13446 Either::Left((message, ..)) => ready(message).left_future(),
13447 Either::Right(..) => pending::<String>().right_future(),
13448 }),
13449 )
13450 .await;
13451
13452 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13453 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13454 match response_result {
13455 ConnectionResult::Timeout => {
13456 log::error!("Timeout during workspace diagnostics pull");
13457 continue 'request;
13458 }
13459 ConnectionResult::ConnectionReset => {
13460 log::error!("Server closed a workspace diagnostics pull request");
13461 continue 'request;
13462 }
13463 ConnectionResult::Result(Err(e)) => {
13464 log::error!("Error during workspace diagnostics pull: {e:#}");
13465 break 'request;
13466 }
13467 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13468 attempts = 0;
13469 if lsp_store
13470 .update(cx, |lsp_store, cx| {
13471 lsp_store.apply_workspace_diagnostic_report(
13472 server.server_id(),
13473 pulled_diagnostics,
13474 registration_id_shared.clone(),
13475 cx,
13476 )
13477 })
13478 .is_err()
13479 {
13480 return;
13481 }
13482 break 'request;
13483 }
13484 }
13485 }
13486 }
13487 });
13488
13489 Some(WorkspaceRefreshTask {
13490 refresh_tx,
13491 progress_tx,
13492 task: workspace_query_language_server,
13493 })
13494}
13495
13496fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13497 match &options {
13498 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13499 diagnostic_options.identifier.clone()
13500 }
13501 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13502 let diagnostic_options = ®istration_options.diagnostic_options;
13503 diagnostic_options.identifier.clone()
13504 }
13505 }
13506}
13507
13508fn workspace_diagnostic_identifier(
13509 options: &DiagnosticServerCapabilities,
13510) -> Option<Option<String>> {
13511 match &options {
13512 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13513 if !diagnostic_options.workspace_diagnostics {
13514 return None;
13515 }
13516 Some(diagnostic_options.identifier.clone())
13517 }
13518 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13519 let diagnostic_options = ®istration_options.diagnostic_options;
13520 if !diagnostic_options.workspace_diagnostics {
13521 return None;
13522 }
13523 Some(diagnostic_options.identifier.clone())
13524 }
13525 }
13526}
13527
13528fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13529 let CompletionSource::BufferWord {
13530 word_range,
13531 resolved,
13532 } = &mut completion.source
13533 else {
13534 return;
13535 };
13536 if *resolved {
13537 return;
13538 }
13539
13540 if completion.new_text
13541 != snapshot
13542 .text_for_range(word_range.clone())
13543 .collect::<String>()
13544 {
13545 return;
13546 }
13547
13548 let mut offset = 0;
13549 for chunk in snapshot.chunks(word_range.clone(), true) {
13550 let end_offset = offset + chunk.text.len();
13551 if let Some(highlight_id) = chunk.syntax_highlight_id {
13552 completion
13553 .label
13554 .runs
13555 .push((offset..end_offset, highlight_id));
13556 }
13557 offset = end_offset;
13558 }
13559 *resolved = true;
13560}
13561
13562impl EventEmitter<LspStoreEvent> for LspStore {}
13563
13564fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13565 hover
13566 .contents
13567 .retain(|hover_block| !hover_block.text.trim().is_empty());
13568 if hover.contents.is_empty() {
13569 None
13570 } else {
13571 Some(hover)
13572 }
13573}
13574
13575async fn populate_labels_for_completions(
13576 new_completions: Vec<CoreCompletion>,
13577 language: Option<Arc<Language>>,
13578 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13579) -> Vec<Completion> {
13580 let lsp_completions = new_completions
13581 .iter()
13582 .filter_map(|new_completion| {
13583 new_completion
13584 .source
13585 .lsp_completion(true)
13586 .map(|lsp_completion| lsp_completion.into_owned())
13587 })
13588 .collect::<Vec<_>>();
13589
13590 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13591 lsp_adapter
13592 .labels_for_completions(&lsp_completions, language)
13593 .await
13594 .log_err()
13595 .unwrap_or_default()
13596 } else {
13597 Vec::new()
13598 }
13599 .into_iter()
13600 .fuse();
13601
13602 let mut completions = Vec::new();
13603 for completion in new_completions {
13604 match completion.source.lsp_completion(true) {
13605 Some(lsp_completion) => {
13606 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13607
13608 let mut label = labels.next().flatten().unwrap_or_else(|| {
13609 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13610 });
13611 ensure_uniform_list_compatible_label(&mut label);
13612 completions.push(Completion {
13613 label,
13614 documentation,
13615 replace_range: completion.replace_range,
13616 new_text: completion.new_text,
13617 insert_text_mode: lsp_completion.insert_text_mode,
13618 source: completion.source,
13619 icon_path: None,
13620 confirm: None,
13621 match_start: None,
13622 snippet_deduplication_key: None,
13623 });
13624 }
13625 None => {
13626 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13627 ensure_uniform_list_compatible_label(&mut label);
13628 completions.push(Completion {
13629 label,
13630 documentation: None,
13631 replace_range: completion.replace_range,
13632 new_text: completion.new_text,
13633 source: completion.source,
13634 insert_text_mode: None,
13635 icon_path: None,
13636 confirm: None,
13637 match_start: None,
13638 snippet_deduplication_key: None,
13639 });
13640 }
13641 }
13642 }
13643 completions
13644}
13645
13646#[derive(Debug)]
13647pub enum LanguageServerToQuery {
13648 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13649 FirstCapable,
13650 /// Query a specific language server.
13651 Other(LanguageServerId),
13652}
13653
13654#[derive(Default)]
13655struct RenamePathsWatchedForServer {
13656 did_rename: Vec<RenameActionPredicate>,
13657 will_rename: Vec<RenameActionPredicate>,
13658}
13659
13660impl RenamePathsWatchedForServer {
13661 fn with_did_rename_patterns(
13662 mut self,
13663 did_rename: Option<&FileOperationRegistrationOptions>,
13664 ) -> Self {
13665 if let Some(did_rename) = did_rename {
13666 self.did_rename = did_rename
13667 .filters
13668 .iter()
13669 .filter_map(|filter| filter.try_into().log_err())
13670 .collect();
13671 }
13672 self
13673 }
13674 fn with_will_rename_patterns(
13675 mut self,
13676 will_rename: Option<&FileOperationRegistrationOptions>,
13677 ) -> Self {
13678 if let Some(will_rename) = will_rename {
13679 self.will_rename = will_rename
13680 .filters
13681 .iter()
13682 .filter_map(|filter| filter.try_into().log_err())
13683 .collect();
13684 }
13685 self
13686 }
13687
13688 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13689 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13690 }
13691 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13692 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13693 }
13694}
13695
13696impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13697 type Error = globset::Error;
13698 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13699 Ok(Self {
13700 kind: ops.pattern.matches.clone(),
13701 glob: GlobBuilder::new(&ops.pattern.glob)
13702 .case_insensitive(
13703 ops.pattern
13704 .options
13705 .as_ref()
13706 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13707 )
13708 .build()?
13709 .compile_matcher(),
13710 })
13711 }
13712}
13713struct RenameActionPredicate {
13714 glob: GlobMatcher,
13715 kind: Option<FileOperationPatternKind>,
13716}
13717
13718impl RenameActionPredicate {
13719 // Returns true if language server should be notified
13720 fn eval(&self, path: &str, is_dir: bool) -> bool {
13721 self.kind.as_ref().is_none_or(|kind| {
13722 let expected_kind = if is_dir {
13723 FileOperationPatternKind::Folder
13724 } else {
13725 FileOperationPatternKind::File
13726 };
13727 kind == &expected_kind
13728 }) && self.glob.is_match(path)
13729 }
13730}
13731
13732#[derive(Default)]
13733struct LanguageServerWatchedPaths {
13734 worktree_paths: HashMap<WorktreeId, GlobSet>,
13735 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13736}
13737
13738#[derive(Default)]
13739struct LanguageServerWatchedPathsBuilder {
13740 worktree_paths: HashMap<WorktreeId, GlobSet>,
13741 abs_paths: HashMap<Arc<Path>, GlobSet>,
13742}
13743
13744impl LanguageServerWatchedPathsBuilder {
13745 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13746 self.worktree_paths.insert(worktree_id, glob_set);
13747 }
13748 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13749 self.abs_paths.insert(path, glob_set);
13750 }
13751 fn build(
13752 self,
13753 fs: Arc<dyn Fs>,
13754 language_server_id: LanguageServerId,
13755 cx: &mut Context<LspStore>,
13756 ) -> LanguageServerWatchedPaths {
13757 let lsp_store = cx.weak_entity();
13758
13759 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13760 let abs_paths = self
13761 .abs_paths
13762 .into_iter()
13763 .map(|(abs_path, globset)| {
13764 let task = cx.spawn({
13765 let abs_path = abs_path.clone();
13766 let fs = fs.clone();
13767
13768 let lsp_store = lsp_store.clone();
13769 async move |_, cx| {
13770 maybe!(async move {
13771 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13772 while let Some(update) = push_updates.0.next().await {
13773 let action = lsp_store
13774 .update(cx, |this, _| {
13775 let Some(local) = this.as_local() else {
13776 return ControlFlow::Break(());
13777 };
13778 let Some(watcher) = local
13779 .language_server_watched_paths
13780 .get(&language_server_id)
13781 else {
13782 return ControlFlow::Break(());
13783 };
13784 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13785 "Watched abs path is not registered with a watcher",
13786 );
13787 let matching_entries = update
13788 .into_iter()
13789 .filter(|event| globs.is_match(&event.path))
13790 .collect::<Vec<_>>();
13791 this.lsp_notify_abs_paths_changed(
13792 language_server_id,
13793 matching_entries,
13794 );
13795 ControlFlow::Continue(())
13796 })
13797 .ok()?;
13798
13799 if action.is_break() {
13800 break;
13801 }
13802 }
13803 Some(())
13804 })
13805 .await;
13806 }
13807 });
13808 (abs_path, (globset, task))
13809 })
13810 .collect();
13811 LanguageServerWatchedPaths {
13812 worktree_paths: self.worktree_paths,
13813 abs_paths,
13814 }
13815 }
13816}
13817
13818struct LspBufferSnapshot {
13819 version: i32,
13820 snapshot: TextBufferSnapshot,
13821}
13822
13823/// A prompt requested by LSP server.
13824#[derive(Clone, Debug)]
13825pub struct LanguageServerPromptRequest {
13826 pub id: usize,
13827 pub level: PromptLevel,
13828 pub message: String,
13829 pub actions: Vec<MessageActionItem>,
13830 pub lsp_name: String,
13831 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13832}
13833
13834impl LanguageServerPromptRequest {
13835 pub fn new(
13836 level: PromptLevel,
13837 message: String,
13838 actions: Vec<MessageActionItem>,
13839 lsp_name: String,
13840 response_channel: smol::channel::Sender<MessageActionItem>,
13841 ) -> Self {
13842 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13843 LanguageServerPromptRequest {
13844 id,
13845 level,
13846 message,
13847 actions,
13848 lsp_name,
13849 response_channel,
13850 }
13851 }
13852 pub async fn respond(self, index: usize) -> Option<()> {
13853 if let Some(response) = self.actions.into_iter().nth(index) {
13854 self.response_channel.send(response).await.ok()
13855 } else {
13856 None
13857 }
13858 }
13859
13860 #[cfg(any(test, feature = "test-support"))]
13861 pub fn test(
13862 level: PromptLevel,
13863 message: String,
13864 actions: Vec<MessageActionItem>,
13865 lsp_name: String,
13866 ) -> Self {
13867 let (tx, _rx) = smol::channel::unbounded();
13868 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13869 }
13870}
13871impl PartialEq for LanguageServerPromptRequest {
13872 fn eq(&self, other: &Self) -> bool {
13873 self.message == other.message && self.actions == other.actions
13874 }
13875}
13876
13877#[derive(Clone, Debug, PartialEq)]
13878pub enum LanguageServerLogType {
13879 Log(MessageType),
13880 Trace { verbose_info: Option<String> },
13881 Rpc { received: bool },
13882}
13883
13884impl LanguageServerLogType {
13885 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13886 match self {
13887 Self::Log(log_type) => {
13888 use proto::log_message::LogLevel;
13889 let level = match *log_type {
13890 MessageType::ERROR => LogLevel::Error,
13891 MessageType::WARNING => LogLevel::Warning,
13892 MessageType::INFO => LogLevel::Info,
13893 MessageType::LOG => LogLevel::Log,
13894 other => {
13895 log::warn!("Unknown lsp log message type: {other:?}");
13896 LogLevel::Log
13897 }
13898 };
13899 proto::language_server_log::LogType::Log(proto::LogMessage {
13900 level: level as i32,
13901 })
13902 }
13903 Self::Trace { verbose_info } => {
13904 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13905 verbose_info: verbose_info.to_owned(),
13906 })
13907 }
13908 Self::Rpc { received } => {
13909 let kind = if *received {
13910 proto::rpc_message::Kind::Received
13911 } else {
13912 proto::rpc_message::Kind::Sent
13913 };
13914 let kind = kind as i32;
13915 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13916 }
13917 }
13918 }
13919
13920 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13921 use proto::log_message::LogLevel;
13922 use proto::rpc_message;
13923 match log_type {
13924 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13925 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13926 LogLevel::Error => MessageType::ERROR,
13927 LogLevel::Warning => MessageType::WARNING,
13928 LogLevel::Info => MessageType::INFO,
13929 LogLevel::Log => MessageType::LOG,
13930 },
13931 ),
13932 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13933 verbose_info: trace_message.verbose_info,
13934 },
13935 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13936 received: match rpc_message::Kind::from_i32(message.kind)
13937 .unwrap_or(rpc_message::Kind::Received)
13938 {
13939 rpc_message::Kind::Received => true,
13940 rpc_message::Kind::Sent => false,
13941 },
13942 },
13943 }
13944 }
13945}
13946
13947pub struct WorkspaceRefreshTask {
13948 refresh_tx: mpsc::Sender<()>,
13949 progress_tx: mpsc::Sender<()>,
13950 #[allow(dead_code)]
13951 task: Task<()>,
13952}
13953
13954pub enum LanguageServerState {
13955 Starting {
13956 startup: Task<Option<Arc<LanguageServer>>>,
13957 /// List of language servers that will be added to the workspace once it's initialization completes.
13958 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13959 },
13960
13961 Running {
13962 adapter: Arc<CachedLspAdapter>,
13963 server: Arc<LanguageServer>,
13964 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13965 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13966 },
13967}
13968
13969impl LanguageServerState {
13970 fn add_workspace_folder(&self, uri: Uri) {
13971 match self {
13972 LanguageServerState::Starting {
13973 pending_workspace_folders,
13974 ..
13975 } => {
13976 pending_workspace_folders.lock().insert(uri);
13977 }
13978 LanguageServerState::Running { server, .. } => {
13979 server.add_workspace_folder(uri);
13980 }
13981 }
13982 }
13983 fn _remove_workspace_folder(&self, uri: Uri) {
13984 match self {
13985 LanguageServerState::Starting {
13986 pending_workspace_folders,
13987 ..
13988 } => {
13989 pending_workspace_folders.lock().remove(&uri);
13990 }
13991 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13992 }
13993 }
13994}
13995
13996impl std::fmt::Debug for LanguageServerState {
13997 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13998 match self {
13999 LanguageServerState::Starting { .. } => {
14000 f.debug_struct("LanguageServerState::Starting").finish()
14001 }
14002 LanguageServerState::Running { .. } => {
14003 f.debug_struct("LanguageServerState::Running").finish()
14004 }
14005 }
14006 }
14007}
14008
14009#[derive(Clone, Debug, Serialize)]
14010pub struct LanguageServerProgress {
14011 pub is_disk_based_diagnostics_progress: bool,
14012 pub is_cancellable: bool,
14013 pub title: Option<String>,
14014 pub message: Option<String>,
14015 pub percentage: Option<usize>,
14016 #[serde(skip_serializing)]
14017 pub last_update_at: Instant,
14018}
14019
14020#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14021pub struct DiagnosticSummary {
14022 pub error_count: usize,
14023 pub warning_count: usize,
14024}
14025
14026impl DiagnosticSummary {
14027 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14028 let mut this = Self {
14029 error_count: 0,
14030 warning_count: 0,
14031 };
14032
14033 for entry in diagnostics {
14034 if entry.diagnostic.is_primary {
14035 match entry.diagnostic.severity {
14036 DiagnosticSeverity::ERROR => this.error_count += 1,
14037 DiagnosticSeverity::WARNING => this.warning_count += 1,
14038 _ => {}
14039 }
14040 }
14041 }
14042
14043 this
14044 }
14045
14046 pub fn is_empty(&self) -> bool {
14047 self.error_count == 0 && self.warning_count == 0
14048 }
14049
14050 pub fn to_proto(
14051 self,
14052 language_server_id: LanguageServerId,
14053 path: &RelPath,
14054 ) -> proto::DiagnosticSummary {
14055 proto::DiagnosticSummary {
14056 path: path.to_proto(),
14057 language_server_id: language_server_id.0 as u64,
14058 error_count: self.error_count as u32,
14059 warning_count: self.warning_count as u32,
14060 }
14061 }
14062}
14063
14064#[derive(Clone, Debug)]
14065pub enum CompletionDocumentation {
14066 /// There is no documentation for this completion.
14067 Undocumented,
14068 /// A single line of documentation.
14069 SingleLine(SharedString),
14070 /// Multiple lines of plain text documentation.
14071 MultiLinePlainText(SharedString),
14072 /// Markdown documentation.
14073 MultiLineMarkdown(SharedString),
14074 /// Both single line and multiple lines of plain text documentation.
14075 SingleLineAndMultiLinePlainText {
14076 single_line: SharedString,
14077 plain_text: Option<SharedString>,
14078 },
14079}
14080
14081impl CompletionDocumentation {
14082 #[cfg(any(test, feature = "test-support"))]
14083 pub fn text(&self) -> SharedString {
14084 match self {
14085 CompletionDocumentation::Undocumented => "".into(),
14086 CompletionDocumentation::SingleLine(s) => s.clone(),
14087 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14088 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14089 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14090 single_line.clone()
14091 }
14092 }
14093 }
14094}
14095
14096impl From<lsp::Documentation> for CompletionDocumentation {
14097 fn from(docs: lsp::Documentation) -> Self {
14098 match docs {
14099 lsp::Documentation::String(text) => {
14100 if text.lines().count() <= 1 {
14101 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14102 } else {
14103 CompletionDocumentation::MultiLinePlainText(text.into())
14104 }
14105 }
14106
14107 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14108 lsp::MarkupKind::PlainText => {
14109 if value.lines().count() <= 1 {
14110 CompletionDocumentation::SingleLine(value.into())
14111 } else {
14112 CompletionDocumentation::MultiLinePlainText(value.into())
14113 }
14114 }
14115
14116 lsp::MarkupKind::Markdown => {
14117 CompletionDocumentation::MultiLineMarkdown(value.into())
14118 }
14119 },
14120 }
14121 }
14122}
14123
14124pub enum ResolvedHint {
14125 Resolved(InlayHint),
14126 Resolving(Shared<Task<()>>),
14127}
14128
14129pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14130 glob.components()
14131 .take_while(|component| match component {
14132 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14133 _ => true,
14134 })
14135 .collect()
14136}
14137
14138pub struct SshLspAdapter {
14139 name: LanguageServerName,
14140 binary: LanguageServerBinary,
14141 initialization_options: Option<String>,
14142 code_action_kinds: Option<Vec<CodeActionKind>>,
14143}
14144
14145impl SshLspAdapter {
14146 pub fn new(
14147 name: LanguageServerName,
14148 binary: LanguageServerBinary,
14149 initialization_options: Option<String>,
14150 code_action_kinds: Option<String>,
14151 ) -> Self {
14152 Self {
14153 name,
14154 binary,
14155 initialization_options,
14156 code_action_kinds: code_action_kinds
14157 .as_ref()
14158 .and_then(|c| serde_json::from_str(c).ok()),
14159 }
14160 }
14161}
14162
14163impl LspInstaller for SshLspAdapter {
14164 type BinaryVersion = ();
14165 async fn check_if_user_installed(
14166 &self,
14167 _: &dyn LspAdapterDelegate,
14168 _: Option<Toolchain>,
14169 _: &AsyncApp,
14170 ) -> Option<LanguageServerBinary> {
14171 Some(self.binary.clone())
14172 }
14173
14174 async fn cached_server_binary(
14175 &self,
14176 _: PathBuf,
14177 _: &dyn LspAdapterDelegate,
14178 ) -> Option<LanguageServerBinary> {
14179 None
14180 }
14181
14182 async fn fetch_latest_server_version(
14183 &self,
14184 _: &dyn LspAdapterDelegate,
14185 _: bool,
14186 _: &mut AsyncApp,
14187 ) -> Result<()> {
14188 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14189 }
14190
14191 async fn fetch_server_binary(
14192 &self,
14193 _: (),
14194 _: PathBuf,
14195 _: &dyn LspAdapterDelegate,
14196 ) -> Result<LanguageServerBinary> {
14197 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14198 }
14199}
14200
14201#[async_trait(?Send)]
14202impl LspAdapter for SshLspAdapter {
14203 fn name(&self) -> LanguageServerName {
14204 self.name.clone()
14205 }
14206
14207 async fn initialization_options(
14208 self: Arc<Self>,
14209 _: &Arc<dyn LspAdapterDelegate>,
14210 ) -> Result<Option<serde_json::Value>> {
14211 let Some(options) = &self.initialization_options else {
14212 return Ok(None);
14213 };
14214 let result = serde_json::from_str(options)?;
14215 Ok(result)
14216 }
14217
14218 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14219 self.code_action_kinds.clone()
14220 }
14221}
14222
14223pub fn language_server_settings<'a>(
14224 delegate: &'a dyn LspAdapterDelegate,
14225 language: &LanguageServerName,
14226 cx: &'a App,
14227) -> Option<&'a LspSettings> {
14228 language_server_settings_for(
14229 SettingsLocation {
14230 worktree_id: delegate.worktree_id(),
14231 path: RelPath::empty(),
14232 },
14233 language,
14234 cx,
14235 )
14236}
14237
14238pub fn language_server_settings_for<'a>(
14239 location: SettingsLocation<'a>,
14240 language: &LanguageServerName,
14241 cx: &'a App,
14242) -> Option<&'a LspSettings> {
14243 ProjectSettings::get(Some(location), cx).lsp.get(language)
14244}
14245
14246pub struct LocalLspAdapterDelegate {
14247 lsp_store: WeakEntity<LspStore>,
14248 worktree: worktree::Snapshot,
14249 fs: Arc<dyn Fs>,
14250 http_client: Arc<dyn HttpClient>,
14251 language_registry: Arc<LanguageRegistry>,
14252 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14253}
14254
14255impl LocalLspAdapterDelegate {
14256 pub fn new(
14257 language_registry: Arc<LanguageRegistry>,
14258 environment: &Entity<ProjectEnvironment>,
14259 lsp_store: WeakEntity<LspStore>,
14260 worktree: &Entity<Worktree>,
14261 http_client: Arc<dyn HttpClient>,
14262 fs: Arc<dyn Fs>,
14263 cx: &mut App,
14264 ) -> Arc<Self> {
14265 let load_shell_env_task =
14266 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14267
14268 Arc::new(Self {
14269 lsp_store,
14270 worktree: worktree.read(cx).snapshot(),
14271 fs,
14272 http_client,
14273 language_registry,
14274 load_shell_env_task,
14275 })
14276 }
14277
14278 pub fn from_local_lsp(
14279 local: &LocalLspStore,
14280 worktree: &Entity<Worktree>,
14281 cx: &mut App,
14282 ) -> Arc<Self> {
14283 Self::new(
14284 local.languages.clone(),
14285 &local.environment,
14286 local.weak.clone(),
14287 worktree,
14288 local.http_client.clone(),
14289 local.fs.clone(),
14290 cx,
14291 )
14292 }
14293}
14294
14295#[async_trait]
14296impl LspAdapterDelegate for LocalLspAdapterDelegate {
14297 fn show_notification(&self, message: &str, cx: &mut App) {
14298 self.lsp_store
14299 .update(cx, |_, cx| {
14300 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14301 })
14302 .ok();
14303 }
14304
14305 fn http_client(&self) -> Arc<dyn HttpClient> {
14306 self.http_client.clone()
14307 }
14308
14309 fn worktree_id(&self) -> WorktreeId {
14310 self.worktree.id()
14311 }
14312
14313 fn worktree_root_path(&self) -> &Path {
14314 self.worktree.abs_path().as_ref()
14315 }
14316
14317 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14318 self.worktree.resolve_executable_path(path)
14319 }
14320
14321 async fn shell_env(&self) -> HashMap<String, String> {
14322 let task = self.load_shell_env_task.clone();
14323 task.await.unwrap_or_default()
14324 }
14325
14326 async fn npm_package_installed_version(
14327 &self,
14328 package_name: &str,
14329 ) -> Result<Option<(PathBuf, Version)>> {
14330 let local_package_directory = self.worktree_root_path();
14331 let node_modules_directory = local_package_directory.join("node_modules");
14332
14333 if let Some(version) =
14334 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14335 {
14336 return Ok(Some((node_modules_directory, version)));
14337 }
14338 let Some(npm) = self.which("npm".as_ref()).await else {
14339 log::warn!(
14340 "Failed to find npm executable for {:?}",
14341 local_package_directory
14342 );
14343 return Ok(None);
14344 };
14345
14346 let env = self.shell_env().await;
14347 let output = util::command::new_smol_command(&npm)
14348 .args(["root", "-g"])
14349 .envs(env)
14350 .current_dir(local_package_directory)
14351 .output()
14352 .await?;
14353 let global_node_modules =
14354 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14355
14356 if let Some(version) =
14357 read_package_installed_version(global_node_modules.clone(), package_name).await?
14358 {
14359 return Ok(Some((global_node_modules, version)));
14360 }
14361 return Ok(None);
14362 }
14363
14364 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14365 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14366 if self.fs.is_file(&worktree_abs_path).await {
14367 worktree_abs_path.pop();
14368 }
14369
14370 let env = self.shell_env().await;
14371
14372 let shell_path = env.get("PATH").cloned();
14373
14374 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14375 }
14376
14377 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14378 let mut working_dir = self.worktree_root_path().to_path_buf();
14379 if self.fs.is_file(&working_dir).await {
14380 working_dir.pop();
14381 }
14382 let output = util::command::new_smol_command(&command.path)
14383 .args(command.arguments)
14384 .envs(command.env.clone().unwrap_or_default())
14385 .current_dir(working_dir)
14386 .output()
14387 .await?;
14388
14389 anyhow::ensure!(
14390 output.status.success(),
14391 "{}, stdout: {:?}, stderr: {:?}",
14392 output.status,
14393 String::from_utf8_lossy(&output.stdout),
14394 String::from_utf8_lossy(&output.stderr)
14395 );
14396 Ok(())
14397 }
14398
14399 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14400 self.language_registry
14401 .update_lsp_binary_status(server_name, status);
14402 }
14403
14404 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14405 self.language_registry
14406 .all_lsp_adapters()
14407 .into_iter()
14408 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14409 .collect()
14410 }
14411
14412 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14413 let dir = self.language_registry.language_server_download_dir(name)?;
14414
14415 if !dir.exists() {
14416 smol::fs::create_dir_all(&dir)
14417 .await
14418 .context("failed to create container directory")
14419 .log_err()?;
14420 }
14421
14422 Some(dir)
14423 }
14424
14425 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14426 let entry = self
14427 .worktree
14428 .entry_for_path(path)
14429 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14430 let abs_path = self.worktree.absolutize(&entry.path);
14431 self.fs.load(&abs_path).await
14432 }
14433}
14434
14435async fn populate_labels_for_symbols(
14436 symbols: Vec<CoreSymbol>,
14437 language_registry: &Arc<LanguageRegistry>,
14438 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14439 output: &mut Vec<Symbol>,
14440) {
14441 #[allow(clippy::mutable_key_type)]
14442 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14443
14444 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14445 for symbol in symbols {
14446 let Some(file_name) = symbol.path.file_name() else {
14447 continue;
14448 };
14449 let language = language_registry
14450 .load_language_for_file_path(Path::new(file_name))
14451 .await
14452 .ok()
14453 .or_else(|| {
14454 unknown_paths.insert(file_name.into());
14455 None
14456 });
14457 symbols_by_language
14458 .entry(language)
14459 .or_default()
14460 .push(symbol);
14461 }
14462
14463 for unknown_path in unknown_paths {
14464 log::info!("no language found for symbol in file {unknown_path:?}");
14465 }
14466
14467 let mut label_params = Vec::new();
14468 for (language, mut symbols) in symbols_by_language {
14469 label_params.clear();
14470 label_params.extend(
14471 symbols
14472 .iter_mut()
14473 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14474 );
14475
14476 let mut labels = Vec::new();
14477 if let Some(language) = language {
14478 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14479 language_registry
14480 .lsp_adapters(&language.name())
14481 .first()
14482 .cloned()
14483 });
14484 if let Some(lsp_adapter) = lsp_adapter {
14485 labels = lsp_adapter
14486 .labels_for_symbols(&label_params, &language)
14487 .await
14488 .log_err()
14489 .unwrap_or_default();
14490 }
14491 }
14492
14493 for ((symbol, (name, _)), label) in symbols
14494 .into_iter()
14495 .zip(label_params.drain(..))
14496 .zip(labels.into_iter().chain(iter::repeat(None)))
14497 {
14498 output.push(Symbol {
14499 language_server_name: symbol.language_server_name,
14500 source_worktree_id: symbol.source_worktree_id,
14501 source_language_server_id: symbol.source_language_server_id,
14502 path: symbol.path,
14503 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14504 name,
14505 kind: symbol.kind,
14506 range: symbol.range,
14507 });
14508 }
14509 }
14510}
14511
14512fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14513 match server.capabilities().text_document_sync.as_ref()? {
14514 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14515 // Server wants didSave but didn't specify includeText.
14516 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14517 // Server doesn't want didSave at all.
14518 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14519 // Server provided SaveOptions.
14520 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14521 Some(save_options.include_text.unwrap_or(false))
14522 }
14523 },
14524 // We do not have any save info. Kind affects didChange only.
14525 lsp::TextDocumentSyncCapability::Kind(_) => None,
14526 }
14527}
14528
14529/// Completion items are displayed in a `UniformList`.
14530/// Usually, those items are single-line strings, but in LSP responses,
14531/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14532/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14533/// 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,
14534/// breaking the completions menu presentation.
14535///
14536/// 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.
14537pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14538 let mut new_text = String::with_capacity(label.text.len());
14539 let mut offset_map = vec![0; label.text.len() + 1];
14540 let mut last_char_was_space = false;
14541 let mut new_idx = 0;
14542 let chars = label.text.char_indices().fuse();
14543 let mut newlines_removed = false;
14544
14545 for (idx, c) in chars {
14546 offset_map[idx] = new_idx;
14547
14548 match c {
14549 '\n' if last_char_was_space => {
14550 newlines_removed = true;
14551 }
14552 '\t' | ' ' if last_char_was_space => {}
14553 '\n' if !last_char_was_space => {
14554 new_text.push(' ');
14555 new_idx += 1;
14556 last_char_was_space = true;
14557 newlines_removed = true;
14558 }
14559 ' ' | '\t' => {
14560 new_text.push(' ');
14561 new_idx += 1;
14562 last_char_was_space = true;
14563 }
14564 _ => {
14565 new_text.push(c);
14566 new_idx += c.len_utf8();
14567 last_char_was_space = false;
14568 }
14569 }
14570 }
14571 offset_map[label.text.len()] = new_idx;
14572
14573 // Only modify the label if newlines were removed.
14574 if !newlines_removed {
14575 return;
14576 }
14577
14578 let last_index = new_idx;
14579 let mut run_ranges_errors = Vec::new();
14580 label.runs.retain_mut(|(range, _)| {
14581 match offset_map.get(range.start) {
14582 Some(&start) => range.start = start,
14583 None => {
14584 run_ranges_errors.push(range.clone());
14585 return false;
14586 }
14587 }
14588
14589 match offset_map.get(range.end) {
14590 Some(&end) => range.end = end,
14591 None => {
14592 run_ranges_errors.push(range.clone());
14593 range.end = last_index;
14594 }
14595 }
14596 true
14597 });
14598 if !run_ranges_errors.is_empty() {
14599 log::error!(
14600 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14601 label.text
14602 );
14603 }
14604
14605 let mut wrong_filter_range = None;
14606 if label.filter_range == (0..label.text.len()) {
14607 label.filter_range = 0..new_text.len();
14608 } else {
14609 let mut original_filter_range = Some(label.filter_range.clone());
14610 match offset_map.get(label.filter_range.start) {
14611 Some(&start) => label.filter_range.start = start,
14612 None => {
14613 wrong_filter_range = original_filter_range.take();
14614 label.filter_range.start = last_index;
14615 }
14616 }
14617
14618 match offset_map.get(label.filter_range.end) {
14619 Some(&end) => label.filter_range.end = end,
14620 None => {
14621 wrong_filter_range = original_filter_range.take();
14622 label.filter_range.end = last_index;
14623 }
14624 }
14625 }
14626 if let Some(wrong_filter_range) = wrong_filter_range {
14627 log::error!(
14628 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14629 label.text
14630 );
14631 }
14632
14633 label.text = new_text;
14634}