1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
59 Subscription, Task, WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
65 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
66 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
67 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
68 Toolchain, Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_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#[derive(Clone, Debug, Hash, PartialEq, Eq)]
230struct LanguageServerSeed {
231 worktree_id: WorktreeId,
232 name: LanguageServerName,
233 toolchain: Option<Toolchain>,
234 settings: Arc<LspSettings>,
235}
236
237#[derive(Debug)]
238pub struct DocumentDiagnosticsUpdate<'a, D> {
239 pub diagnostics: D,
240 pub result_id: Option<SharedString>,
241 pub registration_id: Option<SharedString>,
242 pub server_id: LanguageServerId,
243 pub disk_based_sources: Cow<'a, [String]>,
244}
245
246pub struct DocumentDiagnostics {
247 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
248 document_abs_path: PathBuf,
249 version: Option<i32>,
250}
251
252#[derive(Default, Debug)]
253struct DynamicRegistrations {
254 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
255 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
256}
257
258pub struct LocalLspStore {
259 weak: WeakEntity<LspStore>,
260 pub worktree_store: Entity<WorktreeStore>,
261 toolchain_store: Entity<LocalToolchainStore>,
262 http_client: Arc<dyn HttpClient>,
263 environment: Entity<ProjectEnvironment>,
264 fs: Arc<dyn Fs>,
265 languages: Arc<LanguageRegistry>,
266 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
267 yarn: Entity<YarnPathStore>,
268 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
269 buffers_being_formatted: HashSet<BufferId>,
270 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
271 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
272 watched_manifest_filenames: HashSet<ManifestName>,
273 language_server_paths_watched_for_rename:
274 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
275 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
276 supplementary_language_servers:
277 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
278 prettier_store: Entity<PrettierStore>,
279 next_diagnostic_group_id: usize,
280 diagnostics: HashMap<
281 WorktreeId,
282 HashMap<
283 Arc<RelPath>,
284 Vec<(
285 LanguageServerId,
286 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
287 )>,
288 >,
289 >,
290 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
291 _subscription: gpui::Subscription,
292 lsp_tree: LanguageServerTree,
293 registered_buffers: HashMap<BufferId, usize>,
294 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
295 buffer_pull_diagnostics_result_ids: HashMap<
296 LanguageServerId,
297 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
298 >,
299 workspace_pull_diagnostics_result_ids: HashMap<
300 LanguageServerId,
301 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
302 >,
303 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
304
305 buffers_to_refresh_hash_set: HashSet<BufferId>,
306 buffers_to_refresh_queue: VecDeque<BufferId>,
307 _background_diagnostics_worker: Shared<Task<()>>,
308}
309
310impl LocalLspStore {
311 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
312 pub fn running_language_server_for_id(
313 &self,
314 id: LanguageServerId,
315 ) -> Option<&Arc<LanguageServer>> {
316 let language_server_state = self.language_servers.get(&id)?;
317
318 match language_server_state {
319 LanguageServerState::Running { server, .. } => Some(server),
320 LanguageServerState::Starting { .. } => None,
321 }
322 }
323
324 fn get_or_insert_language_server(
325 &mut self,
326 worktree_handle: &Entity<Worktree>,
327 delegate: Arc<LocalLspAdapterDelegate>,
328 disposition: &Arc<LaunchDisposition>,
329 language_name: &LanguageName,
330 cx: &mut App,
331 ) -> LanguageServerId {
332 let key = LanguageServerSeed {
333 worktree_id: worktree_handle.read(cx).id(),
334 name: disposition.server_name.clone(),
335 settings: disposition.settings.clone(),
336 toolchain: disposition.toolchain.clone(),
337 };
338 if let Some(state) = self.language_server_ids.get_mut(&key) {
339 state.project_roots.insert(disposition.path.path.clone());
340 state.id
341 } else {
342 let adapter = self
343 .languages
344 .lsp_adapters(language_name)
345 .into_iter()
346 .find(|adapter| adapter.name() == disposition.server_name)
347 .expect("To find LSP adapter");
348 let new_language_server_id = self.start_language_server(
349 worktree_handle,
350 delegate,
351 adapter,
352 disposition.settings.clone(),
353 key.clone(),
354 cx,
355 );
356 if let Some(state) = self.language_server_ids.get_mut(&key) {
357 state.project_roots.insert(disposition.path.path.clone());
358 } else {
359 debug_assert!(
360 false,
361 "Expected `start_language_server` to ensure that `key` exists in a map"
362 );
363 }
364 new_language_server_id
365 }
366 }
367
368 fn start_language_server(
369 &mut self,
370 worktree_handle: &Entity<Worktree>,
371 delegate: Arc<LocalLspAdapterDelegate>,
372 adapter: Arc<CachedLspAdapter>,
373 settings: Arc<LspSettings>,
374 key: LanguageServerSeed,
375 cx: &mut App,
376 ) -> LanguageServerId {
377 let worktree = worktree_handle.read(cx);
378
379 let worktree_id = worktree.id();
380 let worktree_abs_path = worktree.abs_path();
381 let toolchain = key.toolchain.clone();
382 let override_options = settings.initialization_options.clone();
383
384 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
385
386 let server_id = self.languages.next_language_server_id();
387 log::trace!(
388 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
389 adapter.name.0
390 );
391
392 let wait_until_worktree_trust =
393 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
394 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
395 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
396 });
397 if can_trust {
398 self.restricted_worktrees_tasks.remove(&worktree_id);
399 None
400 } else {
401 match self.restricted_worktrees_tasks.entry(worktree_id) {
402 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
403 hash_map::Entry::Vacant(v) => {
404 let (mut tx, rx) = watch::channel::<bool>();
405 let lsp_store = self.weak.clone();
406 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
407 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
408 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
409 tx.blocking_send(true).ok();
410 lsp_store
411 .update(cx, |lsp_store, _| {
412 if let Some(local_lsp_store) =
413 lsp_store.as_local_mut()
414 {
415 local_lsp_store
416 .restricted_worktrees_tasks
417 .remove(&worktree_id);
418 }
419 })
420 .ok();
421 }
422 }
423 });
424 v.insert((subscription, rx.clone()));
425 Some(rx)
426 }
427 }
428 }
429 });
430 let update_binary_status = wait_until_worktree_trust.is_none();
431
432 let binary = self.get_language_server_binary(
433 worktree_abs_path.clone(),
434 adapter.clone(),
435 settings,
436 toolchain.clone(),
437 delegate.clone(),
438 true,
439 wait_until_worktree_trust,
440 cx,
441 );
442 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
443
444 let pending_server = cx.spawn({
445 let adapter = adapter.clone();
446 let server_name = adapter.name.clone();
447 let stderr_capture = stderr_capture.clone();
448 #[cfg(any(test, feature = "test-support"))]
449 let lsp_store = self.weak.clone();
450 let pending_workspace_folders = pending_workspace_folders.clone();
451 async move |cx| {
452 let binary = binary.await?;
453 #[cfg(any(test, feature = "test-support"))]
454 if let Some(server) = lsp_store
455 .update(&mut cx.clone(), |this, cx| {
456 this.languages.create_fake_language_server(
457 server_id,
458 &server_name,
459 binary.clone(),
460 &mut cx.to_async(),
461 )
462 })
463 .ok()
464 .flatten()
465 {
466 return Ok(server);
467 }
468
469 let code_action_kinds = adapter.code_action_kinds();
470 lsp::LanguageServer::new(
471 stderr_capture,
472 server_id,
473 server_name,
474 binary,
475 &worktree_abs_path,
476 code_action_kinds,
477 Some(pending_workspace_folders),
478 cx,
479 )
480 }
481 });
482
483 let startup = {
484 let server_name = adapter.name.0.clone();
485 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
486 let key = key.clone();
487 let adapter = adapter.clone();
488 let lsp_store = self.weak.clone();
489 let pending_workspace_folders = pending_workspace_folders.clone();
490
491 let pull_diagnostics = ProjectSettings::get_global(cx)
492 .diagnostics
493 .lsp_pull_diagnostics
494 .enabled;
495 cx.spawn(async move |cx| {
496 let result = async {
497 let language_server = pending_server.await?;
498
499 let workspace_config = Self::workspace_configuration_for_adapter(
500 adapter.adapter.clone(),
501 &delegate,
502 toolchain,
503 None,
504 cx,
505 )
506 .await?;
507
508 let mut initialization_options = Self::initialization_options_for_adapter(
509 adapter.adapter.clone(),
510 &delegate,
511 )
512 .await?;
513
514 match (&mut initialization_options, override_options) {
515 (Some(initialization_options), Some(override_options)) => {
516 merge_json_value_into(override_options, initialization_options);
517 }
518 (None, override_options) => initialization_options = override_options,
519 _ => {}
520 }
521
522 let initialization_params = cx.update(|cx| {
523 let mut params =
524 language_server.default_initialize_params(pull_diagnostics, cx);
525 params.initialization_options = initialization_options;
526 adapter.adapter.prepare_initialize_params(params, cx)
527 })?;
528
529 Self::setup_lsp_messages(
530 lsp_store.clone(),
531 &language_server,
532 delegate.clone(),
533 adapter.clone(),
534 );
535
536 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
537 settings: workspace_config,
538 };
539 let language_server = cx
540 .update(|cx| {
541 language_server.initialize(
542 initialization_params,
543 Arc::new(did_change_configuration_params.clone()),
544 cx,
545 )
546 })
547 .await
548 .inspect_err(|_| {
549 if let Some(lsp_store) = lsp_store.upgrade() {
550 lsp_store.update(cx, |lsp_store, cx| {
551 lsp_store.cleanup_lsp_data(server_id);
552 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
553 });
554 }
555 })?;
556
557 language_server.notify::<lsp::notification::DidChangeConfiguration>(
558 did_change_configuration_params,
559 )?;
560
561 anyhow::Ok(language_server)
562 }
563 .await;
564
565 match result {
566 Ok(server) => {
567 lsp_store
568 .update(cx, |lsp_store, cx| {
569 lsp_store.insert_newly_running_language_server(
570 adapter,
571 server.clone(),
572 server_id,
573 key,
574 pending_workspace_folders,
575 cx,
576 );
577 })
578 .ok();
579 stderr_capture.lock().take();
580 Some(server)
581 }
582
583 Err(err) => {
584 let log = stderr_capture.lock().take().unwrap_or_default();
585 delegate.update_status(
586 adapter.name(),
587 BinaryStatus::Failed {
588 error: if log.is_empty() {
589 format!("{err:#}")
590 } else {
591 format!("{err:#}\n-- stderr --\n{log}")
592 },
593 },
594 );
595 log::error!(
596 "Failed to start language server {server_name:?}: {}",
597 redact_command(&format!("{err:?}"))
598 );
599 if !log.is_empty() {
600 log::error!("server stderr: {}", redact_command(&log));
601 }
602 None
603 }
604 }
605 })
606 };
607 let state = LanguageServerState::Starting {
608 startup,
609 pending_workspace_folders,
610 };
611
612 if update_binary_status {
613 self.languages
614 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
615 }
616
617 self.language_servers.insert(server_id, state);
618 self.language_server_ids
619 .entry(key)
620 .or_insert(UnifiedLanguageServer {
621 id: server_id,
622 project_roots: Default::default(),
623 });
624 server_id
625 }
626
627 fn get_language_server_binary(
628 &self,
629 worktree_abs_path: Arc<Path>,
630 adapter: Arc<CachedLspAdapter>,
631 settings: Arc<LspSettings>,
632 toolchain: Option<Toolchain>,
633 delegate: Arc<dyn LspAdapterDelegate>,
634 allow_binary_download: bool,
635 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
636 cx: &mut App,
637 ) -> Task<Result<LanguageServerBinary>> {
638 if let Some(settings) = &settings.binary
639 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
640 {
641 let settings = settings.clone();
642 let languages = self.languages.clone();
643 return cx.background_spawn(async move {
644 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
645 let already_trusted = *wait_until_worktree_trust.borrow();
646 if !already_trusted {
647 log::info!(
648 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
649 adapter.name(),
650 );
651 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
652 if worktree_trusted {
653 break;
654 }
655 }
656 log::info!(
657 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
658 adapter.name(),
659 );
660 }
661 languages
662 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
663 }
664 let mut env = delegate.shell_env().await;
665 env.extend(settings.env.unwrap_or_default());
666
667 Ok(LanguageServerBinary {
668 path: delegate.resolve_executable_path(path),
669 env: Some(env),
670 arguments: settings
671 .arguments
672 .unwrap_or_default()
673 .iter()
674 .map(Into::into)
675 .collect(),
676 })
677 });
678 }
679 let lsp_binary_options = LanguageServerBinaryOptions {
680 allow_path_lookup: !settings
681 .binary
682 .as_ref()
683 .and_then(|b| b.ignore_system_version)
684 .unwrap_or_default(),
685 allow_binary_download,
686 pre_release: settings
687 .fetch
688 .as_ref()
689 .and_then(|f| f.pre_release)
690 .unwrap_or(false),
691 };
692
693 cx.spawn(async move |cx| {
694 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
695 let already_trusted = *wait_until_worktree_trust.borrow();
696 if !already_trusted {
697 log::info!(
698 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
699 adapter.name(),
700 );
701 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
702 if worktree_trusted {
703 break;
704 }
705 }
706 log::info!(
707 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
708 adapter.name(),
709 );
710 }
711 }
712
713 let (existing_binary, maybe_download_binary) = adapter
714 .clone()
715 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
716 .await
717 .await;
718
719 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
720
721 let mut binary = match (existing_binary, maybe_download_binary) {
722 (binary, None) => binary?,
723 (Err(_), Some(downloader)) => downloader.await?,
724 (Ok(existing_binary), Some(downloader)) => {
725 let mut download_timeout = cx
726 .background_executor()
727 .timer(SERVER_DOWNLOAD_TIMEOUT)
728 .fuse();
729 let mut downloader = downloader.fuse();
730 futures::select! {
731 _ = download_timeout => {
732 // Return existing binary and kick the existing work to the background.
733 cx.spawn(async move |_| downloader.await).detach();
734 Ok(existing_binary)
735 },
736 downloaded_or_existing_binary = downloader => {
737 // If download fails, this results in the existing binary.
738 downloaded_or_existing_binary
739 }
740 }?
741 }
742 };
743 let mut shell_env = delegate.shell_env().await;
744
745 shell_env.extend(binary.env.unwrap_or_default());
746
747 if let Some(settings) = settings.binary.as_ref() {
748 if let Some(arguments) = &settings.arguments {
749 binary.arguments = arguments.iter().map(Into::into).collect();
750 }
751 if let Some(env) = &settings.env {
752 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
753 }
754 }
755
756 binary.env = Some(shell_env);
757 Ok(binary)
758 })
759 }
760
761 fn setup_lsp_messages(
762 lsp_store: WeakEntity<LspStore>,
763 language_server: &LanguageServer,
764 delegate: Arc<dyn LspAdapterDelegate>,
765 adapter: Arc<CachedLspAdapter>,
766 ) {
767 let name = language_server.name();
768 let server_id = language_server.server_id();
769 language_server
770 .on_notification::<lsp::notification::PublishDiagnostics, _>({
771 let adapter = adapter.clone();
772 let this = lsp_store.clone();
773 move |mut params, cx| {
774 let adapter = adapter.clone();
775 if let Some(this) = this.upgrade() {
776 this.update(cx, |this, cx| {
777 {
778 let buffer = params
779 .uri
780 .to_file_path()
781 .map(|file_path| this.get_buffer(&file_path, cx))
782 .ok()
783 .flatten();
784 adapter.process_diagnostics(&mut params, server_id, buffer);
785 }
786
787 this.merge_lsp_diagnostics(
788 DiagnosticSourceKind::Pushed,
789 vec![DocumentDiagnosticsUpdate {
790 server_id,
791 diagnostics: params,
792 result_id: None,
793 disk_based_sources: Cow::Borrowed(
794 &adapter.disk_based_diagnostic_sources,
795 ),
796 registration_id: None,
797 }],
798 |_, diagnostic, cx| match diagnostic.source_kind {
799 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
800 adapter.retain_old_diagnostic(diagnostic, cx)
801 }
802 DiagnosticSourceKind::Pulled => true,
803 },
804 cx,
805 )
806 .log_err();
807 });
808 }
809 }
810 })
811 .detach();
812 language_server
813 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
814 let adapter = adapter.adapter.clone();
815 let delegate = delegate.clone();
816 let this = lsp_store.clone();
817 move |params, cx| {
818 let adapter = adapter.clone();
819 let delegate = delegate.clone();
820 let this = this.clone();
821 let mut cx = cx.clone();
822 async move {
823 let toolchain_for_id = this
824 .update(&mut cx, |this, _| {
825 this.as_local()?.language_server_ids.iter().find_map(
826 |(seed, value)| {
827 (value.id == server_id).then(|| seed.toolchain.clone())
828 },
829 )
830 })?
831 .context("Expected the LSP store to be in a local mode")?;
832
833 let mut scope_uri_to_workspace_config = BTreeMap::new();
834 for item in ¶ms.items {
835 let scope_uri = item.scope_uri.clone();
836 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
837 scope_uri_to_workspace_config.entry(scope_uri.clone())
838 else {
839 // We've already queried workspace configuration of this URI.
840 continue;
841 };
842 let workspace_config = Self::workspace_configuration_for_adapter(
843 adapter.clone(),
844 &delegate,
845 toolchain_for_id.clone(),
846 scope_uri,
847 &mut cx,
848 )
849 .await?;
850 new_scope_uri.insert(workspace_config);
851 }
852
853 Ok(params
854 .items
855 .into_iter()
856 .filter_map(|item| {
857 let workspace_config =
858 scope_uri_to_workspace_config.get(&item.scope_uri)?;
859 if let Some(section) = &item.section {
860 Some(
861 workspace_config
862 .get(section)
863 .cloned()
864 .unwrap_or(serde_json::Value::Null),
865 )
866 } else {
867 Some(workspace_config.clone())
868 }
869 })
870 .collect())
871 }
872 }
873 })
874 .detach();
875
876 language_server
877 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
878 let this = lsp_store.clone();
879 move |_, cx| {
880 let this = this.clone();
881 let cx = cx.clone();
882 async move {
883 let Some(server) =
884 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
885 else {
886 return Ok(None);
887 };
888 let root = server.workspace_folders();
889 Ok(Some(
890 root.into_iter()
891 .map(|uri| WorkspaceFolder {
892 uri,
893 name: Default::default(),
894 })
895 .collect(),
896 ))
897 }
898 }
899 })
900 .detach();
901 // Even though we don't have handling for these requests, respond to them to
902 // avoid stalling any language server like `gopls` which waits for a response
903 // to these requests when initializing.
904 language_server
905 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
906 let this = lsp_store.clone();
907 move |params, cx| {
908 let this = this.clone();
909 let mut cx = cx.clone();
910 async move {
911 this.update(&mut cx, |this, _| {
912 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
913 {
914 status
915 .progress_tokens
916 .insert(ProgressToken::from_lsp(params.token));
917 }
918 })?;
919
920 Ok(())
921 }
922 }
923 })
924 .detach();
925
926 language_server
927 .on_request::<lsp::request::RegisterCapability, _, _>({
928 let lsp_store = lsp_store.clone();
929 move |params, cx| {
930 let lsp_store = lsp_store.clone();
931 let mut cx = cx.clone();
932 async move {
933 lsp_store
934 .update(&mut cx, |lsp_store, cx| {
935 if lsp_store.as_local().is_some() {
936 match lsp_store
937 .register_server_capabilities(server_id, params, cx)
938 {
939 Ok(()) => {}
940 Err(e) => {
941 log::error!(
942 "Failed to register server capabilities: {e:#}"
943 );
944 }
945 };
946 }
947 })
948 .ok();
949 Ok(())
950 }
951 }
952 })
953 .detach();
954
955 language_server
956 .on_request::<lsp::request::UnregisterCapability, _, _>({
957 let lsp_store = lsp_store.clone();
958 move |params, cx| {
959 let lsp_store = lsp_store.clone();
960 let mut cx = cx.clone();
961 async move {
962 lsp_store
963 .update(&mut cx, |lsp_store, cx| {
964 if lsp_store.as_local().is_some() {
965 match lsp_store
966 .unregister_server_capabilities(server_id, params, cx)
967 {
968 Ok(()) => {}
969 Err(e) => {
970 log::error!(
971 "Failed to unregister server capabilities: {e:#}"
972 );
973 }
974 }
975 }
976 })
977 .ok();
978 Ok(())
979 }
980 }
981 })
982 .detach();
983
984 language_server
985 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
986 let this = lsp_store.clone();
987 move |params, cx| {
988 let mut cx = cx.clone();
989 let this = this.clone();
990 async move {
991 LocalLspStore::on_lsp_workspace_edit(
992 this.clone(),
993 params,
994 server_id,
995 &mut cx,
996 )
997 .await
998 }
999 }
1000 })
1001 .detach();
1002
1003 language_server
1004 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1005 let lsp_store = lsp_store.clone();
1006 let request_id = Arc::new(AtomicUsize::new(0));
1007 move |(), cx| {
1008 let lsp_store = lsp_store.clone();
1009 let request_id = request_id.clone();
1010 let mut cx = cx.clone();
1011 async move {
1012 lsp_store
1013 .update(&mut cx, |lsp_store, cx| {
1014 let request_id =
1015 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1016 cx.emit(LspStoreEvent::RefreshInlayHints {
1017 server_id,
1018 request_id,
1019 });
1020 lsp_store
1021 .downstream_client
1022 .as_ref()
1023 .map(|(client, project_id)| {
1024 client.send(proto::RefreshInlayHints {
1025 project_id: *project_id,
1026 server_id: server_id.to_proto(),
1027 request_id: request_id.map(|id| id as u64),
1028 })
1029 })
1030 })?
1031 .transpose()?;
1032 Ok(())
1033 }
1034 }
1035 })
1036 .detach();
1037
1038 language_server
1039 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1040 let this = lsp_store.clone();
1041 move |(), cx| {
1042 let this = this.clone();
1043 let mut cx = cx.clone();
1044 async move {
1045 this.update(&mut cx, |this, cx| {
1046 cx.emit(LspStoreEvent::RefreshCodeLens);
1047 this.downstream_client.as_ref().map(|(client, project_id)| {
1048 client.send(proto::RefreshCodeLens {
1049 project_id: *project_id,
1050 })
1051 })
1052 })?
1053 .transpose()?;
1054 Ok(())
1055 }
1056 }
1057 })
1058 .detach();
1059
1060 language_server
1061 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1062 let this = lsp_store.clone();
1063 move |(), cx| {
1064 let this = this.clone();
1065 let mut cx = cx.clone();
1066 async move {
1067 this.update(&mut cx, |lsp_store, cx| {
1068 lsp_store.pull_workspace_diagnostics(server_id);
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::PullWorkspaceDiagnostics {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 })
1077 })
1078 .transpose()?;
1079 anyhow::Ok(
1080 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1081 )
1082 })??
1083 .await;
1084 Ok(())
1085 }
1086 }
1087 })
1088 .detach();
1089
1090 language_server
1091 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1092 let this = lsp_store.clone();
1093 let name = name.to_string();
1094 let adapter = adapter.clone();
1095 move |params, cx| {
1096 let this = this.clone();
1097 let name = name.to_string();
1098 let adapter = adapter.clone();
1099 let mut cx = cx.clone();
1100 async move {
1101 let actions = params.actions.unwrap_or_default();
1102 let message = params.message.clone();
1103 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1104 let level = match params.typ {
1105 lsp::MessageType::ERROR => PromptLevel::Critical,
1106 lsp::MessageType::WARNING => PromptLevel::Warning,
1107 _ => PromptLevel::Info,
1108 };
1109 let request = LanguageServerPromptRequest::new(
1110 level,
1111 params.message,
1112 actions,
1113 name.clone(),
1114 tx,
1115 );
1116
1117 let did_update = this
1118 .update(&mut cx, |_, cx| {
1119 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1120 })
1121 .is_ok();
1122 if did_update {
1123 let response = rx.recv().await.ok();
1124 if let Some(ref selected_action) = response {
1125 let context = language::PromptResponseContext {
1126 message,
1127 selected_action: selected_action.clone(),
1128 };
1129 adapter.process_prompt_response(&context, &mut cx)
1130 }
1131
1132 Ok(response)
1133 } else {
1134 Ok(None)
1135 }
1136 }
1137 }
1138 })
1139 .detach();
1140 language_server
1141 .on_notification::<lsp::notification::ShowMessage, _>({
1142 let this = lsp_store.clone();
1143 let name = name.to_string();
1144 move |params, cx| {
1145 let this = this.clone();
1146 let name = name.to_string();
1147 let mut cx = cx.clone();
1148
1149 let (tx, _) = smol::channel::bounded(1);
1150 let level = match params.typ {
1151 lsp::MessageType::ERROR => PromptLevel::Critical,
1152 lsp::MessageType::WARNING => PromptLevel::Warning,
1153 _ => PromptLevel::Info,
1154 };
1155 let request =
1156 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1157
1158 let _ = this.update(&mut cx, |_, cx| {
1159 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1160 });
1161 }
1162 })
1163 .detach();
1164
1165 let disk_based_diagnostics_progress_token =
1166 adapter.disk_based_diagnostics_progress_token.clone();
1167
1168 language_server
1169 .on_notification::<lsp::notification::Progress, _>({
1170 let this = lsp_store.clone();
1171 move |params, cx| {
1172 if let Some(this) = this.upgrade() {
1173 this.update(cx, |this, cx| {
1174 this.on_lsp_progress(
1175 params,
1176 server_id,
1177 disk_based_diagnostics_progress_token.clone(),
1178 cx,
1179 );
1180 });
1181 }
1182 }
1183 })
1184 .detach();
1185
1186 language_server
1187 .on_notification::<lsp::notification::LogMessage, _>({
1188 let this = lsp_store.clone();
1189 move |params, cx| {
1190 if let Some(this) = this.upgrade() {
1191 this.update(cx, |_, cx| {
1192 cx.emit(LspStoreEvent::LanguageServerLog(
1193 server_id,
1194 LanguageServerLogType::Log(params.typ),
1195 params.message,
1196 ));
1197 });
1198 }
1199 }
1200 })
1201 .detach();
1202
1203 language_server
1204 .on_notification::<lsp::notification::LogTrace, _>({
1205 let this = lsp_store.clone();
1206 move |params, cx| {
1207 let mut cx = cx.clone();
1208 if let Some(this) = this.upgrade() {
1209 this.update(&mut cx, |_, cx| {
1210 cx.emit(LspStoreEvent::LanguageServerLog(
1211 server_id,
1212 LanguageServerLogType::Trace {
1213 verbose_info: params.verbose,
1214 },
1215 params.message,
1216 ));
1217 });
1218 }
1219 }
1220 })
1221 .detach();
1222
1223 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1224 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1225 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1226 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1227 }
1228
1229 fn shutdown_language_servers_on_quit(
1230 &mut self,
1231 _: &mut Context<LspStore>,
1232 ) -> impl Future<Output = ()> + use<> {
1233 let shutdown_futures = self
1234 .language_servers
1235 .drain()
1236 .map(|(_, server_state)| Self::shutdown_server(server_state))
1237 .collect::<Vec<_>>();
1238
1239 async move {
1240 join_all(shutdown_futures).await;
1241 }
1242 }
1243
1244 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1245 match server_state {
1246 LanguageServerState::Running { server, .. } => {
1247 if let Some(shutdown) = server.shutdown() {
1248 shutdown.await;
1249 }
1250 }
1251 LanguageServerState::Starting { startup, .. } => {
1252 if let Some(server) = startup.await
1253 && let Some(shutdown) = server.shutdown()
1254 {
1255 shutdown.await;
1256 }
1257 }
1258 }
1259 Ok(())
1260 }
1261
1262 fn language_servers_for_worktree(
1263 &self,
1264 worktree_id: WorktreeId,
1265 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1266 self.language_server_ids
1267 .iter()
1268 .filter_map(move |(seed, state)| {
1269 if seed.worktree_id != worktree_id {
1270 return None;
1271 }
1272
1273 if let Some(LanguageServerState::Running { server, .. }) =
1274 self.language_servers.get(&state.id)
1275 {
1276 Some(server)
1277 } else {
1278 None
1279 }
1280 })
1281 }
1282
1283 fn language_server_ids_for_project_path(
1284 &self,
1285 project_path: ProjectPath,
1286 language: &Language,
1287 cx: &mut App,
1288 ) -> Vec<LanguageServerId> {
1289 let Some(worktree) = self
1290 .worktree_store
1291 .read(cx)
1292 .worktree_for_id(project_path.worktree_id, cx)
1293 else {
1294 return Vec::new();
1295 };
1296 let delegate: Arc<dyn ManifestDelegate> =
1297 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1298
1299 self.lsp_tree
1300 .get(
1301 project_path,
1302 language.name(),
1303 language.manifest(),
1304 &delegate,
1305 cx,
1306 )
1307 .collect::<Vec<_>>()
1308 }
1309
1310 fn language_server_ids_for_buffer(
1311 &self,
1312 buffer: &Buffer,
1313 cx: &mut App,
1314 ) -> Vec<LanguageServerId> {
1315 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1316 let worktree_id = file.worktree_id(cx);
1317
1318 let path: Arc<RelPath> = file
1319 .path()
1320 .parent()
1321 .map(Arc::from)
1322 .unwrap_or_else(|| file.path().clone());
1323 let worktree_path = ProjectPath { worktree_id, path };
1324 self.language_server_ids_for_project_path(worktree_path, language, cx)
1325 } else {
1326 Vec::new()
1327 }
1328 }
1329
1330 fn language_servers_for_buffer<'a>(
1331 &'a self,
1332 buffer: &'a Buffer,
1333 cx: &'a mut App,
1334 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1335 self.language_server_ids_for_buffer(buffer, cx)
1336 .into_iter()
1337 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1338 LanguageServerState::Running {
1339 adapter, server, ..
1340 } => Some((adapter, server)),
1341 _ => None,
1342 })
1343 }
1344
1345 async fn execute_code_action_kind_locally(
1346 lsp_store: WeakEntity<LspStore>,
1347 mut buffers: Vec<Entity<Buffer>>,
1348 kind: CodeActionKind,
1349 push_to_history: bool,
1350 cx: &mut AsyncApp,
1351 ) -> anyhow::Result<ProjectTransaction> {
1352 // Do not allow multiple concurrent code actions requests for the
1353 // same buffer.
1354 lsp_store.update(cx, |this, cx| {
1355 let this = this.as_local_mut().unwrap();
1356 buffers.retain(|buffer| {
1357 this.buffers_being_formatted
1358 .insert(buffer.read(cx).remote_id())
1359 });
1360 })?;
1361 let _cleanup = defer({
1362 let this = lsp_store.clone();
1363 let mut cx = cx.clone();
1364 let buffers = &buffers;
1365 move || {
1366 this.update(&mut cx, |this, cx| {
1367 let this = this.as_local_mut().unwrap();
1368 for buffer in buffers {
1369 this.buffers_being_formatted
1370 .remove(&buffer.read(cx).remote_id());
1371 }
1372 })
1373 .ok();
1374 }
1375 });
1376 let mut project_transaction = ProjectTransaction::default();
1377
1378 for buffer in &buffers {
1379 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1380 buffer.update(cx, |buffer, cx| {
1381 lsp_store
1382 .as_local()
1383 .unwrap()
1384 .language_servers_for_buffer(buffer, cx)
1385 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1386 .collect::<Vec<_>>()
1387 })
1388 })?;
1389 for (_, language_server) in adapters_and_servers.iter() {
1390 let actions = Self::get_server_code_actions_from_action_kinds(
1391 &lsp_store,
1392 language_server.server_id(),
1393 vec![kind.clone()],
1394 buffer,
1395 cx,
1396 )
1397 .await?;
1398 Self::execute_code_actions_on_server(
1399 &lsp_store,
1400 language_server,
1401 actions,
1402 push_to_history,
1403 &mut project_transaction,
1404 cx,
1405 )
1406 .await?;
1407 }
1408 }
1409 Ok(project_transaction)
1410 }
1411
1412 async fn format_locally(
1413 lsp_store: WeakEntity<LspStore>,
1414 mut buffers: Vec<FormattableBuffer>,
1415 push_to_history: bool,
1416 trigger: FormatTrigger,
1417 logger: zlog::Logger,
1418 cx: &mut AsyncApp,
1419 ) -> anyhow::Result<ProjectTransaction> {
1420 // Do not allow multiple concurrent formatting requests for the
1421 // same buffer.
1422 lsp_store.update(cx, |this, cx| {
1423 let this = this.as_local_mut().unwrap();
1424 buffers.retain(|buffer| {
1425 this.buffers_being_formatted
1426 .insert(buffer.handle.read(cx).remote_id())
1427 });
1428 })?;
1429
1430 let _cleanup = defer({
1431 let this = lsp_store.clone();
1432 let mut cx = cx.clone();
1433 let buffers = &buffers;
1434 move || {
1435 this.update(&mut cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 for buffer in buffers {
1438 this.buffers_being_formatted
1439 .remove(&buffer.handle.read(cx).remote_id());
1440 }
1441 })
1442 .ok();
1443 }
1444 });
1445
1446 let mut project_transaction = ProjectTransaction::default();
1447
1448 for buffer in &buffers {
1449 zlog::debug!(
1450 logger =>
1451 "formatting buffer '{:?}'",
1452 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1453 );
1454 // Create an empty transaction to hold all of the formatting edits.
1455 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1456 // ensure no transactions created while formatting are
1457 // grouped with the previous transaction in the history
1458 // based on the transaction group interval
1459 buffer.finalize_last_transaction();
1460 buffer
1461 .start_transaction()
1462 .context("transaction already open")?;
1463 buffer.end_transaction(cx);
1464 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1465 buffer.finalize_last_transaction();
1466 anyhow::Ok(transaction_id)
1467 })?;
1468
1469 let result = Self::format_buffer_locally(
1470 lsp_store.clone(),
1471 buffer,
1472 formatting_transaction_id,
1473 trigger,
1474 logger,
1475 cx,
1476 )
1477 .await;
1478
1479 buffer.handle.update(cx, |buffer, cx| {
1480 let Some(formatting_transaction) =
1481 buffer.get_transaction(formatting_transaction_id).cloned()
1482 else {
1483 zlog::warn!(logger => "no formatting transaction");
1484 return;
1485 };
1486 if formatting_transaction.edit_ids.is_empty() {
1487 zlog::debug!(logger => "no changes made while formatting");
1488 buffer.forget_transaction(formatting_transaction_id);
1489 return;
1490 }
1491 if !push_to_history {
1492 zlog::trace!(logger => "forgetting format transaction");
1493 buffer.forget_transaction(formatting_transaction.id);
1494 }
1495 project_transaction
1496 .0
1497 .insert(cx.entity(), formatting_transaction);
1498 });
1499
1500 result?;
1501 }
1502
1503 Ok(project_transaction)
1504 }
1505
1506 async fn format_buffer_locally(
1507 lsp_store: WeakEntity<LspStore>,
1508 buffer: &FormattableBuffer,
1509 formatting_transaction_id: clock::Lamport,
1510 trigger: FormatTrigger,
1511 logger: zlog::Logger,
1512 cx: &mut AsyncApp,
1513 ) -> Result<()> {
1514 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1515 buffer.handle.update(cx, |buffer, cx| {
1516 let adapters_and_servers = lsp_store
1517 .as_local()
1518 .unwrap()
1519 .language_servers_for_buffer(buffer, cx)
1520 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1521 .collect::<Vec<_>>();
1522 let settings =
1523 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1524 .into_owned();
1525 (adapters_and_servers, settings)
1526 })
1527 })?;
1528
1529 /// Apply edits to the buffer that will become part of the formatting transaction.
1530 /// Fails if the buffer has been edited since the start of that transaction.
1531 fn extend_formatting_transaction(
1532 buffer: &FormattableBuffer,
1533 formatting_transaction_id: text::TransactionId,
1534 cx: &mut AsyncApp,
1535 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1536 ) -> anyhow::Result<()> {
1537 buffer.handle.update(cx, |buffer, cx| {
1538 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1539 if last_transaction_id != Some(formatting_transaction_id) {
1540 anyhow::bail!("Buffer edited while formatting. Aborting")
1541 }
1542 buffer.start_transaction();
1543 operation(buffer, cx);
1544 if let Some(transaction_id) = buffer.end_transaction(cx) {
1545 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1546 }
1547 Ok(())
1548 })
1549 }
1550
1551 // handle whitespace formatting
1552 if settings.remove_trailing_whitespace_on_save {
1553 zlog::trace!(logger => "removing trailing whitespace");
1554 let diff = buffer
1555 .handle
1556 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1557 .await;
1558 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1559 buffer.apply_diff(diff, cx);
1560 })?;
1561 }
1562
1563 if settings.ensure_final_newline_on_save {
1564 zlog::trace!(logger => "ensuring final newline");
1565 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1566 buffer.ensure_final_newline(cx);
1567 })?;
1568 }
1569
1570 // Formatter for `code_actions_on_format` that runs before
1571 // the rest of the formatters
1572 let mut code_actions_on_format_formatters = None;
1573 let should_run_code_actions_on_format = !matches!(
1574 (trigger, &settings.format_on_save),
1575 (FormatTrigger::Save, &FormatOnSave::Off)
1576 );
1577 if should_run_code_actions_on_format {
1578 let have_code_actions_to_run_on_format = settings
1579 .code_actions_on_format
1580 .values()
1581 .any(|enabled| *enabled);
1582 if have_code_actions_to_run_on_format {
1583 zlog::trace!(logger => "going to run code actions on format");
1584 code_actions_on_format_formatters = Some(
1585 settings
1586 .code_actions_on_format
1587 .iter()
1588 .filter_map(|(action, enabled)| enabled.then_some(action))
1589 .cloned()
1590 .map(Formatter::CodeAction)
1591 .collect::<Vec<_>>(),
1592 );
1593 }
1594 }
1595
1596 let formatters = match (trigger, &settings.format_on_save) {
1597 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1598 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1599 settings.formatter.as_ref()
1600 }
1601 };
1602
1603 let formatters = code_actions_on_format_formatters
1604 .iter()
1605 .flatten()
1606 .chain(formatters);
1607
1608 for formatter in formatters {
1609 let formatter = if formatter == &Formatter::Auto {
1610 if settings.prettier.allowed {
1611 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1612 &Formatter::Prettier
1613 } else {
1614 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1615 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1616 }
1617 } else {
1618 formatter
1619 };
1620 match formatter {
1621 Formatter::Auto => unreachable!("Auto resolved above"),
1622 Formatter::Prettier => {
1623 let logger = zlog::scoped!(logger => "prettier");
1624 zlog::trace!(logger => "formatting");
1625 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1626
1627 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1628 lsp_store.prettier_store().unwrap().downgrade()
1629 })?;
1630 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1631 .await
1632 .transpose()?;
1633 let Some(diff) = diff else {
1634 zlog::trace!(logger => "No changes");
1635 continue;
1636 };
1637
1638 extend_formatting_transaction(
1639 buffer,
1640 formatting_transaction_id,
1641 cx,
1642 |buffer, cx| {
1643 buffer.apply_diff(diff, cx);
1644 },
1645 )?;
1646 }
1647 Formatter::External { command, arguments } => {
1648 let logger = zlog::scoped!(logger => "command");
1649 zlog::trace!(logger => "formatting");
1650 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1651
1652 let diff = Self::format_via_external_command(
1653 buffer,
1654 &command,
1655 arguments.as_deref(),
1656 cx,
1657 )
1658 .await
1659 .with_context(|| {
1660 format!("Failed to format buffer via external command: {}", command)
1661 })?;
1662 let Some(diff) = diff else {
1663 zlog::trace!(logger => "No changes");
1664 continue;
1665 };
1666
1667 extend_formatting_transaction(
1668 buffer,
1669 formatting_transaction_id,
1670 cx,
1671 |buffer, cx| {
1672 buffer.apply_diff(diff, cx);
1673 },
1674 )?;
1675 }
1676 Formatter::LanguageServer(specifier) => {
1677 let logger = zlog::scoped!(logger => "language-server");
1678 zlog::trace!(logger => "formatting");
1679 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1680
1681 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1682 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1683 continue;
1684 };
1685
1686 let language_server = match specifier {
1687 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1688 adapters_and_servers.iter().find_map(|(adapter, server)| {
1689 if adapter.name.0.as_ref() == name {
1690 Some(server.clone())
1691 } else {
1692 None
1693 }
1694 })
1695 }
1696 settings::LanguageServerFormatterSpecifier::Current => {
1697 adapters_and_servers.first().map(|e| e.1.clone())
1698 }
1699 };
1700
1701 let Some(language_server) = language_server else {
1702 log::debug!(
1703 "No language server found to format buffer '{:?}'. Skipping",
1704 buffer_path_abs.as_path().to_string_lossy()
1705 );
1706 continue;
1707 };
1708
1709 zlog::trace!(
1710 logger =>
1711 "Formatting buffer '{:?}' using language server '{:?}'",
1712 buffer_path_abs.as_path().to_string_lossy(),
1713 language_server.name()
1714 );
1715
1716 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1717 zlog::trace!(logger => "formatting ranges");
1718 Self::format_ranges_via_lsp(
1719 &lsp_store,
1720 &buffer.handle,
1721 ranges,
1722 buffer_path_abs,
1723 &language_server,
1724 &settings,
1725 cx,
1726 )
1727 .await
1728 .context("Failed to format ranges via language server")?
1729 } else {
1730 zlog::trace!(logger => "formatting full");
1731 Self::format_via_lsp(
1732 &lsp_store,
1733 &buffer.handle,
1734 buffer_path_abs,
1735 &language_server,
1736 &settings,
1737 cx,
1738 )
1739 .await
1740 .context("failed to format via language server")?
1741 };
1742
1743 if edits.is_empty() {
1744 zlog::trace!(logger => "No changes");
1745 continue;
1746 }
1747 extend_formatting_transaction(
1748 buffer,
1749 formatting_transaction_id,
1750 cx,
1751 |buffer, cx| {
1752 buffer.edit(edits, None, cx);
1753 },
1754 )?;
1755 }
1756 Formatter::CodeAction(code_action_name) => {
1757 let logger = zlog::scoped!(logger => "code-actions");
1758 zlog::trace!(logger => "formatting");
1759 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1760
1761 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1762 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1763 continue;
1764 };
1765
1766 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1767 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1768
1769 let mut actions_and_servers = Vec::new();
1770
1771 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1772 let actions_result = Self::get_server_code_actions_from_action_kinds(
1773 &lsp_store,
1774 language_server.server_id(),
1775 vec![code_action_kind.clone()],
1776 &buffer.handle,
1777 cx,
1778 )
1779 .await
1780 .with_context(|| {
1781 format!(
1782 "Failed to resolve code action {:?} with language server {}",
1783 code_action_kind,
1784 language_server.name()
1785 )
1786 });
1787 let Ok(actions) = actions_result else {
1788 // note: it may be better to set result to the error and break formatters here
1789 // but for now we try to execute the actions that we can resolve and skip the rest
1790 zlog::error!(
1791 logger =>
1792 "Failed to resolve code action {:?} with language server {}",
1793 code_action_kind,
1794 language_server.name()
1795 );
1796 continue;
1797 };
1798 for action in actions {
1799 actions_and_servers.push((action, index));
1800 }
1801 }
1802
1803 if actions_and_servers.is_empty() {
1804 zlog::warn!(logger => "No code actions were resolved, continuing");
1805 continue;
1806 }
1807
1808 'actions: for (mut action, server_index) in actions_and_servers {
1809 let server = &adapters_and_servers[server_index].1;
1810
1811 let describe_code_action = |action: &CodeAction| {
1812 format!(
1813 "code action '{}' with title \"{}\" on server {}",
1814 action
1815 .lsp_action
1816 .action_kind()
1817 .unwrap_or("unknown".into())
1818 .as_str(),
1819 action.lsp_action.title(),
1820 server.name(),
1821 )
1822 };
1823
1824 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1825
1826 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1827 zlog::error!(
1828 logger =>
1829 "Failed to resolve {}. Error: {}",
1830 describe_code_action(&action),
1831 err
1832 );
1833 continue;
1834 }
1835
1836 if let Some(edit) = action.lsp_action.edit().cloned() {
1837 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1838 // but filters out and logs warnings for code actions that require unreasonably
1839 // difficult handling on our part, such as:
1840 // - applying edits that call commands
1841 // which can result in arbitrary workspace edits being sent from the server that
1842 // have no way of being tied back to the command that initiated them (i.e. we
1843 // can't know which edits are part of the format request, or if the server is done sending
1844 // actions in response to the command)
1845 // - actions that create/delete/modify/rename files other than the one we are formatting
1846 // as we then would need to handle such changes correctly in the local history as well
1847 // as the remote history through the ProjectTransaction
1848 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1849 // Supporting these actions is not impossible, but not supported as of yet.
1850 if edit.changes.is_none() && edit.document_changes.is_none() {
1851 zlog::trace!(
1852 logger =>
1853 "No changes for code action. Skipping {}",
1854 describe_code_action(&action),
1855 );
1856 continue;
1857 }
1858
1859 let mut operations = Vec::new();
1860 if let Some(document_changes) = edit.document_changes {
1861 match document_changes {
1862 lsp::DocumentChanges::Edits(edits) => operations.extend(
1863 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1864 ),
1865 lsp::DocumentChanges::Operations(ops) => operations = ops,
1866 }
1867 } else if let Some(changes) = edit.changes {
1868 operations.extend(changes.into_iter().map(|(uri, edits)| {
1869 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1870 text_document:
1871 lsp::OptionalVersionedTextDocumentIdentifier {
1872 uri,
1873 version: None,
1874 },
1875 edits: edits.into_iter().map(Edit::Plain).collect(),
1876 })
1877 }));
1878 }
1879
1880 let mut edits = Vec::with_capacity(operations.len());
1881
1882 if operations.is_empty() {
1883 zlog::trace!(
1884 logger =>
1885 "No changes for code action. Skipping {}",
1886 describe_code_action(&action),
1887 );
1888 continue;
1889 }
1890 for operation in operations {
1891 let op = match operation {
1892 lsp::DocumentChangeOperation::Edit(op) => op,
1893 lsp::DocumentChangeOperation::Op(_) => {
1894 zlog::warn!(
1895 logger =>
1896 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1897 describe_code_action(&action),
1898 );
1899 continue 'actions;
1900 }
1901 };
1902 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1903 zlog::warn!(
1904 logger =>
1905 "Failed to convert URI '{:?}' to file path. Skipping {}",
1906 &op.text_document.uri,
1907 describe_code_action(&action),
1908 );
1909 continue 'actions;
1910 };
1911 if &file_path != buffer_path_abs {
1912 zlog::warn!(
1913 logger =>
1914 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1915 file_path,
1916 buffer_path_abs,
1917 describe_code_action(&action),
1918 );
1919 continue 'actions;
1920 }
1921
1922 let mut lsp_edits = Vec::new();
1923 for edit in op.edits {
1924 match edit {
1925 Edit::Plain(edit) => {
1926 if !lsp_edits.contains(&edit) {
1927 lsp_edits.push(edit);
1928 }
1929 }
1930 Edit::Annotated(edit) => {
1931 if !lsp_edits.contains(&edit.text_edit) {
1932 lsp_edits.push(edit.text_edit);
1933 }
1934 }
1935 Edit::Snippet(_) => {
1936 zlog::warn!(
1937 logger =>
1938 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1939 describe_code_action(&action),
1940 );
1941 continue 'actions;
1942 }
1943 }
1944 }
1945 let edits_result = lsp_store
1946 .update(cx, |lsp_store, cx| {
1947 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1948 &buffer.handle,
1949 lsp_edits,
1950 server.server_id(),
1951 op.text_document.version,
1952 cx,
1953 )
1954 })?
1955 .await;
1956 let Ok(resolved_edits) = edits_result else {
1957 zlog::warn!(
1958 logger =>
1959 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1960 buffer_path_abs.as_path(),
1961 describe_code_action(&action),
1962 );
1963 continue 'actions;
1964 };
1965 edits.extend(resolved_edits);
1966 }
1967
1968 if edits.is_empty() {
1969 zlog::warn!(logger => "No edits resolved from LSP");
1970 continue;
1971 }
1972
1973 extend_formatting_transaction(
1974 buffer,
1975 formatting_transaction_id,
1976 cx,
1977 |buffer, cx| {
1978 zlog::info!(
1979 "Applying edits {edits:?}. Content: {:?}",
1980 buffer.text()
1981 );
1982 buffer.edit(edits, None, cx);
1983 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1984 },
1985 )?;
1986 }
1987
1988 if let Some(command) = action.lsp_action.command() {
1989 zlog::warn!(
1990 logger =>
1991 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1992 &command.command,
1993 );
1994
1995 // bail early if command is invalid
1996 let server_capabilities = server.capabilities();
1997 let available_commands = server_capabilities
1998 .execute_command_provider
1999 .as_ref()
2000 .map(|options| options.commands.as_slice())
2001 .unwrap_or_default();
2002 if !available_commands.contains(&command.command) {
2003 zlog::warn!(
2004 logger =>
2005 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2006 command.command,
2007 server.name(),
2008 );
2009 continue;
2010 }
2011
2012 // noop so we just ensure buffer hasn't been edited since resolving code actions
2013 extend_formatting_transaction(
2014 buffer,
2015 formatting_transaction_id,
2016 cx,
2017 |_, _| {},
2018 )?;
2019 zlog::info!(logger => "Executing command {}", &command.command);
2020
2021 lsp_store.update(cx, |this, _| {
2022 this.as_local_mut()
2023 .unwrap()
2024 .last_workspace_edits_by_language_server
2025 .remove(&server.server_id());
2026 })?;
2027
2028 let execute_command_result = server
2029 .request::<lsp::request::ExecuteCommand>(
2030 lsp::ExecuteCommandParams {
2031 command: command.command.clone(),
2032 arguments: command.arguments.clone().unwrap_or_default(),
2033 ..Default::default()
2034 },
2035 )
2036 .await
2037 .into_response();
2038
2039 if execute_command_result.is_err() {
2040 zlog::error!(
2041 logger =>
2042 "Failed to execute command '{}' as part of {}",
2043 &command.command,
2044 describe_code_action(&action),
2045 );
2046 continue 'actions;
2047 }
2048
2049 let mut project_transaction_command =
2050 lsp_store.update(cx, |this, _| {
2051 this.as_local_mut()
2052 .unwrap()
2053 .last_workspace_edits_by_language_server
2054 .remove(&server.server_id())
2055 .unwrap_or_default()
2056 })?;
2057
2058 if let Some(transaction) =
2059 project_transaction_command.0.remove(&buffer.handle)
2060 {
2061 zlog::trace!(
2062 logger =>
2063 "Successfully captured {} edits that resulted from command {}",
2064 transaction.edit_ids.len(),
2065 &command.command,
2066 );
2067 let transaction_id_project_transaction = transaction.id;
2068 buffer.handle.update(cx, |buffer, _| {
2069 // it may have been removed from history if push_to_history was
2070 // false in deserialize_workspace_edit. If so push it so we
2071 // can merge it with the format transaction
2072 // and pop the combined transaction off the history stack
2073 // later if push_to_history is false
2074 if buffer.get_transaction(transaction.id).is_none() {
2075 buffer.push_transaction(transaction, Instant::now());
2076 }
2077 buffer.merge_transactions(
2078 transaction_id_project_transaction,
2079 formatting_transaction_id,
2080 );
2081 });
2082 }
2083
2084 if !project_transaction_command.0.is_empty() {
2085 let mut extra_buffers = String::new();
2086 for buffer in project_transaction_command.0.keys() {
2087 buffer.read_with(cx, |b, cx| {
2088 if let Some(path) = b.project_path(cx) {
2089 if !extra_buffers.is_empty() {
2090 extra_buffers.push_str(", ");
2091 }
2092 extra_buffers.push_str(path.path.as_unix_str());
2093 }
2094 });
2095 }
2096 zlog::warn!(
2097 logger =>
2098 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2099 &command.command,
2100 extra_buffers,
2101 );
2102 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2103 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2104 // add it so it's included, and merge it into the format transaction when its created later
2105 }
2106 }
2107 }
2108 }
2109 }
2110 }
2111
2112 Ok(())
2113 }
2114
2115 pub async fn format_ranges_via_lsp(
2116 this: &WeakEntity<LspStore>,
2117 buffer_handle: &Entity<Buffer>,
2118 ranges: &[Range<Anchor>],
2119 abs_path: &Path,
2120 language_server: &Arc<LanguageServer>,
2121 settings: &LanguageSettings,
2122 cx: &mut AsyncApp,
2123 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2124 let capabilities = &language_server.capabilities();
2125 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2126 if range_formatting_provider == Some(&OneOf::Left(false)) {
2127 anyhow::bail!(
2128 "{} language server does not support range formatting",
2129 language_server.name()
2130 );
2131 }
2132
2133 let uri = file_path_to_lsp_url(abs_path)?;
2134 let text_document = lsp::TextDocumentIdentifier::new(uri);
2135
2136 let lsp_edits = {
2137 let mut lsp_ranges = Vec::new();
2138 this.update(cx, |_this, cx| {
2139 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2140 // not have been sent to the language server. This seems like a fairly systemic
2141 // issue, though, the resolution probably is not specific to formatting.
2142 //
2143 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2144 // LSP.
2145 let snapshot = buffer_handle.read(cx).snapshot();
2146 for range in ranges {
2147 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2148 }
2149 anyhow::Ok(())
2150 })??;
2151
2152 let mut edits = None;
2153 for range in lsp_ranges {
2154 if let Some(mut edit) = language_server
2155 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2156 text_document: text_document.clone(),
2157 range,
2158 options: lsp_command::lsp_formatting_options(settings),
2159 work_done_progress_params: Default::default(),
2160 })
2161 .await
2162 .into_response()?
2163 {
2164 edits.get_or_insert_with(Vec::new).append(&mut edit);
2165 }
2166 }
2167 edits
2168 };
2169
2170 if let Some(lsp_edits) = lsp_edits {
2171 this.update(cx, |this, cx| {
2172 this.as_local_mut().unwrap().edits_from_lsp(
2173 buffer_handle,
2174 lsp_edits,
2175 language_server.server_id(),
2176 None,
2177 cx,
2178 )
2179 })?
2180 .await
2181 } else {
2182 Ok(Vec::with_capacity(0))
2183 }
2184 }
2185
2186 async fn format_via_lsp(
2187 this: &WeakEntity<LspStore>,
2188 buffer: &Entity<Buffer>,
2189 abs_path: &Path,
2190 language_server: &Arc<LanguageServer>,
2191 settings: &LanguageSettings,
2192 cx: &mut AsyncApp,
2193 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2194 let logger = zlog::scoped!("lsp_format");
2195 zlog::debug!(logger => "Formatting via LSP");
2196
2197 let uri = file_path_to_lsp_url(abs_path)?;
2198 let text_document = lsp::TextDocumentIdentifier::new(uri);
2199 let capabilities = &language_server.capabilities();
2200
2201 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2202 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2203
2204 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2205 let _timer = zlog::time!(logger => "format-full");
2206 language_server
2207 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2208 text_document,
2209 options: lsp_command::lsp_formatting_options(settings),
2210 work_done_progress_params: Default::default(),
2211 })
2212 .await
2213 .into_response()?
2214 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2215 let _timer = zlog::time!(logger => "format-range");
2216 let buffer_start = lsp::Position::new(0, 0);
2217 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2218 language_server
2219 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2220 text_document: text_document.clone(),
2221 range: lsp::Range::new(buffer_start, buffer_end),
2222 options: lsp_command::lsp_formatting_options(settings),
2223 work_done_progress_params: Default::default(),
2224 })
2225 .await
2226 .into_response()?
2227 } else {
2228 None
2229 };
2230
2231 if let Some(lsp_edits) = lsp_edits {
2232 this.update(cx, |this, cx| {
2233 this.as_local_mut().unwrap().edits_from_lsp(
2234 buffer,
2235 lsp_edits,
2236 language_server.server_id(),
2237 None,
2238 cx,
2239 )
2240 })?
2241 .await
2242 } else {
2243 Ok(Vec::with_capacity(0))
2244 }
2245 }
2246
2247 async fn format_via_external_command(
2248 buffer: &FormattableBuffer,
2249 command: &str,
2250 arguments: Option<&[String]>,
2251 cx: &mut AsyncApp,
2252 ) -> Result<Option<Diff>> {
2253 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2254 let file = File::from_dyn(buffer.file())?;
2255 let worktree = file.worktree.read(cx);
2256 let mut worktree_path = worktree.abs_path().to_path_buf();
2257 if worktree.root_entry()?.is_file() {
2258 worktree_path.pop();
2259 }
2260 Some(worktree_path)
2261 });
2262
2263 let mut child = util::command::new_smol_command(command);
2264
2265 if let Some(buffer_env) = buffer.env.as_ref() {
2266 child.envs(buffer_env);
2267 }
2268
2269 if let Some(working_dir_path) = working_dir_path {
2270 child.current_dir(working_dir_path);
2271 }
2272
2273 if let Some(arguments) = arguments {
2274 child.args(arguments.iter().map(|arg| {
2275 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2276 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2277 } else {
2278 arg.replace("{buffer_path}", "Untitled")
2279 }
2280 }));
2281 }
2282
2283 let mut child = child
2284 .stdin(smol::process::Stdio::piped())
2285 .stdout(smol::process::Stdio::piped())
2286 .stderr(smol::process::Stdio::piped())
2287 .spawn()?;
2288
2289 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2290 let text = buffer
2291 .handle
2292 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2293 for chunk in text.chunks() {
2294 stdin.write_all(chunk.as_bytes()).await?;
2295 }
2296 stdin.flush().await?;
2297
2298 let output = child.output().await?;
2299 anyhow::ensure!(
2300 output.status.success(),
2301 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2302 output.status.code(),
2303 String::from_utf8_lossy(&output.stdout),
2304 String::from_utf8_lossy(&output.stderr),
2305 );
2306
2307 let stdout = String::from_utf8(output.stdout)?;
2308 Ok(Some(
2309 buffer
2310 .handle
2311 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2312 .await,
2313 ))
2314 }
2315
2316 async fn try_resolve_code_action(
2317 lang_server: &LanguageServer,
2318 action: &mut CodeAction,
2319 ) -> anyhow::Result<()> {
2320 match &mut action.lsp_action {
2321 LspAction::Action(lsp_action) => {
2322 if !action.resolved
2323 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2324 && lsp_action.data.is_some()
2325 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2326 {
2327 **lsp_action = lang_server
2328 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2329 .await
2330 .into_response()?;
2331 }
2332 }
2333 LspAction::CodeLens(lens) => {
2334 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2335 *lens = lang_server
2336 .request::<lsp::request::CodeLensResolve>(lens.clone())
2337 .await
2338 .into_response()?;
2339 }
2340 }
2341 LspAction::Command(_) => {}
2342 }
2343
2344 action.resolved = true;
2345 anyhow::Ok(())
2346 }
2347
2348 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2349 let buffer = buffer_handle.read(cx);
2350
2351 let file = buffer.file().cloned();
2352
2353 let Some(file) = File::from_dyn(file.as_ref()) else {
2354 return;
2355 };
2356 if !file.is_local() {
2357 return;
2358 }
2359 let path = ProjectPath::from_file(file, cx);
2360 let worktree_id = file.worktree_id(cx);
2361 let language = buffer.language().cloned();
2362
2363 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2364 for (server_id, diagnostics) in
2365 diagnostics.get(file.path()).cloned().unwrap_or_default()
2366 {
2367 self.update_buffer_diagnostics(
2368 buffer_handle,
2369 server_id,
2370 None,
2371 None,
2372 None,
2373 Vec::new(),
2374 diagnostics,
2375 cx,
2376 )
2377 .log_err();
2378 }
2379 }
2380 let Some(language) = language else {
2381 return;
2382 };
2383 let Some(snapshot) = self
2384 .worktree_store
2385 .read(cx)
2386 .worktree_for_id(worktree_id, cx)
2387 .map(|worktree| worktree.read(cx).snapshot())
2388 else {
2389 return;
2390 };
2391 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2392
2393 for server_id in
2394 self.lsp_tree
2395 .get(path, language.name(), language.manifest(), &delegate, cx)
2396 {
2397 let server = self
2398 .language_servers
2399 .get(&server_id)
2400 .and_then(|server_state| {
2401 if let LanguageServerState::Running { server, .. } = server_state {
2402 Some(server.clone())
2403 } else {
2404 None
2405 }
2406 });
2407 let server = match server {
2408 Some(server) => server,
2409 None => continue,
2410 };
2411
2412 buffer_handle.update(cx, |buffer, cx| {
2413 buffer.set_completion_triggers(
2414 server.server_id(),
2415 server
2416 .capabilities()
2417 .completion_provider
2418 .as_ref()
2419 .and_then(|provider| {
2420 provider
2421 .trigger_characters
2422 .as_ref()
2423 .map(|characters| characters.iter().cloned().collect())
2424 })
2425 .unwrap_or_default(),
2426 cx,
2427 );
2428 });
2429 }
2430 }
2431
2432 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2433 buffer.update(cx, |buffer, cx| {
2434 let Some(language) = buffer.language() else {
2435 return;
2436 };
2437 let path = ProjectPath {
2438 worktree_id: old_file.worktree_id(cx),
2439 path: old_file.path.clone(),
2440 };
2441 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2442 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2443 buffer.set_completion_triggers(server_id, Default::default(), cx);
2444 }
2445 });
2446 }
2447
2448 fn update_buffer_diagnostics(
2449 &mut self,
2450 buffer: &Entity<Buffer>,
2451 server_id: LanguageServerId,
2452 registration_id: Option<Option<SharedString>>,
2453 result_id: Option<SharedString>,
2454 version: Option<i32>,
2455 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2456 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2457 cx: &mut Context<LspStore>,
2458 ) -> Result<()> {
2459 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2460 Ordering::Equal
2461 .then_with(|| b.is_primary.cmp(&a.is_primary))
2462 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2463 .then_with(|| a.severity.cmp(&b.severity))
2464 .then_with(|| a.message.cmp(&b.message))
2465 }
2466
2467 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2468 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2469 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2470
2471 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2472 Ordering::Equal
2473 .then_with(|| a.range.start.cmp(&b.range.start))
2474 .then_with(|| b.range.end.cmp(&a.range.end))
2475 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2476 });
2477
2478 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2479
2480 let edits_since_save = std::cell::LazyCell::new(|| {
2481 let saved_version = buffer.read(cx).saved_version();
2482 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2483 });
2484
2485 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2486
2487 for (new_diagnostic, entry) in diagnostics {
2488 let start;
2489 let end;
2490 if new_diagnostic && entry.diagnostic.is_disk_based {
2491 // Some diagnostics are based on files on disk instead of buffers'
2492 // current contents. Adjust these diagnostics' ranges to reflect
2493 // any unsaved edits.
2494 // Do not alter the reused ones though, as their coordinates were stored as anchors
2495 // and were properly adjusted on reuse.
2496 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2497 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2498 } else {
2499 start = entry.range.start;
2500 end = entry.range.end;
2501 }
2502
2503 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2504 ..snapshot.clip_point_utf16(end, Bias::Right);
2505
2506 // Expand empty ranges by one codepoint
2507 if range.start == range.end {
2508 // This will be go to the next boundary when being clipped
2509 range.end.column += 1;
2510 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2511 if range.start == range.end && range.end.column > 0 {
2512 range.start.column -= 1;
2513 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2514 }
2515 }
2516
2517 sanitized_diagnostics.push(DiagnosticEntry {
2518 range,
2519 diagnostic: entry.diagnostic,
2520 });
2521 }
2522 drop(edits_since_save);
2523
2524 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2525 buffer.update(cx, |buffer, cx| {
2526 if let Some(registration_id) = registration_id {
2527 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2528 self.buffer_pull_diagnostics_result_ids
2529 .entry(server_id)
2530 .or_default()
2531 .entry(registration_id)
2532 .or_default()
2533 .insert(abs_path, result_id);
2534 }
2535 }
2536
2537 buffer.update_diagnostics(server_id, set, cx)
2538 });
2539
2540 Ok(())
2541 }
2542
2543 fn register_language_server_for_invisible_worktree(
2544 &mut self,
2545 worktree: &Entity<Worktree>,
2546 language_server_id: LanguageServerId,
2547 cx: &mut App,
2548 ) {
2549 let worktree = worktree.read(cx);
2550 let worktree_id = worktree.id();
2551 debug_assert!(!worktree.is_visible());
2552 let Some(mut origin_seed) = self
2553 .language_server_ids
2554 .iter()
2555 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2556 else {
2557 return;
2558 };
2559 origin_seed.worktree_id = worktree_id;
2560 self.language_server_ids
2561 .entry(origin_seed)
2562 .or_insert_with(|| UnifiedLanguageServer {
2563 id: language_server_id,
2564 project_roots: Default::default(),
2565 });
2566 }
2567
2568 fn register_buffer_with_language_servers(
2569 &mut self,
2570 buffer_handle: &Entity<Buffer>,
2571 only_register_servers: HashSet<LanguageServerSelector>,
2572 cx: &mut Context<LspStore>,
2573 ) {
2574 let buffer = buffer_handle.read(cx);
2575 let buffer_id = buffer.remote_id();
2576
2577 let Some(file) = File::from_dyn(buffer.file()) else {
2578 return;
2579 };
2580 if !file.is_local() {
2581 return;
2582 }
2583
2584 let abs_path = file.abs_path(cx);
2585 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2586 return;
2587 };
2588 let initial_snapshot = buffer.text_snapshot();
2589 let worktree_id = file.worktree_id(cx);
2590
2591 let Some(language) = buffer.language().cloned() else {
2592 return;
2593 };
2594 let path: Arc<RelPath> = file
2595 .path()
2596 .parent()
2597 .map(Arc::from)
2598 .unwrap_or_else(|| file.path().clone());
2599 let Some(worktree) = self
2600 .worktree_store
2601 .read(cx)
2602 .worktree_for_id(worktree_id, cx)
2603 else {
2604 return;
2605 };
2606 let language_name = language.name();
2607 let (reused, delegate, servers) = self
2608 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2609 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2610 .unwrap_or_else(|| {
2611 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2612 let delegate: Arc<dyn ManifestDelegate> =
2613 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2614
2615 let servers = self
2616 .lsp_tree
2617 .walk(
2618 ProjectPath { worktree_id, path },
2619 language.name(),
2620 language.manifest(),
2621 &delegate,
2622 cx,
2623 )
2624 .collect::<Vec<_>>();
2625 (false, lsp_delegate, servers)
2626 });
2627 let servers_and_adapters = servers
2628 .into_iter()
2629 .filter_map(|server_node| {
2630 if reused && server_node.server_id().is_none() {
2631 return None;
2632 }
2633 if !only_register_servers.is_empty() {
2634 if let Some(server_id) = server_node.server_id()
2635 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2636 {
2637 return None;
2638 }
2639 if let Some(name) = server_node.name()
2640 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2641 {
2642 return None;
2643 }
2644 }
2645
2646 let server_id = server_node.server_id_or_init(|disposition| {
2647 let path = &disposition.path;
2648
2649 {
2650 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2651
2652 let server_id = self.get_or_insert_language_server(
2653 &worktree,
2654 delegate.clone(),
2655 disposition,
2656 &language_name,
2657 cx,
2658 );
2659
2660 if let Some(state) = self.language_servers.get(&server_id)
2661 && let Ok(uri) = uri
2662 {
2663 state.add_workspace_folder(uri);
2664 };
2665 server_id
2666 }
2667 })?;
2668 let server_state = self.language_servers.get(&server_id)?;
2669 if let LanguageServerState::Running {
2670 server, adapter, ..
2671 } = server_state
2672 {
2673 Some((server.clone(), adapter.clone()))
2674 } else {
2675 None
2676 }
2677 })
2678 .collect::<Vec<_>>();
2679 for (server, adapter) in servers_and_adapters {
2680 buffer_handle.update(cx, |buffer, cx| {
2681 buffer.set_completion_triggers(
2682 server.server_id(),
2683 server
2684 .capabilities()
2685 .completion_provider
2686 .as_ref()
2687 .and_then(|provider| {
2688 provider
2689 .trigger_characters
2690 .as_ref()
2691 .map(|characters| characters.iter().cloned().collect())
2692 })
2693 .unwrap_or_default(),
2694 cx,
2695 );
2696 });
2697
2698 let snapshot = LspBufferSnapshot {
2699 version: 0,
2700 snapshot: initial_snapshot.clone(),
2701 };
2702
2703 let mut registered = false;
2704 self.buffer_snapshots
2705 .entry(buffer_id)
2706 .or_default()
2707 .entry(server.server_id())
2708 .or_insert_with(|| {
2709 registered = true;
2710 server.register_buffer(
2711 uri.clone(),
2712 adapter.language_id(&language.name()),
2713 0,
2714 initial_snapshot.text(),
2715 );
2716
2717 vec![snapshot]
2718 });
2719
2720 self.buffers_opened_in_servers
2721 .entry(buffer_id)
2722 .or_default()
2723 .insert(server.server_id());
2724 if registered {
2725 cx.emit(LspStoreEvent::LanguageServerUpdate {
2726 language_server_id: server.server_id(),
2727 name: None,
2728 message: proto::update_language_server::Variant::RegisteredForBuffer(
2729 proto::RegisteredForBuffer {
2730 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2731 buffer_id: buffer_id.to_proto(),
2732 },
2733 ),
2734 });
2735 }
2736 }
2737 }
2738
2739 fn reuse_existing_language_server<'lang_name>(
2740 &self,
2741 server_tree: &LanguageServerTree,
2742 worktree: &Entity<Worktree>,
2743 language_name: &'lang_name LanguageName,
2744 cx: &mut App,
2745 ) -> Option<(
2746 Arc<LocalLspAdapterDelegate>,
2747 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2748 )> {
2749 if worktree.read(cx).is_visible() {
2750 return None;
2751 }
2752
2753 let worktree_store = self.worktree_store.read(cx);
2754 let servers = server_tree
2755 .instances
2756 .iter()
2757 .filter(|(worktree_id, _)| {
2758 worktree_store
2759 .worktree_for_id(**worktree_id, cx)
2760 .is_some_and(|worktree| worktree.read(cx).is_visible())
2761 })
2762 .flat_map(|(worktree_id, servers)| {
2763 servers
2764 .roots
2765 .iter()
2766 .flat_map(|(_, language_servers)| language_servers)
2767 .map(move |(_, (server_node, server_languages))| {
2768 (worktree_id, server_node, server_languages)
2769 })
2770 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2771 .map(|(worktree_id, server_node, _)| {
2772 (
2773 *worktree_id,
2774 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2775 )
2776 })
2777 })
2778 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2779 acc.entry(worktree_id)
2780 .or_insert_with(Vec::new)
2781 .push(server_node);
2782 acc
2783 })
2784 .into_values()
2785 .max_by_key(|servers| servers.len())?;
2786
2787 let worktree_id = worktree.read(cx).id();
2788 let apply = move |tree: &mut LanguageServerTree| {
2789 for server_node in &servers {
2790 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2791 }
2792 servers
2793 };
2794
2795 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2796 Some((delegate, apply))
2797 }
2798
2799 pub(crate) fn unregister_old_buffer_from_language_servers(
2800 &mut self,
2801 buffer: &Entity<Buffer>,
2802 old_file: &File,
2803 cx: &mut App,
2804 ) {
2805 let old_path = match old_file.as_local() {
2806 Some(local) => local.abs_path(cx),
2807 None => return,
2808 };
2809
2810 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2811 debug_panic!("{old_path:?} is not parseable as an URI");
2812 return;
2813 };
2814 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2815 }
2816
2817 pub(crate) fn unregister_buffer_from_language_servers(
2818 &mut self,
2819 buffer: &Entity<Buffer>,
2820 file_url: &lsp::Uri,
2821 cx: &mut App,
2822 ) {
2823 buffer.update(cx, |buffer, cx| {
2824 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2825
2826 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2827 if snapshots
2828 .as_mut()
2829 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2830 {
2831 language_server.unregister_buffer(file_url.clone());
2832 }
2833 }
2834 });
2835 }
2836
2837 fn buffer_snapshot_for_lsp_version(
2838 &mut self,
2839 buffer: &Entity<Buffer>,
2840 server_id: LanguageServerId,
2841 version: Option<i32>,
2842 cx: &App,
2843 ) -> Result<TextBufferSnapshot> {
2844 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2845
2846 if let Some(version) = version {
2847 let buffer_id = buffer.read(cx).remote_id();
2848 let snapshots = if let Some(snapshots) = self
2849 .buffer_snapshots
2850 .get_mut(&buffer_id)
2851 .and_then(|m| m.get_mut(&server_id))
2852 {
2853 snapshots
2854 } else if version == 0 {
2855 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2856 // We detect this case and treat it as if the version was `None`.
2857 return Ok(buffer.read(cx).text_snapshot());
2858 } else {
2859 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2860 };
2861
2862 let found_snapshot = snapshots
2863 .binary_search_by_key(&version, |e| e.version)
2864 .map(|ix| snapshots[ix].snapshot.clone())
2865 .map_err(|_| {
2866 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2867 })?;
2868
2869 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2870 Ok(found_snapshot)
2871 } else {
2872 Ok((buffer.read(cx)).text_snapshot())
2873 }
2874 }
2875
2876 async fn get_server_code_actions_from_action_kinds(
2877 lsp_store: &WeakEntity<LspStore>,
2878 language_server_id: LanguageServerId,
2879 code_action_kinds: Vec<lsp::CodeActionKind>,
2880 buffer: &Entity<Buffer>,
2881 cx: &mut AsyncApp,
2882 ) -> Result<Vec<CodeAction>> {
2883 let actions = lsp_store
2884 .update(cx, move |this, cx| {
2885 let request = GetCodeActions {
2886 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2887 kinds: Some(code_action_kinds),
2888 };
2889 let server = LanguageServerToQuery::Other(language_server_id);
2890 this.request_lsp(buffer.clone(), server, request, cx)
2891 })?
2892 .await?;
2893 Ok(actions)
2894 }
2895
2896 pub async fn execute_code_actions_on_server(
2897 lsp_store: &WeakEntity<LspStore>,
2898 language_server: &Arc<LanguageServer>,
2899
2900 actions: Vec<CodeAction>,
2901 push_to_history: bool,
2902 project_transaction: &mut ProjectTransaction,
2903 cx: &mut AsyncApp,
2904 ) -> anyhow::Result<()> {
2905 for mut action in actions {
2906 Self::try_resolve_code_action(language_server, &mut action)
2907 .await
2908 .context("resolving a formatting code action")?;
2909
2910 if let Some(edit) = action.lsp_action.edit() {
2911 if edit.changes.is_none() && edit.document_changes.is_none() {
2912 continue;
2913 }
2914
2915 let new = Self::deserialize_workspace_edit(
2916 lsp_store.upgrade().context("project dropped")?,
2917 edit.clone(),
2918 push_to_history,
2919 language_server.clone(),
2920 cx,
2921 )
2922 .await?;
2923 project_transaction.0.extend(new.0);
2924 }
2925
2926 if let Some(command) = action.lsp_action.command() {
2927 let server_capabilities = language_server.capabilities();
2928 let available_commands = server_capabilities
2929 .execute_command_provider
2930 .as_ref()
2931 .map(|options| options.commands.as_slice())
2932 .unwrap_or_default();
2933 if available_commands.contains(&command.command) {
2934 lsp_store.update(cx, |lsp_store, _| {
2935 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2936 mode.last_workspace_edits_by_language_server
2937 .remove(&language_server.server_id());
2938 }
2939 })?;
2940
2941 language_server
2942 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2943 command: command.command.clone(),
2944 arguments: command.arguments.clone().unwrap_or_default(),
2945 ..Default::default()
2946 })
2947 .await
2948 .into_response()
2949 .context("execute command")?;
2950
2951 lsp_store.update(cx, |this, _| {
2952 if let LspStoreMode::Local(mode) = &mut this.mode {
2953 project_transaction.0.extend(
2954 mode.last_workspace_edits_by_language_server
2955 .remove(&language_server.server_id())
2956 .unwrap_or_default()
2957 .0,
2958 )
2959 }
2960 })?;
2961 } else {
2962 log::warn!(
2963 "Cannot execute a command {} not listed in the language server capabilities",
2964 command.command
2965 )
2966 }
2967 }
2968 }
2969 Ok(())
2970 }
2971
2972 pub async fn deserialize_text_edits(
2973 this: Entity<LspStore>,
2974 buffer_to_edit: Entity<Buffer>,
2975 edits: Vec<lsp::TextEdit>,
2976 push_to_history: bool,
2977 _: Arc<CachedLspAdapter>,
2978 language_server: Arc<LanguageServer>,
2979 cx: &mut AsyncApp,
2980 ) -> Result<Option<Transaction>> {
2981 let edits = this
2982 .update(cx, |this, cx| {
2983 this.as_local_mut().unwrap().edits_from_lsp(
2984 &buffer_to_edit,
2985 edits,
2986 language_server.server_id(),
2987 None,
2988 cx,
2989 )
2990 })
2991 .await?;
2992
2993 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2994 buffer.finalize_last_transaction();
2995 buffer.start_transaction();
2996 for (range, text) in edits {
2997 buffer.edit([(range, text)], None, cx);
2998 }
2999
3000 if buffer.end_transaction(cx).is_some() {
3001 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3002 if !push_to_history {
3003 buffer.forget_transaction(transaction.id);
3004 }
3005 Some(transaction)
3006 } else {
3007 None
3008 }
3009 });
3010
3011 Ok(transaction)
3012 }
3013
3014 #[allow(clippy::type_complexity)]
3015 pub fn edits_from_lsp(
3016 &mut self,
3017 buffer: &Entity<Buffer>,
3018 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3019 server_id: LanguageServerId,
3020 version: Option<i32>,
3021 cx: &mut Context<LspStore>,
3022 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3023 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3024 cx.background_spawn(async move {
3025 let snapshot = snapshot?;
3026 let mut lsp_edits = lsp_edits
3027 .into_iter()
3028 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3029 .collect::<Vec<_>>();
3030
3031 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3032
3033 let mut lsp_edits = lsp_edits.into_iter().peekable();
3034 let mut edits = Vec::new();
3035 while let Some((range, mut new_text)) = lsp_edits.next() {
3036 // Clip invalid ranges provided by the language server.
3037 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3038 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3039
3040 // Combine any LSP edits that are adjacent.
3041 //
3042 // Also, combine LSP edits that are separated from each other by only
3043 // a newline. This is important because for some code actions,
3044 // Rust-analyzer rewrites the entire buffer via a series of edits that
3045 // are separated by unchanged newline characters.
3046 //
3047 // In order for the diffing logic below to work properly, any edits that
3048 // cancel each other out must be combined into one.
3049 while let Some((next_range, next_text)) = lsp_edits.peek() {
3050 if next_range.start.0 > range.end {
3051 if next_range.start.0.row > range.end.row + 1
3052 || next_range.start.0.column > 0
3053 || snapshot.clip_point_utf16(
3054 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3055 Bias::Left,
3056 ) > range.end
3057 {
3058 break;
3059 }
3060 new_text.push('\n');
3061 }
3062 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3063 new_text.push_str(next_text);
3064 lsp_edits.next();
3065 }
3066
3067 // For multiline edits, perform a diff of the old and new text so that
3068 // we can identify the changes more precisely, preserving the locations
3069 // of any anchors positioned in the unchanged regions.
3070 if range.end.row > range.start.row {
3071 let offset = range.start.to_offset(&snapshot);
3072 let old_text = snapshot.text_for_range(range).collect::<String>();
3073 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3074 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3075 (
3076 snapshot.anchor_after(offset + range.start)
3077 ..snapshot.anchor_before(offset + range.end),
3078 replacement,
3079 )
3080 }));
3081 } else if range.end == range.start {
3082 let anchor = snapshot.anchor_after(range.start);
3083 edits.push((anchor..anchor, new_text.into()));
3084 } else {
3085 let edit_start = snapshot.anchor_after(range.start);
3086 let edit_end = snapshot.anchor_before(range.end);
3087 edits.push((edit_start..edit_end, new_text.into()));
3088 }
3089 }
3090
3091 Ok(edits)
3092 })
3093 }
3094
3095 pub(crate) async fn deserialize_workspace_edit(
3096 this: Entity<LspStore>,
3097 edit: lsp::WorkspaceEdit,
3098 push_to_history: bool,
3099 language_server: Arc<LanguageServer>,
3100 cx: &mut AsyncApp,
3101 ) -> Result<ProjectTransaction> {
3102 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3103
3104 let mut operations = Vec::new();
3105 if let Some(document_changes) = edit.document_changes {
3106 match document_changes {
3107 lsp::DocumentChanges::Edits(edits) => {
3108 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3109 }
3110 lsp::DocumentChanges::Operations(ops) => operations = ops,
3111 }
3112 } else if let Some(changes) = edit.changes {
3113 operations.extend(changes.into_iter().map(|(uri, edits)| {
3114 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3115 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3116 uri,
3117 version: None,
3118 },
3119 edits: edits.into_iter().map(Edit::Plain).collect(),
3120 })
3121 }));
3122 }
3123
3124 let mut project_transaction = ProjectTransaction::default();
3125 for operation in operations {
3126 match operation {
3127 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3128 let abs_path = op
3129 .uri
3130 .to_file_path()
3131 .map_err(|()| anyhow!("can't convert URI to path"))?;
3132
3133 if let Some(parent_path) = abs_path.parent() {
3134 fs.create_dir(parent_path).await?;
3135 }
3136 if abs_path.ends_with("/") {
3137 fs.create_dir(&abs_path).await?;
3138 } else {
3139 fs.create_file(
3140 &abs_path,
3141 op.options
3142 .map(|options| fs::CreateOptions {
3143 overwrite: options.overwrite.unwrap_or(false),
3144 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3145 })
3146 .unwrap_or_default(),
3147 )
3148 .await?;
3149 }
3150 }
3151
3152 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3153 let source_abs_path = op
3154 .old_uri
3155 .to_file_path()
3156 .map_err(|()| anyhow!("can't convert URI to path"))?;
3157 let target_abs_path = op
3158 .new_uri
3159 .to_file_path()
3160 .map_err(|()| anyhow!("can't convert URI to path"))?;
3161
3162 let options = fs::RenameOptions {
3163 overwrite: op
3164 .options
3165 .as_ref()
3166 .and_then(|options| options.overwrite)
3167 .unwrap_or(false),
3168 ignore_if_exists: op
3169 .options
3170 .as_ref()
3171 .and_then(|options| options.ignore_if_exists)
3172 .unwrap_or(false),
3173 create_parents: true,
3174 };
3175
3176 fs.rename(&source_abs_path, &target_abs_path, options)
3177 .await?;
3178 }
3179
3180 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3181 let abs_path = op
3182 .uri
3183 .to_file_path()
3184 .map_err(|()| anyhow!("can't convert URI to path"))?;
3185 let options = op
3186 .options
3187 .map(|options| fs::RemoveOptions {
3188 recursive: options.recursive.unwrap_or(false),
3189 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3190 })
3191 .unwrap_or_default();
3192 if abs_path.ends_with("/") {
3193 fs.remove_dir(&abs_path, options).await?;
3194 } else {
3195 fs.remove_file(&abs_path, options).await?;
3196 }
3197 }
3198
3199 lsp::DocumentChangeOperation::Edit(op) => {
3200 let buffer_to_edit = this
3201 .update(cx, |this, cx| {
3202 this.open_local_buffer_via_lsp(
3203 op.text_document.uri.clone(),
3204 language_server.server_id(),
3205 cx,
3206 )
3207 })
3208 .await?;
3209
3210 let edits = this
3211 .update(cx, |this, cx| {
3212 let path = buffer_to_edit.read(cx).project_path(cx);
3213 let active_entry = this.active_entry;
3214 let is_active_entry = path.is_some_and(|project_path| {
3215 this.worktree_store
3216 .read(cx)
3217 .entry_for_path(&project_path, cx)
3218 .is_some_and(|entry| Some(entry.id) == active_entry)
3219 });
3220 let local = this.as_local_mut().unwrap();
3221
3222 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3223 for edit in op.edits {
3224 match edit {
3225 Edit::Plain(edit) => {
3226 if !edits.contains(&edit) {
3227 edits.push(edit)
3228 }
3229 }
3230 Edit::Annotated(edit) => {
3231 if !edits.contains(&edit.text_edit) {
3232 edits.push(edit.text_edit)
3233 }
3234 }
3235 Edit::Snippet(edit) => {
3236 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3237 else {
3238 continue;
3239 };
3240
3241 if is_active_entry {
3242 snippet_edits.push((edit.range, snippet));
3243 } else {
3244 // Since this buffer is not focused, apply a normal edit.
3245 let new_edit = TextEdit {
3246 range: edit.range,
3247 new_text: snippet.text,
3248 };
3249 if !edits.contains(&new_edit) {
3250 edits.push(new_edit);
3251 }
3252 }
3253 }
3254 }
3255 }
3256 if !snippet_edits.is_empty() {
3257 let buffer_id = buffer_to_edit.read(cx).remote_id();
3258 let version = if let Some(buffer_version) = op.text_document.version
3259 {
3260 local
3261 .buffer_snapshot_for_lsp_version(
3262 &buffer_to_edit,
3263 language_server.server_id(),
3264 Some(buffer_version),
3265 cx,
3266 )
3267 .ok()
3268 .map(|snapshot| snapshot.version)
3269 } else {
3270 Some(buffer_to_edit.read(cx).saved_version().clone())
3271 };
3272
3273 let most_recent_edit =
3274 version.and_then(|version| version.most_recent());
3275 // Check if the edit that triggered that edit has been made by this participant.
3276
3277 if let Some(most_recent_edit) = most_recent_edit {
3278 cx.emit(LspStoreEvent::SnippetEdit {
3279 buffer_id,
3280 edits: snippet_edits,
3281 most_recent_edit,
3282 });
3283 }
3284 }
3285
3286 local.edits_from_lsp(
3287 &buffer_to_edit,
3288 edits,
3289 language_server.server_id(),
3290 op.text_document.version,
3291 cx,
3292 )
3293 })
3294 .await?;
3295
3296 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3297 buffer.finalize_last_transaction();
3298 buffer.start_transaction();
3299 for (range, text) in edits {
3300 buffer.edit([(range, text)], None, cx);
3301 }
3302
3303 buffer.end_transaction(cx).and_then(|transaction_id| {
3304 if push_to_history {
3305 buffer.finalize_last_transaction();
3306 buffer.get_transaction(transaction_id).cloned()
3307 } else {
3308 buffer.forget_transaction(transaction_id)
3309 }
3310 })
3311 });
3312 if let Some(transaction) = transaction {
3313 project_transaction.0.insert(buffer_to_edit, transaction);
3314 }
3315 }
3316 }
3317 }
3318
3319 Ok(project_transaction)
3320 }
3321
3322 async fn on_lsp_workspace_edit(
3323 this: WeakEntity<LspStore>,
3324 params: lsp::ApplyWorkspaceEditParams,
3325 server_id: LanguageServerId,
3326 cx: &mut AsyncApp,
3327 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3328 let this = this.upgrade().context("project project closed")?;
3329 let language_server = this
3330 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3331 .context("language server not found")?;
3332 let transaction = Self::deserialize_workspace_edit(
3333 this.clone(),
3334 params.edit,
3335 true,
3336 language_server.clone(),
3337 cx,
3338 )
3339 .await
3340 .log_err();
3341 this.update(cx, |this, cx| {
3342 if let Some(transaction) = transaction {
3343 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3344
3345 this.as_local_mut()
3346 .unwrap()
3347 .last_workspace_edits_by_language_server
3348 .insert(server_id, transaction);
3349 }
3350 });
3351 Ok(lsp::ApplyWorkspaceEditResponse {
3352 applied: true,
3353 failed_change: None,
3354 failure_reason: None,
3355 })
3356 }
3357
3358 fn remove_worktree(
3359 &mut self,
3360 id_to_remove: WorktreeId,
3361 cx: &mut Context<LspStore>,
3362 ) -> Vec<LanguageServerId> {
3363 self.restricted_worktrees_tasks.remove(&id_to_remove);
3364 self.diagnostics.remove(&id_to_remove);
3365 self.prettier_store.update(cx, |prettier_store, cx| {
3366 prettier_store.remove_worktree(id_to_remove, cx);
3367 });
3368
3369 let mut servers_to_remove = BTreeSet::default();
3370 let mut servers_to_preserve = HashSet::default();
3371 for (seed, state) in &self.language_server_ids {
3372 if seed.worktree_id == id_to_remove {
3373 servers_to_remove.insert(state.id);
3374 } else {
3375 servers_to_preserve.insert(state.id);
3376 }
3377 }
3378 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3379 self.language_server_ids
3380 .retain(|_, state| !servers_to_remove.contains(&state.id));
3381 for server_id_to_remove in &servers_to_remove {
3382 self.language_server_watched_paths
3383 .remove(server_id_to_remove);
3384 self.language_server_paths_watched_for_rename
3385 .remove(server_id_to_remove);
3386 self.last_workspace_edits_by_language_server
3387 .remove(server_id_to_remove);
3388 self.language_servers.remove(server_id_to_remove);
3389 self.buffer_pull_diagnostics_result_ids
3390 .remove(server_id_to_remove);
3391 self.workspace_pull_diagnostics_result_ids
3392 .remove(server_id_to_remove);
3393 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3394 buffer_servers.remove(server_id_to_remove);
3395 }
3396 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3397 }
3398 servers_to_remove.into_iter().collect()
3399 }
3400
3401 fn rebuild_watched_paths_inner<'a>(
3402 &'a self,
3403 language_server_id: LanguageServerId,
3404 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3405 cx: &mut Context<LspStore>,
3406 ) -> LanguageServerWatchedPathsBuilder {
3407 let worktrees = self
3408 .worktree_store
3409 .read(cx)
3410 .worktrees()
3411 .filter_map(|worktree| {
3412 self.language_servers_for_worktree(worktree.read(cx).id())
3413 .find(|server| server.server_id() == language_server_id)
3414 .map(|_| worktree)
3415 })
3416 .collect::<Vec<_>>();
3417
3418 let mut worktree_globs = HashMap::default();
3419 let mut abs_globs = HashMap::default();
3420 log::trace!(
3421 "Processing new watcher paths for language server with id {}",
3422 language_server_id
3423 );
3424
3425 for watcher in watchers {
3426 if let Some((worktree, literal_prefix, pattern)) =
3427 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3428 {
3429 worktree.update(cx, |worktree, _| {
3430 if let Some((tree, glob)) =
3431 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3432 {
3433 tree.add_path_prefix_to_scan(literal_prefix);
3434 worktree_globs
3435 .entry(tree.id())
3436 .or_insert_with(GlobSetBuilder::new)
3437 .add(glob);
3438 }
3439 });
3440 } else {
3441 let (path, pattern) = match &watcher.glob_pattern {
3442 lsp::GlobPattern::String(s) => {
3443 let watcher_path = SanitizedPath::new(s);
3444 let path = glob_literal_prefix(watcher_path.as_path());
3445 let pattern = watcher_path
3446 .as_path()
3447 .strip_prefix(&path)
3448 .map(|p| p.to_string_lossy().into_owned())
3449 .unwrap_or_else(|e| {
3450 debug_panic!(
3451 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3452 s,
3453 path.display(),
3454 e
3455 );
3456 watcher_path.as_path().to_string_lossy().into_owned()
3457 });
3458 (path, pattern)
3459 }
3460 lsp::GlobPattern::Relative(rp) => {
3461 let Ok(mut base_uri) = match &rp.base_uri {
3462 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3463 lsp::OneOf::Right(base_uri) => base_uri,
3464 }
3465 .to_file_path() else {
3466 continue;
3467 };
3468
3469 let path = glob_literal_prefix(Path::new(&rp.pattern));
3470 let pattern = Path::new(&rp.pattern)
3471 .strip_prefix(&path)
3472 .map(|p| p.to_string_lossy().into_owned())
3473 .unwrap_or_else(|e| {
3474 debug_panic!(
3475 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3476 rp.pattern,
3477 path.display(),
3478 e
3479 );
3480 rp.pattern.clone()
3481 });
3482 base_uri.push(path);
3483 (base_uri, pattern)
3484 }
3485 };
3486
3487 if let Some(glob) = Glob::new(&pattern).log_err() {
3488 if !path
3489 .components()
3490 .any(|c| matches!(c, path::Component::Normal(_)))
3491 {
3492 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3493 // rather than adding a new watcher for `/`.
3494 for worktree in &worktrees {
3495 worktree_globs
3496 .entry(worktree.read(cx).id())
3497 .or_insert_with(GlobSetBuilder::new)
3498 .add(glob.clone());
3499 }
3500 } else {
3501 abs_globs
3502 .entry(path.into())
3503 .or_insert_with(GlobSetBuilder::new)
3504 .add(glob);
3505 }
3506 }
3507 }
3508 }
3509
3510 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3511 for (worktree_id, builder) in worktree_globs {
3512 if let Ok(globset) = builder.build() {
3513 watch_builder.watch_worktree(worktree_id, globset);
3514 }
3515 }
3516 for (abs_path, builder) in abs_globs {
3517 if let Ok(globset) = builder.build() {
3518 watch_builder.watch_abs_path(abs_path, globset);
3519 }
3520 }
3521 watch_builder
3522 }
3523
3524 fn worktree_and_path_for_file_watcher(
3525 worktrees: &[Entity<Worktree>],
3526 watcher: &FileSystemWatcher,
3527 cx: &App,
3528 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3529 worktrees.iter().find_map(|worktree| {
3530 let tree = worktree.read(cx);
3531 let worktree_root_path = tree.abs_path();
3532 let path_style = tree.path_style();
3533 match &watcher.glob_pattern {
3534 lsp::GlobPattern::String(s) => {
3535 let watcher_path = SanitizedPath::new(s);
3536 let relative = watcher_path
3537 .as_path()
3538 .strip_prefix(&worktree_root_path)
3539 .ok()?;
3540 let literal_prefix = glob_literal_prefix(relative);
3541 Some((
3542 worktree.clone(),
3543 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3544 relative.to_string_lossy().into_owned(),
3545 ))
3546 }
3547 lsp::GlobPattern::Relative(rp) => {
3548 let base_uri = match &rp.base_uri {
3549 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3550 lsp::OneOf::Right(base_uri) => base_uri,
3551 }
3552 .to_file_path()
3553 .ok()?;
3554 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3555 let mut literal_prefix = relative.to_owned();
3556 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3557 Some((
3558 worktree.clone(),
3559 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3560 rp.pattern.clone(),
3561 ))
3562 }
3563 }
3564 })
3565 }
3566
3567 fn rebuild_watched_paths(
3568 &mut self,
3569 language_server_id: LanguageServerId,
3570 cx: &mut Context<LspStore>,
3571 ) {
3572 let Some(registrations) = self
3573 .language_server_dynamic_registrations
3574 .get(&language_server_id)
3575 else {
3576 return;
3577 };
3578
3579 let watch_builder = self.rebuild_watched_paths_inner(
3580 language_server_id,
3581 registrations.did_change_watched_files.values().flatten(),
3582 cx,
3583 );
3584 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3585 self.language_server_watched_paths
3586 .insert(language_server_id, watcher);
3587
3588 cx.notify();
3589 }
3590
3591 fn on_lsp_did_change_watched_files(
3592 &mut self,
3593 language_server_id: LanguageServerId,
3594 registration_id: &str,
3595 params: DidChangeWatchedFilesRegistrationOptions,
3596 cx: &mut Context<LspStore>,
3597 ) {
3598 let registrations = self
3599 .language_server_dynamic_registrations
3600 .entry(language_server_id)
3601 .or_default();
3602
3603 registrations
3604 .did_change_watched_files
3605 .insert(registration_id.to_string(), params.watchers);
3606
3607 self.rebuild_watched_paths(language_server_id, cx);
3608 }
3609
3610 fn on_lsp_unregister_did_change_watched_files(
3611 &mut self,
3612 language_server_id: LanguageServerId,
3613 registration_id: &str,
3614 cx: &mut Context<LspStore>,
3615 ) {
3616 let registrations = self
3617 .language_server_dynamic_registrations
3618 .entry(language_server_id)
3619 .or_default();
3620
3621 if registrations
3622 .did_change_watched_files
3623 .remove(registration_id)
3624 .is_some()
3625 {
3626 log::info!(
3627 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3628 language_server_id,
3629 registration_id
3630 );
3631 } else {
3632 log::warn!(
3633 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3634 language_server_id,
3635 registration_id
3636 );
3637 }
3638
3639 self.rebuild_watched_paths(language_server_id, cx);
3640 }
3641
3642 async fn initialization_options_for_adapter(
3643 adapter: Arc<dyn LspAdapter>,
3644 delegate: &Arc<dyn LspAdapterDelegate>,
3645 ) -> Result<Option<serde_json::Value>> {
3646 let Some(mut initialization_config) =
3647 adapter.clone().initialization_options(delegate).await?
3648 else {
3649 return Ok(None);
3650 };
3651
3652 for other_adapter in delegate.registered_lsp_adapters() {
3653 if other_adapter.name() == adapter.name() {
3654 continue;
3655 }
3656 if let Ok(Some(target_config)) = other_adapter
3657 .clone()
3658 .additional_initialization_options(adapter.name(), delegate)
3659 .await
3660 {
3661 merge_json_value_into(target_config.clone(), &mut initialization_config);
3662 }
3663 }
3664
3665 Ok(Some(initialization_config))
3666 }
3667
3668 async fn workspace_configuration_for_adapter(
3669 adapter: Arc<dyn LspAdapter>,
3670 delegate: &Arc<dyn LspAdapterDelegate>,
3671 toolchain: Option<Toolchain>,
3672 requested_uri: Option<Uri>,
3673 cx: &mut AsyncApp,
3674 ) -> Result<serde_json::Value> {
3675 let mut workspace_config = adapter
3676 .clone()
3677 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3678 .await?;
3679
3680 for other_adapter in delegate.registered_lsp_adapters() {
3681 if other_adapter.name() == adapter.name() {
3682 continue;
3683 }
3684 if let Ok(Some(target_config)) = other_adapter
3685 .clone()
3686 .additional_workspace_configuration(adapter.name(), delegate, cx)
3687 .await
3688 {
3689 merge_json_value_into(target_config.clone(), &mut workspace_config);
3690 }
3691 }
3692
3693 Ok(workspace_config)
3694 }
3695
3696 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3697 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3698 Some(server.clone())
3699 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3700 Some(Arc::clone(server))
3701 } else {
3702 None
3703 }
3704 }
3705}
3706
3707fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3708 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3709 cx.emit(LspStoreEvent::LanguageServerUpdate {
3710 language_server_id: server.server_id(),
3711 name: Some(server.name()),
3712 message: proto::update_language_server::Variant::MetadataUpdated(
3713 proto::ServerMetadataUpdated {
3714 capabilities: Some(capabilities),
3715 binary: Some(proto::LanguageServerBinaryInfo {
3716 path: server.binary().path.to_string_lossy().into_owned(),
3717 arguments: server
3718 .binary()
3719 .arguments
3720 .iter()
3721 .map(|arg| arg.to_string_lossy().into_owned())
3722 .collect(),
3723 }),
3724 configuration: serde_json::to_string(server.configuration()).ok(),
3725 workspace_folders: server
3726 .workspace_folders()
3727 .iter()
3728 .map(|uri| uri.to_string())
3729 .collect(),
3730 },
3731 ),
3732 });
3733 }
3734}
3735
3736#[derive(Debug)]
3737pub struct FormattableBuffer {
3738 handle: Entity<Buffer>,
3739 abs_path: Option<PathBuf>,
3740 env: Option<HashMap<String, String>>,
3741 ranges: Option<Vec<Range<Anchor>>>,
3742}
3743
3744pub struct RemoteLspStore {
3745 upstream_client: Option<AnyProtoClient>,
3746 upstream_project_id: u64,
3747}
3748
3749pub(crate) enum LspStoreMode {
3750 Local(LocalLspStore), // ssh host and collab host
3751 Remote(RemoteLspStore), // collab guest
3752}
3753
3754impl LspStoreMode {
3755 fn is_local(&self) -> bool {
3756 matches!(self, LspStoreMode::Local(_))
3757 }
3758}
3759
3760pub struct LspStore {
3761 mode: LspStoreMode,
3762 last_formatting_failure: Option<String>,
3763 downstream_client: Option<(AnyProtoClient, u64)>,
3764 nonce: u128,
3765 buffer_store: Entity<BufferStore>,
3766 worktree_store: Entity<WorktreeStore>,
3767 pub languages: Arc<LanguageRegistry>,
3768 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3769 active_entry: Option<ProjectEntryId>,
3770 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3771 _maintain_buffer_languages: Task<()>,
3772 diagnostic_summaries:
3773 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3774 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3775 lsp_data: HashMap<BufferId, BufferLspData>,
3776 next_hint_id: Arc<AtomicUsize>,
3777}
3778
3779#[derive(Debug)]
3780pub struct BufferLspData {
3781 buffer_version: Global,
3782 document_colors: Option<DocumentColorData>,
3783 code_lens: Option<CodeLensData>,
3784 inlay_hints: BufferInlayHints,
3785 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3786 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3787}
3788
3789#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3790struct LspKey {
3791 request_type: TypeId,
3792 server_queried: Option<LanguageServerId>,
3793}
3794
3795impl BufferLspData {
3796 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3797 Self {
3798 buffer_version: buffer.read(cx).version(),
3799 document_colors: None,
3800 code_lens: None,
3801 inlay_hints: BufferInlayHints::new(buffer, cx),
3802 lsp_requests: HashMap::default(),
3803 chunk_lsp_requests: HashMap::default(),
3804 }
3805 }
3806
3807 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3808 if let Some(document_colors) = &mut self.document_colors {
3809 document_colors.colors.remove(&for_server);
3810 document_colors.cache_version += 1;
3811 }
3812
3813 if let Some(code_lens) = &mut self.code_lens {
3814 code_lens.lens.remove(&for_server);
3815 }
3816
3817 self.inlay_hints.remove_server_data(for_server);
3818 }
3819
3820 #[cfg(any(test, feature = "test-support"))]
3821 pub fn inlay_hints(&self) -> &BufferInlayHints {
3822 &self.inlay_hints
3823 }
3824}
3825
3826#[derive(Debug, Default, Clone)]
3827pub struct DocumentColors {
3828 pub colors: HashSet<DocumentColor>,
3829 pub cache_version: Option<usize>,
3830}
3831
3832type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3833type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3834
3835#[derive(Debug, Default)]
3836struct DocumentColorData {
3837 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3838 cache_version: usize,
3839 colors_update: Option<(Global, DocumentColorTask)>,
3840}
3841
3842#[derive(Debug, Default)]
3843struct CodeLensData {
3844 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3845 update: Option<(Global, CodeLensTask)>,
3846}
3847
3848#[derive(Debug)]
3849pub enum LspStoreEvent {
3850 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3851 LanguageServerRemoved(LanguageServerId),
3852 LanguageServerUpdate {
3853 language_server_id: LanguageServerId,
3854 name: Option<LanguageServerName>,
3855 message: proto::update_language_server::Variant,
3856 },
3857 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3858 LanguageServerPrompt(LanguageServerPromptRequest),
3859 LanguageDetected {
3860 buffer: Entity<Buffer>,
3861 new_language: Option<Arc<Language>>,
3862 },
3863 Notification(String),
3864 RefreshInlayHints {
3865 server_id: LanguageServerId,
3866 request_id: Option<usize>,
3867 },
3868 RefreshCodeLens,
3869 DiagnosticsUpdated {
3870 server_id: LanguageServerId,
3871 paths: Vec<ProjectPath>,
3872 },
3873 DiskBasedDiagnosticsStarted {
3874 language_server_id: LanguageServerId,
3875 },
3876 DiskBasedDiagnosticsFinished {
3877 language_server_id: LanguageServerId,
3878 },
3879 SnippetEdit {
3880 buffer_id: BufferId,
3881 edits: Vec<(lsp::Range, Snippet)>,
3882 most_recent_edit: clock::Lamport,
3883 },
3884 WorkspaceEditApplied(ProjectTransaction),
3885}
3886
3887#[derive(Clone, Debug, Serialize)]
3888pub struct LanguageServerStatus {
3889 pub name: LanguageServerName,
3890 pub server_version: Option<SharedString>,
3891 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3892 pub has_pending_diagnostic_updates: bool,
3893 pub progress_tokens: HashSet<ProgressToken>,
3894 pub worktree: Option<WorktreeId>,
3895 pub binary: Option<LanguageServerBinary>,
3896 pub configuration: Option<Value>,
3897 pub workspace_folders: BTreeSet<Uri>,
3898}
3899
3900#[derive(Clone, Debug)]
3901struct CoreSymbol {
3902 pub language_server_name: LanguageServerName,
3903 pub source_worktree_id: WorktreeId,
3904 pub source_language_server_id: LanguageServerId,
3905 pub path: SymbolLocation,
3906 pub name: String,
3907 pub kind: lsp::SymbolKind,
3908 pub range: Range<Unclipped<PointUtf16>>,
3909}
3910
3911#[derive(Clone, Debug, PartialEq, Eq)]
3912pub enum SymbolLocation {
3913 InProject(ProjectPath),
3914 OutsideProject {
3915 abs_path: Arc<Path>,
3916 signature: [u8; 32],
3917 },
3918}
3919
3920impl SymbolLocation {
3921 fn file_name(&self) -> Option<&str> {
3922 match self {
3923 Self::InProject(path) => path.path.file_name(),
3924 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3925 }
3926 }
3927}
3928
3929impl LspStore {
3930 pub fn init(client: &AnyProtoClient) {
3931 client.add_entity_request_handler(Self::handle_lsp_query);
3932 client.add_entity_message_handler(Self::handle_lsp_query_response);
3933 client.add_entity_request_handler(Self::handle_restart_language_servers);
3934 client.add_entity_request_handler(Self::handle_stop_language_servers);
3935 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3936 client.add_entity_message_handler(Self::handle_start_language_server);
3937 client.add_entity_message_handler(Self::handle_update_language_server);
3938 client.add_entity_message_handler(Self::handle_language_server_log);
3939 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3940 client.add_entity_request_handler(Self::handle_format_buffers);
3941 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3942 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3943 client.add_entity_request_handler(Self::handle_apply_code_action);
3944 client.add_entity_request_handler(Self::handle_get_project_symbols);
3945 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3946 client.add_entity_request_handler(Self::handle_get_color_presentation);
3947 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3948 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3949 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3950 client.add_entity_request_handler(Self::handle_on_type_formatting);
3951 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3952 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3953 client.add_entity_request_handler(Self::handle_rename_project_entry);
3954 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3955 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3956 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3957 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3958 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3959 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3960 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3961
3962 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3963 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3964 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3965 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3966 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3967 client.add_entity_request_handler(
3968 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3969 );
3970 client.add_entity_request_handler(
3971 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3972 );
3973 client.add_entity_request_handler(
3974 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3975 );
3976 }
3977
3978 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3979 match &self.mode {
3980 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3981 _ => None,
3982 }
3983 }
3984
3985 pub fn as_local(&self) -> Option<&LocalLspStore> {
3986 match &self.mode {
3987 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3988 _ => None,
3989 }
3990 }
3991
3992 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3993 match &mut self.mode {
3994 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3995 _ => None,
3996 }
3997 }
3998
3999 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4000 match &self.mode {
4001 LspStoreMode::Remote(RemoteLspStore {
4002 upstream_client: Some(upstream_client),
4003 upstream_project_id,
4004 ..
4005 }) => Some((upstream_client.clone(), *upstream_project_id)),
4006
4007 LspStoreMode::Remote(RemoteLspStore {
4008 upstream_client: None,
4009 ..
4010 }) => None,
4011 LspStoreMode::Local(_) => None,
4012 }
4013 }
4014
4015 pub fn new_local(
4016 buffer_store: Entity<BufferStore>,
4017 worktree_store: Entity<WorktreeStore>,
4018 prettier_store: Entity<PrettierStore>,
4019 toolchain_store: Entity<LocalToolchainStore>,
4020 environment: Entity<ProjectEnvironment>,
4021 manifest_tree: Entity<ManifestTree>,
4022 languages: Arc<LanguageRegistry>,
4023 http_client: Arc<dyn HttpClient>,
4024 fs: Arc<dyn Fs>,
4025 cx: &mut Context<Self>,
4026 ) -> Self {
4027 let yarn = YarnPathStore::new(fs.clone(), cx);
4028 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4029 .detach();
4030 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4031 .detach();
4032 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4033 .detach();
4034 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4035 .detach();
4036 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4037 .detach();
4038 subscribe_to_binary_statuses(&languages, cx).detach();
4039
4040 let _maintain_workspace_config = {
4041 let (sender, receiver) = watch::channel();
4042 (Self::maintain_workspace_config(receiver, cx), sender)
4043 };
4044
4045 Self {
4046 mode: LspStoreMode::Local(LocalLspStore {
4047 weak: cx.weak_entity(),
4048 worktree_store: worktree_store.clone(),
4049
4050 supplementary_language_servers: Default::default(),
4051 languages: languages.clone(),
4052 language_server_ids: Default::default(),
4053 language_servers: Default::default(),
4054 last_workspace_edits_by_language_server: Default::default(),
4055 language_server_watched_paths: Default::default(),
4056 language_server_paths_watched_for_rename: Default::default(),
4057 language_server_dynamic_registrations: Default::default(),
4058 buffers_being_formatted: Default::default(),
4059 buffers_to_refresh_hash_set: HashSet::default(),
4060 buffers_to_refresh_queue: VecDeque::new(),
4061 _background_diagnostics_worker: Task::ready(()).shared(),
4062 buffer_snapshots: Default::default(),
4063 prettier_store,
4064 environment,
4065 http_client,
4066 fs,
4067 yarn,
4068 next_diagnostic_group_id: Default::default(),
4069 diagnostics: Default::default(),
4070 _subscription: cx.on_app_quit(|this, cx| {
4071 this.as_local_mut()
4072 .unwrap()
4073 .shutdown_language_servers_on_quit(cx)
4074 }),
4075 lsp_tree: LanguageServerTree::new(
4076 manifest_tree,
4077 languages.clone(),
4078 toolchain_store.clone(),
4079 ),
4080 toolchain_store,
4081 registered_buffers: HashMap::default(),
4082 buffers_opened_in_servers: HashMap::default(),
4083 buffer_pull_diagnostics_result_ids: HashMap::default(),
4084 workspace_pull_diagnostics_result_ids: HashMap::default(),
4085 restricted_worktrees_tasks: HashMap::default(),
4086 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4087 .manifest_file_names(),
4088 }),
4089 last_formatting_failure: None,
4090 downstream_client: None,
4091 buffer_store,
4092 worktree_store,
4093 languages: languages.clone(),
4094 language_server_statuses: Default::default(),
4095 nonce: StdRng::from_os_rng().random(),
4096 diagnostic_summaries: HashMap::default(),
4097 lsp_server_capabilities: HashMap::default(),
4098 lsp_data: HashMap::default(),
4099 next_hint_id: Arc::default(),
4100 active_entry: None,
4101 _maintain_workspace_config,
4102 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4103 }
4104 }
4105
4106 fn send_lsp_proto_request<R: LspCommand>(
4107 &self,
4108 buffer: Entity<Buffer>,
4109 client: AnyProtoClient,
4110 upstream_project_id: u64,
4111 request: R,
4112 cx: &mut Context<LspStore>,
4113 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4114 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4115 return Task::ready(Ok(R::Response::default()));
4116 }
4117 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4118 cx.spawn(async move |this, cx| {
4119 let response = client.request(message).await?;
4120 let this = this.upgrade().context("project dropped")?;
4121 request
4122 .response_from_proto(response, this, buffer, cx.clone())
4123 .await
4124 })
4125 }
4126
4127 pub(super) fn new_remote(
4128 buffer_store: Entity<BufferStore>,
4129 worktree_store: Entity<WorktreeStore>,
4130 languages: Arc<LanguageRegistry>,
4131 upstream_client: AnyProtoClient,
4132 project_id: u64,
4133 cx: &mut Context<Self>,
4134 ) -> Self {
4135 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4136 .detach();
4137 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4138 .detach();
4139 subscribe_to_binary_statuses(&languages, cx).detach();
4140 let _maintain_workspace_config = {
4141 let (sender, receiver) = watch::channel();
4142 (Self::maintain_workspace_config(receiver, cx), sender)
4143 };
4144 Self {
4145 mode: LspStoreMode::Remote(RemoteLspStore {
4146 upstream_client: Some(upstream_client),
4147 upstream_project_id: project_id,
4148 }),
4149 downstream_client: None,
4150 last_formatting_failure: None,
4151 buffer_store,
4152 worktree_store,
4153 languages: languages.clone(),
4154 language_server_statuses: Default::default(),
4155 nonce: StdRng::from_os_rng().random(),
4156 diagnostic_summaries: HashMap::default(),
4157 lsp_server_capabilities: HashMap::default(),
4158 next_hint_id: Arc::default(),
4159 lsp_data: HashMap::default(),
4160 active_entry: None,
4161
4162 _maintain_workspace_config,
4163 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4164 }
4165 }
4166
4167 fn on_buffer_store_event(
4168 &mut self,
4169 _: Entity<BufferStore>,
4170 event: &BufferStoreEvent,
4171 cx: &mut Context<Self>,
4172 ) {
4173 match event {
4174 BufferStoreEvent::BufferAdded(buffer) => {
4175 self.on_buffer_added(buffer, cx).log_err();
4176 }
4177 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4178 let buffer_id = buffer.read(cx).remote_id();
4179 if let Some(local) = self.as_local_mut()
4180 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4181 {
4182 local.reset_buffer(buffer, old_file, cx);
4183
4184 if local.registered_buffers.contains_key(&buffer_id) {
4185 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4186 }
4187 }
4188
4189 self.detect_language_for_buffer(buffer, cx);
4190 if let Some(local) = self.as_local_mut() {
4191 local.initialize_buffer(buffer, cx);
4192 if local.registered_buffers.contains_key(&buffer_id) {
4193 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4194 }
4195 }
4196 }
4197 _ => {}
4198 }
4199 }
4200
4201 fn on_worktree_store_event(
4202 &mut self,
4203 _: Entity<WorktreeStore>,
4204 event: &WorktreeStoreEvent,
4205 cx: &mut Context<Self>,
4206 ) {
4207 match event {
4208 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4209 if !worktree.read(cx).is_local() {
4210 return;
4211 }
4212 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4213 worktree::Event::UpdatedEntries(changes) => {
4214 this.update_local_worktree_language_servers(&worktree, changes, cx);
4215 }
4216 worktree::Event::UpdatedGitRepositories(_)
4217 | worktree::Event::DeletedEntry(_) => {}
4218 })
4219 .detach()
4220 }
4221 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4222 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4223 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4224 }
4225 WorktreeStoreEvent::WorktreeReleased(..)
4226 | WorktreeStoreEvent::WorktreeOrderChanged
4227 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4228 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4229 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4230 }
4231 }
4232
4233 fn on_prettier_store_event(
4234 &mut self,
4235 _: Entity<PrettierStore>,
4236 event: &PrettierStoreEvent,
4237 cx: &mut Context<Self>,
4238 ) {
4239 match event {
4240 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4241 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4242 }
4243 PrettierStoreEvent::LanguageServerAdded {
4244 new_server_id,
4245 name,
4246 prettier_server,
4247 } => {
4248 self.register_supplementary_language_server(
4249 *new_server_id,
4250 name.clone(),
4251 prettier_server.clone(),
4252 cx,
4253 );
4254 }
4255 }
4256 }
4257
4258 fn on_toolchain_store_event(
4259 &mut self,
4260 _: Entity<LocalToolchainStore>,
4261 event: &ToolchainStoreEvent,
4262 _: &mut Context<Self>,
4263 ) {
4264 if let ToolchainStoreEvent::ToolchainActivated = event {
4265 self.request_workspace_config_refresh()
4266 }
4267 }
4268
4269 fn request_workspace_config_refresh(&mut self) {
4270 *self._maintain_workspace_config.1.borrow_mut() = ();
4271 }
4272
4273 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4274 self.as_local().map(|local| local.prettier_store.clone())
4275 }
4276
4277 fn on_buffer_event(
4278 &mut self,
4279 buffer: Entity<Buffer>,
4280 event: &language::BufferEvent,
4281 cx: &mut Context<Self>,
4282 ) {
4283 match event {
4284 language::BufferEvent::Edited => {
4285 self.on_buffer_edited(buffer, cx);
4286 }
4287
4288 language::BufferEvent::Saved => {
4289 self.on_buffer_saved(buffer, cx);
4290 }
4291
4292 _ => {}
4293 }
4294 }
4295
4296 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4297 buffer
4298 .read(cx)
4299 .set_language_registry(self.languages.clone());
4300
4301 cx.subscribe(buffer, |this, buffer, event, cx| {
4302 this.on_buffer_event(buffer, event, cx);
4303 })
4304 .detach();
4305
4306 self.detect_language_for_buffer(buffer, cx);
4307 if let Some(local) = self.as_local_mut() {
4308 local.initialize_buffer(buffer, cx);
4309 }
4310
4311 Ok(())
4312 }
4313
4314 pub fn refresh_background_diagnostics_for_buffers(
4315 &mut self,
4316 buffers: HashSet<BufferId>,
4317 cx: &mut Context<Self>,
4318 ) -> Shared<Task<()>> {
4319 let Some(local) = self.as_local_mut() else {
4320 return Task::ready(()).shared();
4321 };
4322 for buffer in buffers {
4323 if local.buffers_to_refresh_hash_set.insert(buffer) {
4324 local.buffers_to_refresh_queue.push_back(buffer);
4325 if local.buffers_to_refresh_queue.len() == 1 {
4326 local._background_diagnostics_worker =
4327 Self::background_diagnostics_worker(cx).shared();
4328 }
4329 }
4330 }
4331
4332 local._background_diagnostics_worker.clone()
4333 }
4334
4335 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4336 let buffer_store = self.buffer_store.clone();
4337 let local = self.as_local_mut()?;
4338 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4339 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4340 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4341 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4342 }
4343 }
4344 None
4345 }
4346
4347 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4348 cx.spawn(async move |this, cx| {
4349 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4350 task.await.log_err();
4351 }
4352 })
4353 }
4354
4355 pub(crate) fn register_buffer_with_language_servers(
4356 &mut self,
4357 buffer: &Entity<Buffer>,
4358 only_register_servers: HashSet<LanguageServerSelector>,
4359 ignore_refcounts: bool,
4360 cx: &mut Context<Self>,
4361 ) -> OpenLspBufferHandle {
4362 let buffer_id = buffer.read(cx).remote_id();
4363 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4364 if let Some(local) = self.as_local_mut() {
4365 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4366 if !ignore_refcounts {
4367 *refcount += 1;
4368 }
4369
4370 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4371 // 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
4372 // 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
4373 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4374 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4375 return handle;
4376 };
4377 if !file.is_local() {
4378 return handle;
4379 }
4380
4381 if ignore_refcounts || *refcount == 1 {
4382 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4383 }
4384 if !ignore_refcounts {
4385 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4386 let refcount = {
4387 let local = lsp_store.as_local_mut().unwrap();
4388 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4389 debug_panic!("bad refcounting");
4390 return;
4391 };
4392
4393 *refcount -= 1;
4394 *refcount
4395 };
4396 if refcount == 0 {
4397 lsp_store.lsp_data.remove(&buffer_id);
4398 let local = lsp_store.as_local_mut().unwrap();
4399 local.registered_buffers.remove(&buffer_id);
4400
4401 local.buffers_opened_in_servers.remove(&buffer_id);
4402 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4403 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4404
4405 let buffer_abs_path = file.abs_path(cx);
4406 for (_, buffer_pull_diagnostics_result_ids) in
4407 &mut local.buffer_pull_diagnostics_result_ids
4408 {
4409 buffer_pull_diagnostics_result_ids.retain(
4410 |_, buffer_result_ids| {
4411 buffer_result_ids.remove(&buffer_abs_path);
4412 !buffer_result_ids.is_empty()
4413 },
4414 );
4415 }
4416
4417 let diagnostic_updates = local
4418 .language_servers
4419 .keys()
4420 .cloned()
4421 .map(|server_id| DocumentDiagnosticsUpdate {
4422 diagnostics: DocumentDiagnostics {
4423 document_abs_path: buffer_abs_path.clone(),
4424 version: None,
4425 diagnostics: Vec::new(),
4426 },
4427 result_id: None,
4428 registration_id: None,
4429 server_id: server_id,
4430 disk_based_sources: Cow::Borrowed(&[]),
4431 })
4432 .collect::<Vec<_>>();
4433
4434 lsp_store
4435 .merge_diagnostic_entries(
4436 diagnostic_updates,
4437 |_, diagnostic, _| {
4438 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4439 },
4440 cx,
4441 )
4442 .context("Clearing diagnostics for the closed buffer")
4443 .log_err();
4444 }
4445 }
4446 })
4447 .detach();
4448 }
4449 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4450 let buffer_id = buffer.read(cx).remote_id().to_proto();
4451 cx.background_spawn(async move {
4452 upstream_client
4453 .request(proto::RegisterBufferWithLanguageServers {
4454 project_id: upstream_project_id,
4455 buffer_id,
4456 only_servers: only_register_servers
4457 .into_iter()
4458 .map(|selector| {
4459 let selector = match selector {
4460 LanguageServerSelector::Id(language_server_id) => {
4461 proto::language_server_selector::Selector::ServerId(
4462 language_server_id.to_proto(),
4463 )
4464 }
4465 LanguageServerSelector::Name(language_server_name) => {
4466 proto::language_server_selector::Selector::Name(
4467 language_server_name.to_string(),
4468 )
4469 }
4470 };
4471 proto::LanguageServerSelector {
4472 selector: Some(selector),
4473 }
4474 })
4475 .collect(),
4476 })
4477 .await
4478 })
4479 .detach();
4480 } else {
4481 // Our remote connection got closed
4482 }
4483 handle
4484 }
4485
4486 fn maintain_buffer_languages(
4487 languages: Arc<LanguageRegistry>,
4488 cx: &mut Context<Self>,
4489 ) -> Task<()> {
4490 let mut subscription = languages.subscribe();
4491 let mut prev_reload_count = languages.reload_count();
4492 cx.spawn(async move |this, cx| {
4493 while let Some(()) = subscription.next().await {
4494 if let Some(this) = this.upgrade() {
4495 // If the language registry has been reloaded, then remove and
4496 // re-assign the languages on all open buffers.
4497 let reload_count = languages.reload_count();
4498 if reload_count > prev_reload_count {
4499 prev_reload_count = reload_count;
4500 this.update(cx, |this, cx| {
4501 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4502 for buffer in buffer_store.buffers() {
4503 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4504 {
4505 buffer.update(cx, |buffer, cx| {
4506 buffer.set_language_async(None, cx)
4507 });
4508 if let Some(local) = this.as_local_mut() {
4509 local.reset_buffer(&buffer, &f, cx);
4510
4511 if local
4512 .registered_buffers
4513 .contains_key(&buffer.read(cx).remote_id())
4514 && let Some(file_url) =
4515 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4516 {
4517 local.unregister_buffer_from_language_servers(
4518 &buffer, &file_url, cx,
4519 );
4520 }
4521 }
4522 }
4523 }
4524 });
4525 });
4526 }
4527
4528 this.update(cx, |this, cx| {
4529 let mut plain_text_buffers = Vec::new();
4530 let mut buffers_with_unknown_injections = Vec::new();
4531 for handle in this.buffer_store.read(cx).buffers() {
4532 let buffer = handle.read(cx);
4533 if buffer.language().is_none()
4534 || buffer.language() == Some(&*language::PLAIN_TEXT)
4535 {
4536 plain_text_buffers.push(handle);
4537 } else if buffer.contains_unknown_injections() {
4538 buffers_with_unknown_injections.push(handle);
4539 }
4540 }
4541
4542 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4543 // and reused later in the invisible worktrees.
4544 plain_text_buffers.sort_by_key(|buffer| {
4545 Reverse(
4546 File::from_dyn(buffer.read(cx).file())
4547 .map(|file| file.worktree.read(cx).is_visible()),
4548 )
4549 });
4550
4551 for buffer in plain_text_buffers {
4552 this.detect_language_for_buffer(&buffer, cx);
4553 if let Some(local) = this.as_local_mut() {
4554 local.initialize_buffer(&buffer, cx);
4555 if local
4556 .registered_buffers
4557 .contains_key(&buffer.read(cx).remote_id())
4558 {
4559 local.register_buffer_with_language_servers(
4560 &buffer,
4561 HashSet::default(),
4562 cx,
4563 );
4564 }
4565 }
4566 }
4567
4568 for buffer in buffers_with_unknown_injections {
4569 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4570 }
4571 });
4572 }
4573 }
4574 })
4575 }
4576
4577 fn detect_language_for_buffer(
4578 &mut self,
4579 buffer_handle: &Entity<Buffer>,
4580 cx: &mut Context<Self>,
4581 ) -> Option<language::AvailableLanguage> {
4582 // If the buffer has a language, set it and start the language server if we haven't already.
4583 let buffer = buffer_handle.read(cx);
4584 let file = buffer.file()?;
4585
4586 let content = buffer.as_rope();
4587 let available_language = self.languages.language_for_file(file, Some(content), cx);
4588 if let Some(available_language) = &available_language {
4589 if let Some(Ok(Ok(new_language))) = self
4590 .languages
4591 .load_language(available_language)
4592 .now_or_never()
4593 {
4594 self.set_language_for_buffer(buffer_handle, new_language, cx);
4595 }
4596 } else {
4597 cx.emit(LspStoreEvent::LanguageDetected {
4598 buffer: buffer_handle.clone(),
4599 new_language: None,
4600 });
4601 }
4602
4603 available_language
4604 }
4605
4606 pub(crate) fn set_language_for_buffer(
4607 &mut self,
4608 buffer_entity: &Entity<Buffer>,
4609 new_language: Arc<Language>,
4610 cx: &mut Context<Self>,
4611 ) {
4612 let buffer = buffer_entity.read(cx);
4613 let buffer_file = buffer.file().cloned();
4614 let buffer_id = buffer.remote_id();
4615 if let Some(local_store) = self.as_local_mut()
4616 && local_store.registered_buffers.contains_key(&buffer_id)
4617 && let Some(abs_path) =
4618 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4619 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4620 {
4621 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4622 }
4623 buffer_entity.update(cx, |buffer, cx| {
4624 if buffer
4625 .language()
4626 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4627 {
4628 buffer.set_language_async(Some(new_language.clone()), cx);
4629 }
4630 });
4631
4632 let settings =
4633 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4634 let buffer_file = File::from_dyn(buffer_file.as_ref());
4635
4636 let worktree_id = if let Some(file) = buffer_file {
4637 let worktree = file.worktree.clone();
4638
4639 if let Some(local) = self.as_local_mut()
4640 && local.registered_buffers.contains_key(&buffer_id)
4641 {
4642 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4643 }
4644 Some(worktree.read(cx).id())
4645 } else {
4646 None
4647 };
4648
4649 if settings.prettier.allowed
4650 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4651 {
4652 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4653 if let Some(prettier_store) = prettier_store {
4654 prettier_store.update(cx, |prettier_store, cx| {
4655 prettier_store.install_default_prettier(
4656 worktree_id,
4657 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4658 cx,
4659 )
4660 })
4661 }
4662 }
4663
4664 cx.emit(LspStoreEvent::LanguageDetected {
4665 buffer: buffer_entity.clone(),
4666 new_language: Some(new_language),
4667 })
4668 }
4669
4670 pub fn buffer_store(&self) -> Entity<BufferStore> {
4671 self.buffer_store.clone()
4672 }
4673
4674 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4675 self.active_entry = active_entry;
4676 }
4677
4678 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4679 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4680 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4681 {
4682 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4683 summaries
4684 .iter()
4685 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4686 });
4687 if let Some(summary) = summaries.next() {
4688 client
4689 .send(proto::UpdateDiagnosticSummary {
4690 project_id: downstream_project_id,
4691 worktree_id: worktree.id().to_proto(),
4692 summary: Some(summary),
4693 more_summaries: summaries.collect(),
4694 })
4695 .log_err();
4696 }
4697 }
4698 }
4699
4700 fn is_capable_for_proto_request<R>(
4701 &self,
4702 buffer: &Entity<Buffer>,
4703 request: &R,
4704 cx: &App,
4705 ) -> bool
4706 where
4707 R: LspCommand,
4708 {
4709 self.check_if_capable_for_proto_request(
4710 buffer,
4711 |capabilities| {
4712 request.check_capabilities(AdapterServerCapabilities {
4713 server_capabilities: capabilities.clone(),
4714 code_action_kinds: None,
4715 })
4716 },
4717 cx,
4718 )
4719 }
4720
4721 fn check_if_capable_for_proto_request<F>(
4722 &self,
4723 buffer: &Entity<Buffer>,
4724 check: F,
4725 cx: &App,
4726 ) -> bool
4727 where
4728 F: FnMut(&lsp::ServerCapabilities) -> bool,
4729 {
4730 let Some(language) = buffer.read(cx).language().cloned() else {
4731 return false;
4732 };
4733 let registered_language_servers = self
4734 .languages
4735 .lsp_adapters(&language.name())
4736 .into_iter()
4737 .map(|lsp_adapter| lsp_adapter.name())
4738 .collect::<HashSet<_>>();
4739 self.language_server_statuses
4740 .iter()
4741 .filter_map(|(server_id, server_status)| {
4742 // Include servers that are either registered for this language OR
4743 // available to be loaded (for SSH remote mode where adapters like
4744 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4745 // but only loaded on the server side)
4746 let is_relevant = registered_language_servers.contains(&server_status.name)
4747 || self.languages.is_lsp_adapter_available(&server_status.name);
4748 is_relevant.then_some(server_id)
4749 })
4750 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4751 .any(check)
4752 }
4753
4754 fn all_capable_for_proto_request<F>(
4755 &self,
4756 buffer: &Entity<Buffer>,
4757 mut check: F,
4758 cx: &App,
4759 ) -> Vec<lsp::LanguageServerId>
4760 where
4761 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4762 {
4763 let Some(language) = buffer.read(cx).language().cloned() else {
4764 return Vec::default();
4765 };
4766 let registered_language_servers = self
4767 .languages
4768 .lsp_adapters(&language.name())
4769 .into_iter()
4770 .map(|lsp_adapter| lsp_adapter.name())
4771 .collect::<HashSet<_>>();
4772 self.language_server_statuses
4773 .iter()
4774 .filter_map(|(server_id, server_status)| {
4775 // Include servers that are either registered for this language OR
4776 // available to be loaded (for SSH remote mode where adapters like
4777 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4778 // but only loaded on the server side)
4779 let is_relevant = registered_language_servers.contains(&server_status.name)
4780 || self.languages.is_lsp_adapter_available(&server_status.name);
4781 is_relevant.then_some((server_id, &server_status.name))
4782 })
4783 .filter_map(|(server_id, server_name)| {
4784 self.lsp_server_capabilities
4785 .get(server_id)
4786 .map(|c| (server_id, server_name, c))
4787 })
4788 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4789 .map(|(server_id, _, _)| *server_id)
4790 .collect()
4791 }
4792
4793 pub fn request_lsp<R>(
4794 &mut self,
4795 buffer: Entity<Buffer>,
4796 server: LanguageServerToQuery,
4797 request: R,
4798 cx: &mut Context<Self>,
4799 ) -> Task<Result<R::Response>>
4800 where
4801 R: LspCommand,
4802 <R::LspRequest as lsp::request::Request>::Result: Send,
4803 <R::LspRequest as lsp::request::Request>::Params: Send,
4804 {
4805 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4806 return self.send_lsp_proto_request(
4807 buffer,
4808 upstream_client,
4809 upstream_project_id,
4810 request,
4811 cx,
4812 );
4813 }
4814
4815 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4816 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4817 local
4818 .language_servers_for_buffer(buffer, cx)
4819 .find(|(_, server)| {
4820 request.check_capabilities(server.adapter_server_capabilities())
4821 })
4822 .map(|(_, server)| server.clone())
4823 }),
4824 LanguageServerToQuery::Other(id) => self
4825 .language_server_for_local_buffer(buffer, id, cx)
4826 .and_then(|(_, server)| {
4827 request
4828 .check_capabilities(server.adapter_server_capabilities())
4829 .then(|| Arc::clone(server))
4830 }),
4831 }) else {
4832 return Task::ready(Ok(Default::default()));
4833 };
4834
4835 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4836
4837 let Some(file) = file else {
4838 return Task::ready(Ok(Default::default()));
4839 };
4840
4841 let lsp_params = match request.to_lsp_params_or_response(
4842 &file.abs_path(cx),
4843 buffer.read(cx),
4844 &language_server,
4845 cx,
4846 ) {
4847 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4848 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4849 Err(err) => {
4850 let message = format!(
4851 "{} via {} failed: {}",
4852 request.display_name(),
4853 language_server.name(),
4854 err
4855 );
4856 // rust-analyzer likes to error with this when its still loading up
4857 if !message.ends_with("content modified") {
4858 log::warn!("{message}");
4859 }
4860 return Task::ready(Err(anyhow!(message)));
4861 }
4862 };
4863
4864 let status = request.status();
4865 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4866 return Task::ready(Ok(Default::default()));
4867 }
4868 cx.spawn(async move |this, cx| {
4869 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4870
4871 let id = lsp_request.id();
4872 let _cleanup = if status.is_some() {
4873 cx.update(|cx| {
4874 this.update(cx, |this, cx| {
4875 this.on_lsp_work_start(
4876 language_server.server_id(),
4877 ProgressToken::Number(id),
4878 LanguageServerProgress {
4879 is_disk_based_diagnostics_progress: false,
4880 is_cancellable: false,
4881 title: None,
4882 message: status.clone(),
4883 percentage: None,
4884 last_update_at: cx.background_executor().now(),
4885 },
4886 cx,
4887 );
4888 })
4889 })
4890 .log_err();
4891
4892 Some(defer(|| {
4893 cx.update(|cx| {
4894 this.update(cx, |this, cx| {
4895 this.on_lsp_work_end(
4896 language_server.server_id(),
4897 ProgressToken::Number(id),
4898 cx,
4899 );
4900 })
4901 })
4902 .log_err();
4903 }))
4904 } else {
4905 None
4906 };
4907
4908 let result = lsp_request.await.into_response();
4909
4910 let response = result.map_err(|err| {
4911 let message = format!(
4912 "{} via {} failed: {}",
4913 request.display_name(),
4914 language_server.name(),
4915 err
4916 );
4917 // rust-analyzer likes to error with this when its still loading up
4918 if !message.ends_with("content modified") {
4919 log::warn!("{message}");
4920 }
4921 anyhow::anyhow!(message)
4922 })?;
4923
4924 request
4925 .response_from_lsp(
4926 response,
4927 this.upgrade().context("no app context")?,
4928 buffer,
4929 language_server.server_id(),
4930 cx.clone(),
4931 )
4932 .await
4933 })
4934 }
4935
4936 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4937 let mut language_formatters_to_check = Vec::new();
4938 for buffer in self.buffer_store.read(cx).buffers() {
4939 let buffer = buffer.read(cx);
4940 let buffer_file = File::from_dyn(buffer.file());
4941 let buffer_language = buffer.language();
4942 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4943 if buffer_language.is_some() {
4944 language_formatters_to_check.push((
4945 buffer_file.map(|f| f.worktree_id(cx)),
4946 settings.into_owned(),
4947 ));
4948 }
4949 }
4950
4951 self.request_workspace_config_refresh();
4952
4953 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4954 prettier_store.update(cx, |prettier_store, cx| {
4955 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4956 })
4957 }
4958
4959 cx.notify();
4960 }
4961
4962 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4963 let buffer_store = self.buffer_store.clone();
4964 let Some(local) = self.as_local_mut() else {
4965 return;
4966 };
4967 let mut adapters = BTreeMap::default();
4968 let get_adapter = {
4969 let languages = local.languages.clone();
4970 let environment = local.environment.clone();
4971 let weak = local.weak.clone();
4972 let worktree_store = local.worktree_store.clone();
4973 let http_client = local.http_client.clone();
4974 let fs = local.fs.clone();
4975 move |worktree_id, cx: &mut App| {
4976 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4977 Some(LocalLspAdapterDelegate::new(
4978 languages.clone(),
4979 &environment,
4980 weak.clone(),
4981 &worktree,
4982 http_client.clone(),
4983 fs.clone(),
4984 cx,
4985 ))
4986 }
4987 };
4988
4989 let mut messages_to_report = Vec::new();
4990 let (new_tree, to_stop) = {
4991 let mut rebase = local.lsp_tree.rebase();
4992 let buffers = buffer_store
4993 .read(cx)
4994 .buffers()
4995 .filter_map(|buffer| {
4996 let raw_buffer = buffer.read(cx);
4997 if !local
4998 .registered_buffers
4999 .contains_key(&raw_buffer.remote_id())
5000 {
5001 return None;
5002 }
5003 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5004 let language = raw_buffer.language().cloned()?;
5005 Some((file, language, raw_buffer.remote_id()))
5006 })
5007 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5008 for (file, language, buffer_id) in buffers {
5009 let worktree_id = file.worktree_id(cx);
5010 let Some(worktree) = local
5011 .worktree_store
5012 .read(cx)
5013 .worktree_for_id(worktree_id, cx)
5014 else {
5015 continue;
5016 };
5017
5018 if let Some((_, apply)) = local.reuse_existing_language_server(
5019 rebase.server_tree(),
5020 &worktree,
5021 &language.name(),
5022 cx,
5023 ) {
5024 (apply)(rebase.server_tree());
5025 } else if let Some(lsp_delegate) = adapters
5026 .entry(worktree_id)
5027 .or_insert_with(|| get_adapter(worktree_id, cx))
5028 .clone()
5029 {
5030 let delegate =
5031 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5032 let path = file
5033 .path()
5034 .parent()
5035 .map(Arc::from)
5036 .unwrap_or_else(|| file.path().clone());
5037 let worktree_path = ProjectPath { worktree_id, path };
5038 let abs_path = file.abs_path(cx);
5039 let nodes = rebase
5040 .walk(
5041 worktree_path,
5042 language.name(),
5043 language.manifest(),
5044 delegate.clone(),
5045 cx,
5046 )
5047 .collect::<Vec<_>>();
5048 for node in nodes {
5049 let server_id = node.server_id_or_init(|disposition| {
5050 let path = &disposition.path;
5051 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5052 let key = LanguageServerSeed {
5053 worktree_id,
5054 name: disposition.server_name.clone(),
5055 settings: disposition.settings.clone(),
5056 toolchain: local.toolchain_store.read(cx).active_toolchain(
5057 path.worktree_id,
5058 &path.path,
5059 language.name(),
5060 ),
5061 };
5062 local.language_server_ids.remove(&key);
5063
5064 let server_id = local.get_or_insert_language_server(
5065 &worktree,
5066 lsp_delegate.clone(),
5067 disposition,
5068 &language.name(),
5069 cx,
5070 );
5071 if let Some(state) = local.language_servers.get(&server_id)
5072 && let Ok(uri) = uri
5073 {
5074 state.add_workspace_folder(uri);
5075 };
5076 server_id
5077 });
5078
5079 if let Some(language_server_id) = server_id {
5080 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5081 language_server_id,
5082 name: node.name(),
5083 message:
5084 proto::update_language_server::Variant::RegisteredForBuffer(
5085 proto::RegisteredForBuffer {
5086 buffer_abs_path: abs_path
5087 .to_string_lossy()
5088 .into_owned(),
5089 buffer_id: buffer_id.to_proto(),
5090 },
5091 ),
5092 });
5093 }
5094 }
5095 } else {
5096 continue;
5097 }
5098 }
5099 rebase.finish()
5100 };
5101 for message in messages_to_report {
5102 cx.emit(message);
5103 }
5104 local.lsp_tree = new_tree;
5105 for (id, _) in to_stop {
5106 self.stop_local_language_server(id, cx).detach();
5107 }
5108 }
5109
5110 pub fn apply_code_action(
5111 &self,
5112 buffer_handle: Entity<Buffer>,
5113 mut action: CodeAction,
5114 push_to_history: bool,
5115 cx: &mut Context<Self>,
5116 ) -> Task<Result<ProjectTransaction>> {
5117 if let Some((upstream_client, project_id)) = self.upstream_client() {
5118 let request = proto::ApplyCodeAction {
5119 project_id,
5120 buffer_id: buffer_handle.read(cx).remote_id().into(),
5121 action: Some(Self::serialize_code_action(&action)),
5122 };
5123 let buffer_store = self.buffer_store();
5124 cx.spawn(async move |_, cx| {
5125 let response = upstream_client
5126 .request(request)
5127 .await?
5128 .transaction
5129 .context("missing transaction")?;
5130
5131 buffer_store
5132 .update(cx, |buffer_store, cx| {
5133 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5134 })
5135 .await
5136 })
5137 } else if self.mode.is_local() {
5138 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5139 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5140 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5141 }) else {
5142 return Task::ready(Ok(ProjectTransaction::default()));
5143 };
5144 cx.spawn(async move |this, cx| {
5145 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5146 .await
5147 .context("resolving a code action")?;
5148 if let Some(edit) = action.lsp_action.edit()
5149 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5150 return LocalLspStore::deserialize_workspace_edit(
5151 this.upgrade().context("no app present")?,
5152 edit.clone(),
5153 push_to_history,
5154
5155 lang_server.clone(),
5156 cx,
5157 )
5158 .await;
5159 }
5160
5161 if let Some(command) = action.lsp_action.command() {
5162 let server_capabilities = lang_server.capabilities();
5163 let available_commands = server_capabilities
5164 .execute_command_provider
5165 .as_ref()
5166 .map(|options| options.commands.as_slice())
5167 .unwrap_or_default();
5168 if available_commands.contains(&command.command) {
5169 this.update(cx, |this, _| {
5170 this.as_local_mut()
5171 .unwrap()
5172 .last_workspace_edits_by_language_server
5173 .remove(&lang_server.server_id());
5174 })?;
5175
5176 let _result = lang_server
5177 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5178 command: command.command.clone(),
5179 arguments: command.arguments.clone().unwrap_or_default(),
5180 ..lsp::ExecuteCommandParams::default()
5181 })
5182 .await.into_response()
5183 .context("execute command")?;
5184
5185 return this.update(cx, |this, _| {
5186 this.as_local_mut()
5187 .unwrap()
5188 .last_workspace_edits_by_language_server
5189 .remove(&lang_server.server_id())
5190 .unwrap_or_default()
5191 });
5192 } else {
5193 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5194 }
5195 }
5196
5197 Ok(ProjectTransaction::default())
5198 })
5199 } else {
5200 Task::ready(Err(anyhow!("no upstream client and not local")))
5201 }
5202 }
5203
5204 pub fn apply_code_action_kind(
5205 &mut self,
5206 buffers: HashSet<Entity<Buffer>>,
5207 kind: CodeActionKind,
5208 push_to_history: bool,
5209 cx: &mut Context<Self>,
5210 ) -> Task<anyhow::Result<ProjectTransaction>> {
5211 if self.as_local().is_some() {
5212 cx.spawn(async move |lsp_store, cx| {
5213 let buffers = buffers.into_iter().collect::<Vec<_>>();
5214 let result = LocalLspStore::execute_code_action_kind_locally(
5215 lsp_store.clone(),
5216 buffers,
5217 kind,
5218 push_to_history,
5219 cx,
5220 )
5221 .await;
5222 lsp_store.update(cx, |lsp_store, _| {
5223 lsp_store.update_last_formatting_failure(&result);
5224 })?;
5225 result
5226 })
5227 } else if let Some((client, project_id)) = self.upstream_client() {
5228 let buffer_store = self.buffer_store();
5229 cx.spawn(async move |lsp_store, cx| {
5230 let result = client
5231 .request(proto::ApplyCodeActionKind {
5232 project_id,
5233 kind: kind.as_str().to_owned(),
5234 buffer_ids: buffers
5235 .iter()
5236 .map(|buffer| {
5237 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5238 })
5239 .collect(),
5240 })
5241 .await
5242 .and_then(|result| result.transaction.context("missing transaction"));
5243 lsp_store.update(cx, |lsp_store, _| {
5244 lsp_store.update_last_formatting_failure(&result);
5245 })?;
5246
5247 let transaction_response = result?;
5248 buffer_store
5249 .update(cx, |buffer_store, cx| {
5250 buffer_store.deserialize_project_transaction(
5251 transaction_response,
5252 push_to_history,
5253 cx,
5254 )
5255 })
5256 .await
5257 })
5258 } else {
5259 Task::ready(Ok(ProjectTransaction::default()))
5260 }
5261 }
5262
5263 pub fn resolved_hint(
5264 &mut self,
5265 buffer_id: BufferId,
5266 id: InlayId,
5267 cx: &mut Context<Self>,
5268 ) -> Option<ResolvedHint> {
5269 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5270
5271 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5272 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5273 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5274 let (server_id, resolve_data) = match &hint.resolve_state {
5275 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5276 ResolveState::Resolving => {
5277 return Some(ResolvedHint::Resolving(
5278 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5279 ));
5280 }
5281 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5282 };
5283
5284 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5285 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5286 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5287 id,
5288 cx.spawn(async move |lsp_store, cx| {
5289 let resolved_hint = resolve_task.await;
5290 lsp_store
5291 .update(cx, |lsp_store, _| {
5292 if let Some(old_inlay_hint) = lsp_store
5293 .lsp_data
5294 .get_mut(&buffer_id)
5295 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5296 {
5297 match resolved_hint {
5298 Ok(resolved_hint) => {
5299 *old_inlay_hint = resolved_hint;
5300 }
5301 Err(e) => {
5302 old_inlay_hint.resolve_state =
5303 ResolveState::CanResolve(server_id, resolve_data);
5304 log::error!("Inlay hint resolve failed: {e:#}");
5305 }
5306 }
5307 }
5308 })
5309 .ok();
5310 })
5311 .shared(),
5312 );
5313 debug_assert!(
5314 previous_task.is_none(),
5315 "Did not change hint's resolve state after spawning its resolve"
5316 );
5317 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5318 None
5319 }
5320
5321 fn resolve_inlay_hint(
5322 &self,
5323 mut hint: InlayHint,
5324 buffer: Entity<Buffer>,
5325 server_id: LanguageServerId,
5326 cx: &mut Context<Self>,
5327 ) -> Task<anyhow::Result<InlayHint>> {
5328 if let Some((upstream_client, project_id)) = self.upstream_client() {
5329 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5330 {
5331 hint.resolve_state = ResolveState::Resolved;
5332 return Task::ready(Ok(hint));
5333 }
5334 let request = proto::ResolveInlayHint {
5335 project_id,
5336 buffer_id: buffer.read(cx).remote_id().into(),
5337 language_server_id: server_id.0 as u64,
5338 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5339 };
5340 cx.background_spawn(async move {
5341 let response = upstream_client
5342 .request(request)
5343 .await
5344 .context("inlay hints proto request")?;
5345 match response.hint {
5346 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5347 .context("inlay hints proto resolve response conversion"),
5348 None => Ok(hint),
5349 }
5350 })
5351 } else {
5352 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5353 self.language_server_for_local_buffer(buffer, server_id, cx)
5354 .map(|(_, server)| server.clone())
5355 }) else {
5356 return Task::ready(Ok(hint));
5357 };
5358 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5359 return Task::ready(Ok(hint));
5360 }
5361 let buffer_snapshot = buffer.read(cx).snapshot();
5362 cx.spawn(async move |_, cx| {
5363 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5364 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5365 );
5366 let resolved_hint = resolve_task
5367 .await
5368 .into_response()
5369 .context("inlay hint resolve LSP request")?;
5370 let resolved_hint = InlayHints::lsp_to_project_hint(
5371 resolved_hint,
5372 &buffer,
5373 server_id,
5374 ResolveState::Resolved,
5375 false,
5376 cx,
5377 )
5378 .await?;
5379 Ok(resolved_hint)
5380 })
5381 }
5382 }
5383
5384 pub fn resolve_color_presentation(
5385 &mut self,
5386 mut color: DocumentColor,
5387 buffer: Entity<Buffer>,
5388 server_id: LanguageServerId,
5389 cx: &mut Context<Self>,
5390 ) -> Task<Result<DocumentColor>> {
5391 if color.resolved {
5392 return Task::ready(Ok(color));
5393 }
5394
5395 if let Some((upstream_client, project_id)) = self.upstream_client() {
5396 let start = color.lsp_range.start;
5397 let end = color.lsp_range.end;
5398 let request = proto::GetColorPresentation {
5399 project_id,
5400 server_id: server_id.to_proto(),
5401 buffer_id: buffer.read(cx).remote_id().into(),
5402 color: Some(proto::ColorInformation {
5403 red: color.color.red,
5404 green: color.color.green,
5405 blue: color.color.blue,
5406 alpha: color.color.alpha,
5407 lsp_range_start: Some(proto::PointUtf16 {
5408 row: start.line,
5409 column: start.character,
5410 }),
5411 lsp_range_end: Some(proto::PointUtf16 {
5412 row: end.line,
5413 column: end.character,
5414 }),
5415 }),
5416 };
5417 cx.background_spawn(async move {
5418 let response = upstream_client
5419 .request(request)
5420 .await
5421 .context("color presentation proto request")?;
5422 color.resolved = true;
5423 color.color_presentations = response
5424 .presentations
5425 .into_iter()
5426 .map(|presentation| ColorPresentation {
5427 label: SharedString::from(presentation.label),
5428 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5429 additional_text_edits: presentation
5430 .additional_text_edits
5431 .into_iter()
5432 .filter_map(deserialize_lsp_edit)
5433 .collect(),
5434 })
5435 .collect();
5436 Ok(color)
5437 })
5438 } else {
5439 let path = match buffer
5440 .update(cx, |buffer, cx| {
5441 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5442 })
5443 .context("buffer with the missing path")
5444 {
5445 Ok(path) => path,
5446 Err(e) => return Task::ready(Err(e)),
5447 };
5448 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5449 self.language_server_for_local_buffer(buffer, server_id, cx)
5450 .map(|(_, server)| server.clone())
5451 }) else {
5452 return Task::ready(Ok(color));
5453 };
5454 cx.background_spawn(async move {
5455 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5456 lsp::ColorPresentationParams {
5457 text_document: make_text_document_identifier(&path)?,
5458 color: color.color,
5459 range: color.lsp_range,
5460 work_done_progress_params: Default::default(),
5461 partial_result_params: Default::default(),
5462 },
5463 );
5464 color.color_presentations = resolve_task
5465 .await
5466 .into_response()
5467 .context("color presentation resolve LSP request")?
5468 .into_iter()
5469 .map(|presentation| ColorPresentation {
5470 label: SharedString::from(presentation.label),
5471 text_edit: presentation.text_edit,
5472 additional_text_edits: presentation
5473 .additional_text_edits
5474 .unwrap_or_default(),
5475 })
5476 .collect();
5477 color.resolved = true;
5478 Ok(color)
5479 })
5480 }
5481 }
5482
5483 pub(crate) fn linked_edits(
5484 &mut self,
5485 buffer: &Entity<Buffer>,
5486 position: Anchor,
5487 cx: &mut Context<Self>,
5488 ) -> Task<Result<Vec<Range<Anchor>>>> {
5489 let snapshot = buffer.read(cx).snapshot();
5490 let scope = snapshot.language_scope_at(position);
5491 let Some(server_id) = self
5492 .as_local()
5493 .and_then(|local| {
5494 buffer.update(cx, |buffer, cx| {
5495 local
5496 .language_servers_for_buffer(buffer, cx)
5497 .filter(|(_, server)| {
5498 LinkedEditingRange::check_server_capabilities(server.capabilities())
5499 })
5500 .filter(|(adapter, _)| {
5501 scope
5502 .as_ref()
5503 .map(|scope| scope.language_allowed(&adapter.name))
5504 .unwrap_or(true)
5505 })
5506 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5507 .next()
5508 })
5509 })
5510 .or_else(|| {
5511 self.upstream_client()
5512 .is_some()
5513 .then_some(LanguageServerToQuery::FirstCapable)
5514 })
5515 .filter(|_| {
5516 maybe!({
5517 let language = buffer.read(cx).language_at(position)?;
5518 Some(
5519 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5520 .linked_edits,
5521 )
5522 }) == Some(true)
5523 })
5524 else {
5525 return Task::ready(Ok(Vec::new()));
5526 };
5527
5528 self.request_lsp(
5529 buffer.clone(),
5530 server_id,
5531 LinkedEditingRange { position },
5532 cx,
5533 )
5534 }
5535
5536 fn apply_on_type_formatting(
5537 &mut self,
5538 buffer: Entity<Buffer>,
5539 position: Anchor,
5540 trigger: String,
5541 cx: &mut Context<Self>,
5542 ) -> Task<Result<Option<Transaction>>> {
5543 if let Some((client, project_id)) = self.upstream_client() {
5544 if !self.check_if_capable_for_proto_request(
5545 &buffer,
5546 |capabilities| {
5547 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5548 },
5549 cx,
5550 ) {
5551 return Task::ready(Ok(None));
5552 }
5553 let request = proto::OnTypeFormatting {
5554 project_id,
5555 buffer_id: buffer.read(cx).remote_id().into(),
5556 position: Some(serialize_anchor(&position)),
5557 trigger,
5558 version: serialize_version(&buffer.read(cx).version()),
5559 };
5560 cx.background_spawn(async move {
5561 client
5562 .request(request)
5563 .await?
5564 .transaction
5565 .map(language::proto::deserialize_transaction)
5566 .transpose()
5567 })
5568 } else if let Some(local) = self.as_local_mut() {
5569 let buffer_id = buffer.read(cx).remote_id();
5570 local.buffers_being_formatted.insert(buffer_id);
5571 cx.spawn(async move |this, cx| {
5572 let _cleanup = defer({
5573 let this = this.clone();
5574 let mut cx = cx.clone();
5575 move || {
5576 this.update(&mut cx, |this, _| {
5577 if let Some(local) = this.as_local_mut() {
5578 local.buffers_being_formatted.remove(&buffer_id);
5579 }
5580 })
5581 .ok();
5582 }
5583 });
5584
5585 buffer
5586 .update(cx, |buffer, _| {
5587 buffer.wait_for_edits(Some(position.timestamp))
5588 })
5589 .await?;
5590 this.update(cx, |this, cx| {
5591 let position = position.to_point_utf16(buffer.read(cx));
5592 this.on_type_format(buffer, position, trigger, false, cx)
5593 })?
5594 .await
5595 })
5596 } else {
5597 Task::ready(Err(anyhow!("No upstream client or local language server")))
5598 }
5599 }
5600
5601 pub fn on_type_format<T: ToPointUtf16>(
5602 &mut self,
5603 buffer: Entity<Buffer>,
5604 position: T,
5605 trigger: String,
5606 push_to_history: bool,
5607 cx: &mut Context<Self>,
5608 ) -> Task<Result<Option<Transaction>>> {
5609 let position = position.to_point_utf16(buffer.read(cx));
5610 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5611 }
5612
5613 fn on_type_format_impl(
5614 &mut self,
5615 buffer: Entity<Buffer>,
5616 position: PointUtf16,
5617 trigger: String,
5618 push_to_history: bool,
5619 cx: &mut Context<Self>,
5620 ) -> Task<Result<Option<Transaction>>> {
5621 let options = buffer.update(cx, |buffer, cx| {
5622 lsp_command::lsp_formatting_options(
5623 language_settings(
5624 buffer.language_at(position).map(|l| l.name()),
5625 buffer.file(),
5626 cx,
5627 )
5628 .as_ref(),
5629 )
5630 });
5631
5632 cx.spawn(async move |this, cx| {
5633 if let Some(waiter) =
5634 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5635 {
5636 waiter.await?;
5637 }
5638 cx.update(|cx| {
5639 this.update(cx, |this, cx| {
5640 this.request_lsp(
5641 buffer.clone(),
5642 LanguageServerToQuery::FirstCapable,
5643 OnTypeFormatting {
5644 position,
5645 trigger,
5646 options,
5647 push_to_history,
5648 },
5649 cx,
5650 )
5651 })
5652 })?
5653 .await
5654 })
5655 }
5656
5657 pub fn definitions(
5658 &mut self,
5659 buffer: &Entity<Buffer>,
5660 position: PointUtf16,
5661 cx: &mut Context<Self>,
5662 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5663 if let Some((upstream_client, project_id)) = self.upstream_client() {
5664 let request = GetDefinitions { position };
5665 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5666 return Task::ready(Ok(None));
5667 }
5668 let request_task = upstream_client.request_lsp(
5669 project_id,
5670 None,
5671 LSP_REQUEST_TIMEOUT,
5672 cx.background_executor().clone(),
5673 request.to_proto(project_id, buffer.read(cx)),
5674 );
5675 let buffer = buffer.clone();
5676 cx.spawn(async move |weak_lsp_store, cx| {
5677 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5678 return Ok(None);
5679 };
5680 let Some(responses) = request_task.await? else {
5681 return Ok(None);
5682 };
5683 let actions = join_all(responses.payload.into_iter().map(|response| {
5684 GetDefinitions { position }.response_from_proto(
5685 response.response,
5686 lsp_store.clone(),
5687 buffer.clone(),
5688 cx.clone(),
5689 )
5690 }))
5691 .await;
5692
5693 Ok(Some(
5694 actions
5695 .into_iter()
5696 .collect::<Result<Vec<Vec<_>>>>()?
5697 .into_iter()
5698 .flatten()
5699 .dedup()
5700 .collect(),
5701 ))
5702 })
5703 } else {
5704 let definitions_task = self.request_multiple_lsp_locally(
5705 buffer,
5706 Some(position),
5707 GetDefinitions { position },
5708 cx,
5709 );
5710 cx.background_spawn(async move {
5711 Ok(Some(
5712 definitions_task
5713 .await
5714 .into_iter()
5715 .flat_map(|(_, definitions)| definitions)
5716 .dedup()
5717 .collect(),
5718 ))
5719 })
5720 }
5721 }
5722
5723 pub fn declarations(
5724 &mut self,
5725 buffer: &Entity<Buffer>,
5726 position: PointUtf16,
5727 cx: &mut Context<Self>,
5728 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5729 if let Some((upstream_client, project_id)) = self.upstream_client() {
5730 let request = GetDeclarations { position };
5731 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5732 return Task::ready(Ok(None));
5733 }
5734 let request_task = upstream_client.request_lsp(
5735 project_id,
5736 None,
5737 LSP_REQUEST_TIMEOUT,
5738 cx.background_executor().clone(),
5739 request.to_proto(project_id, buffer.read(cx)),
5740 );
5741 let buffer = buffer.clone();
5742 cx.spawn(async move |weak_lsp_store, cx| {
5743 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5744 return Ok(None);
5745 };
5746 let Some(responses) = request_task.await? else {
5747 return Ok(None);
5748 };
5749 let actions = join_all(responses.payload.into_iter().map(|response| {
5750 GetDeclarations { position }.response_from_proto(
5751 response.response,
5752 lsp_store.clone(),
5753 buffer.clone(),
5754 cx.clone(),
5755 )
5756 }))
5757 .await;
5758
5759 Ok(Some(
5760 actions
5761 .into_iter()
5762 .collect::<Result<Vec<Vec<_>>>>()?
5763 .into_iter()
5764 .flatten()
5765 .dedup()
5766 .collect(),
5767 ))
5768 })
5769 } else {
5770 let declarations_task = self.request_multiple_lsp_locally(
5771 buffer,
5772 Some(position),
5773 GetDeclarations { position },
5774 cx,
5775 );
5776 cx.background_spawn(async move {
5777 Ok(Some(
5778 declarations_task
5779 .await
5780 .into_iter()
5781 .flat_map(|(_, declarations)| declarations)
5782 .dedup()
5783 .collect(),
5784 ))
5785 })
5786 }
5787 }
5788
5789 pub fn type_definitions(
5790 &mut self,
5791 buffer: &Entity<Buffer>,
5792 position: PointUtf16,
5793 cx: &mut Context<Self>,
5794 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5795 if let Some((upstream_client, project_id)) = self.upstream_client() {
5796 let request = GetTypeDefinitions { position };
5797 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5798 return Task::ready(Ok(None));
5799 }
5800 let request_task = upstream_client.request_lsp(
5801 project_id,
5802 None,
5803 LSP_REQUEST_TIMEOUT,
5804 cx.background_executor().clone(),
5805 request.to_proto(project_id, buffer.read(cx)),
5806 );
5807 let buffer = buffer.clone();
5808 cx.spawn(async move |weak_lsp_store, cx| {
5809 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5810 return Ok(None);
5811 };
5812 let Some(responses) = request_task.await? else {
5813 return Ok(None);
5814 };
5815 let actions = join_all(responses.payload.into_iter().map(|response| {
5816 GetTypeDefinitions { position }.response_from_proto(
5817 response.response,
5818 lsp_store.clone(),
5819 buffer.clone(),
5820 cx.clone(),
5821 )
5822 }))
5823 .await;
5824
5825 Ok(Some(
5826 actions
5827 .into_iter()
5828 .collect::<Result<Vec<Vec<_>>>>()?
5829 .into_iter()
5830 .flatten()
5831 .dedup()
5832 .collect(),
5833 ))
5834 })
5835 } else {
5836 let type_definitions_task = self.request_multiple_lsp_locally(
5837 buffer,
5838 Some(position),
5839 GetTypeDefinitions { position },
5840 cx,
5841 );
5842 cx.background_spawn(async move {
5843 Ok(Some(
5844 type_definitions_task
5845 .await
5846 .into_iter()
5847 .flat_map(|(_, type_definitions)| type_definitions)
5848 .dedup()
5849 .collect(),
5850 ))
5851 })
5852 }
5853 }
5854
5855 pub fn implementations(
5856 &mut self,
5857 buffer: &Entity<Buffer>,
5858 position: PointUtf16,
5859 cx: &mut Context<Self>,
5860 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5861 if let Some((upstream_client, project_id)) = self.upstream_client() {
5862 let request = GetImplementations { position };
5863 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5864 return Task::ready(Ok(None));
5865 }
5866 let request_task = upstream_client.request_lsp(
5867 project_id,
5868 None,
5869 LSP_REQUEST_TIMEOUT,
5870 cx.background_executor().clone(),
5871 request.to_proto(project_id, buffer.read(cx)),
5872 );
5873 let buffer = buffer.clone();
5874 cx.spawn(async move |weak_lsp_store, cx| {
5875 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5876 return Ok(None);
5877 };
5878 let Some(responses) = request_task.await? else {
5879 return Ok(None);
5880 };
5881 let actions = join_all(responses.payload.into_iter().map(|response| {
5882 GetImplementations { position }.response_from_proto(
5883 response.response,
5884 lsp_store.clone(),
5885 buffer.clone(),
5886 cx.clone(),
5887 )
5888 }))
5889 .await;
5890
5891 Ok(Some(
5892 actions
5893 .into_iter()
5894 .collect::<Result<Vec<Vec<_>>>>()?
5895 .into_iter()
5896 .flatten()
5897 .dedup()
5898 .collect(),
5899 ))
5900 })
5901 } else {
5902 let implementations_task = self.request_multiple_lsp_locally(
5903 buffer,
5904 Some(position),
5905 GetImplementations { position },
5906 cx,
5907 );
5908 cx.background_spawn(async move {
5909 Ok(Some(
5910 implementations_task
5911 .await
5912 .into_iter()
5913 .flat_map(|(_, implementations)| implementations)
5914 .dedup()
5915 .collect(),
5916 ))
5917 })
5918 }
5919 }
5920
5921 pub fn references(
5922 &mut self,
5923 buffer: &Entity<Buffer>,
5924 position: PointUtf16,
5925 cx: &mut Context<Self>,
5926 ) -> Task<Result<Option<Vec<Location>>>> {
5927 if let Some((upstream_client, project_id)) = self.upstream_client() {
5928 let request = GetReferences { position };
5929 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5930 return Task::ready(Ok(None));
5931 }
5932
5933 let request_task = upstream_client.request_lsp(
5934 project_id,
5935 None,
5936 LSP_REQUEST_TIMEOUT,
5937 cx.background_executor().clone(),
5938 request.to_proto(project_id, buffer.read(cx)),
5939 );
5940 let buffer = buffer.clone();
5941 cx.spawn(async move |weak_lsp_store, cx| {
5942 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5943 return Ok(None);
5944 };
5945 let Some(responses) = request_task.await? else {
5946 return Ok(None);
5947 };
5948
5949 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5950 GetReferences { position }.response_from_proto(
5951 lsp_response.response,
5952 lsp_store.clone(),
5953 buffer.clone(),
5954 cx.clone(),
5955 )
5956 }))
5957 .await
5958 .into_iter()
5959 .collect::<Result<Vec<Vec<_>>>>()?
5960 .into_iter()
5961 .flatten()
5962 .dedup()
5963 .collect();
5964 Ok(Some(locations))
5965 })
5966 } else {
5967 let references_task = self.request_multiple_lsp_locally(
5968 buffer,
5969 Some(position),
5970 GetReferences { position },
5971 cx,
5972 );
5973 cx.background_spawn(async move {
5974 Ok(Some(
5975 references_task
5976 .await
5977 .into_iter()
5978 .flat_map(|(_, references)| references)
5979 .dedup()
5980 .collect(),
5981 ))
5982 })
5983 }
5984 }
5985
5986 pub fn code_actions(
5987 &mut self,
5988 buffer: &Entity<Buffer>,
5989 range: Range<Anchor>,
5990 kinds: Option<Vec<CodeActionKind>>,
5991 cx: &mut Context<Self>,
5992 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5993 if let Some((upstream_client, project_id)) = self.upstream_client() {
5994 let request = GetCodeActions {
5995 range: range.clone(),
5996 kinds: kinds.clone(),
5997 };
5998 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5999 return Task::ready(Ok(None));
6000 }
6001 let request_task = upstream_client.request_lsp(
6002 project_id,
6003 None,
6004 LSP_REQUEST_TIMEOUT,
6005 cx.background_executor().clone(),
6006 request.to_proto(project_id, buffer.read(cx)),
6007 );
6008 let buffer = buffer.clone();
6009 cx.spawn(async move |weak_lsp_store, cx| {
6010 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6011 return Ok(None);
6012 };
6013 let Some(responses) = request_task.await? else {
6014 return Ok(None);
6015 };
6016 let actions = join_all(responses.payload.into_iter().map(|response| {
6017 GetCodeActions {
6018 range: range.clone(),
6019 kinds: kinds.clone(),
6020 }
6021 .response_from_proto(
6022 response.response,
6023 lsp_store.clone(),
6024 buffer.clone(),
6025 cx.clone(),
6026 )
6027 }))
6028 .await;
6029
6030 Ok(Some(
6031 actions
6032 .into_iter()
6033 .collect::<Result<Vec<Vec<_>>>>()?
6034 .into_iter()
6035 .flatten()
6036 .collect(),
6037 ))
6038 })
6039 } else {
6040 let all_actions_task = self.request_multiple_lsp_locally(
6041 buffer,
6042 Some(range.start),
6043 GetCodeActions { range, kinds },
6044 cx,
6045 );
6046 cx.background_spawn(async move {
6047 Ok(Some(
6048 all_actions_task
6049 .await
6050 .into_iter()
6051 .flat_map(|(_, actions)| actions)
6052 .collect(),
6053 ))
6054 })
6055 }
6056 }
6057
6058 pub fn code_lens_actions(
6059 &mut self,
6060 buffer: &Entity<Buffer>,
6061 cx: &mut Context<Self>,
6062 ) -> CodeLensTask {
6063 let version_queried_for = buffer.read(cx).version();
6064 let buffer_id = buffer.read(cx).remote_id();
6065 let existing_servers = self.as_local().map(|local| {
6066 local
6067 .buffers_opened_in_servers
6068 .get(&buffer_id)
6069 .cloned()
6070 .unwrap_or_default()
6071 });
6072
6073 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6074 if let Some(cached_lens) = &lsp_data.code_lens {
6075 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6076 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6077 existing_servers != cached_lens.lens.keys().copied().collect()
6078 });
6079 if !has_different_servers {
6080 return Task::ready(Ok(Some(
6081 cached_lens.lens.values().flatten().cloned().collect(),
6082 )))
6083 .shared();
6084 }
6085 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6086 if !version_queried_for.changed_since(updating_for) {
6087 return running_update.clone();
6088 }
6089 }
6090 }
6091 }
6092
6093 let lens_lsp_data = self
6094 .latest_lsp_data(buffer, cx)
6095 .code_lens
6096 .get_or_insert_default();
6097 let buffer = buffer.clone();
6098 let query_version_queried_for = version_queried_for.clone();
6099 let new_task = cx
6100 .spawn(async move |lsp_store, cx| {
6101 cx.background_executor()
6102 .timer(Duration::from_millis(30))
6103 .await;
6104 let fetched_lens = lsp_store
6105 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6106 .map_err(Arc::new)?
6107 .await
6108 .context("fetching code lens")
6109 .map_err(Arc::new);
6110 let fetched_lens = match fetched_lens {
6111 Ok(fetched_lens) => fetched_lens,
6112 Err(e) => {
6113 lsp_store
6114 .update(cx, |lsp_store, _| {
6115 if let Some(lens_lsp_data) = lsp_store
6116 .lsp_data
6117 .get_mut(&buffer_id)
6118 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6119 {
6120 lens_lsp_data.update = None;
6121 }
6122 })
6123 .ok();
6124 return Err(e);
6125 }
6126 };
6127
6128 lsp_store
6129 .update(cx, |lsp_store, _| {
6130 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6131 let code_lens = lsp_data.code_lens.as_mut()?;
6132 if let Some(fetched_lens) = fetched_lens {
6133 if lsp_data.buffer_version == query_version_queried_for {
6134 code_lens.lens.extend(fetched_lens);
6135 } else if !lsp_data
6136 .buffer_version
6137 .changed_since(&query_version_queried_for)
6138 {
6139 lsp_data.buffer_version = query_version_queried_for;
6140 code_lens.lens = fetched_lens;
6141 }
6142 }
6143 code_lens.update = None;
6144 Some(code_lens.lens.values().flatten().cloned().collect())
6145 })
6146 .map_err(Arc::new)
6147 })
6148 .shared();
6149 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6150 new_task
6151 }
6152
6153 fn fetch_code_lens(
6154 &mut self,
6155 buffer: &Entity<Buffer>,
6156 cx: &mut Context<Self>,
6157 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6158 if let Some((upstream_client, project_id)) = self.upstream_client() {
6159 let request = GetCodeLens;
6160 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6161 return Task::ready(Ok(None));
6162 }
6163 let request_task = upstream_client.request_lsp(
6164 project_id,
6165 None,
6166 LSP_REQUEST_TIMEOUT,
6167 cx.background_executor().clone(),
6168 request.to_proto(project_id, buffer.read(cx)),
6169 );
6170 let buffer = buffer.clone();
6171 cx.spawn(async move |weak_lsp_store, cx| {
6172 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6173 return Ok(None);
6174 };
6175 let Some(responses) = request_task.await? else {
6176 return Ok(None);
6177 };
6178
6179 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6180 let lsp_store = lsp_store.clone();
6181 let buffer = buffer.clone();
6182 let cx = cx.clone();
6183 async move {
6184 (
6185 LanguageServerId::from_proto(response.server_id),
6186 GetCodeLens
6187 .response_from_proto(response.response, lsp_store, buffer, cx)
6188 .await,
6189 )
6190 }
6191 }))
6192 .await;
6193
6194 let mut has_errors = false;
6195 let code_lens_actions = code_lens_actions
6196 .into_iter()
6197 .filter_map(|(server_id, code_lens)| match code_lens {
6198 Ok(code_lens) => Some((server_id, code_lens)),
6199 Err(e) => {
6200 has_errors = true;
6201 log::error!("{e:#}");
6202 None
6203 }
6204 })
6205 .collect::<HashMap<_, _>>();
6206 anyhow::ensure!(
6207 !has_errors || !code_lens_actions.is_empty(),
6208 "Failed to fetch code lens"
6209 );
6210 Ok(Some(code_lens_actions))
6211 })
6212 } else {
6213 let code_lens_actions_task =
6214 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6215 cx.background_spawn(async move {
6216 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6217 })
6218 }
6219 }
6220
6221 #[inline(never)]
6222 pub fn completions(
6223 &self,
6224 buffer: &Entity<Buffer>,
6225 position: PointUtf16,
6226 context: CompletionContext,
6227 cx: &mut Context<Self>,
6228 ) -> Task<Result<Vec<CompletionResponse>>> {
6229 let language_registry = self.languages.clone();
6230
6231 if let Some((upstream_client, project_id)) = self.upstream_client() {
6232 let snapshot = buffer.read(cx).snapshot();
6233 let offset = position.to_offset(&snapshot);
6234 let scope = snapshot.language_scope_at(offset);
6235 let capable_lsps = self.all_capable_for_proto_request(
6236 buffer,
6237 |server_name, capabilities| {
6238 capabilities.completion_provider.is_some()
6239 && scope
6240 .as_ref()
6241 .map(|scope| scope.language_allowed(server_name))
6242 .unwrap_or(true)
6243 },
6244 cx,
6245 );
6246 if capable_lsps.is_empty() {
6247 return Task::ready(Ok(Vec::new()));
6248 }
6249
6250 let language = buffer.read(cx).language().cloned();
6251
6252 // In the future, we should provide project guests with the names of LSP adapters,
6253 // so that they can use the correct LSP adapter when computing labels. For now,
6254 // guests just use the first LSP adapter associated with the buffer's language.
6255 let lsp_adapter = language.as_ref().and_then(|language| {
6256 language_registry
6257 .lsp_adapters(&language.name())
6258 .first()
6259 .cloned()
6260 });
6261
6262 let buffer = buffer.clone();
6263
6264 cx.spawn(async move |this, cx| {
6265 let requests = join_all(
6266 capable_lsps
6267 .into_iter()
6268 .map(|id| {
6269 let request = GetCompletions {
6270 position,
6271 context: context.clone(),
6272 server_id: Some(id),
6273 };
6274 let buffer = buffer.clone();
6275 let language = language.clone();
6276 let lsp_adapter = lsp_adapter.clone();
6277 let upstream_client = upstream_client.clone();
6278 let response = this
6279 .update(cx, |this, cx| {
6280 this.send_lsp_proto_request(
6281 buffer,
6282 upstream_client,
6283 project_id,
6284 request,
6285 cx,
6286 )
6287 })
6288 .log_err();
6289 async move {
6290 let response = response?.await.log_err()?;
6291
6292 let completions = populate_labels_for_completions(
6293 response.completions,
6294 language,
6295 lsp_adapter,
6296 )
6297 .await;
6298
6299 Some(CompletionResponse {
6300 completions,
6301 display_options: CompletionDisplayOptions::default(),
6302 is_incomplete: response.is_incomplete,
6303 })
6304 }
6305 })
6306 .collect::<Vec<_>>(),
6307 );
6308 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6309 })
6310 } else if let Some(local) = self.as_local() {
6311 let snapshot = buffer.read(cx).snapshot();
6312 let offset = position.to_offset(&snapshot);
6313 let scope = snapshot.language_scope_at(offset);
6314 let language = snapshot.language().cloned();
6315 let completion_settings = language_settings(
6316 language.as_ref().map(|language| language.name()),
6317 buffer.read(cx).file(),
6318 cx,
6319 )
6320 .completions
6321 .clone();
6322 if !completion_settings.lsp {
6323 return Task::ready(Ok(Vec::new()));
6324 }
6325
6326 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6327 local
6328 .language_servers_for_buffer(buffer, cx)
6329 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6330 .filter(|(adapter, _)| {
6331 scope
6332 .as_ref()
6333 .map(|scope| scope.language_allowed(&adapter.name))
6334 .unwrap_or(true)
6335 })
6336 .map(|(_, server)| server.server_id())
6337 .collect()
6338 });
6339
6340 let buffer = buffer.clone();
6341 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6342 let lsp_timeout = if lsp_timeout > 0 {
6343 Some(Duration::from_millis(lsp_timeout))
6344 } else {
6345 None
6346 };
6347 cx.spawn(async move |this, cx| {
6348 let mut tasks = Vec::with_capacity(server_ids.len());
6349 this.update(cx, |lsp_store, cx| {
6350 for server_id in server_ids {
6351 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6352 let lsp_timeout = lsp_timeout
6353 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6354 let mut timeout = cx.background_spawn(async move {
6355 match lsp_timeout {
6356 Some(lsp_timeout) => {
6357 lsp_timeout.await;
6358 true
6359 },
6360 None => false,
6361 }
6362 }).fuse();
6363 let mut lsp_request = lsp_store.request_lsp(
6364 buffer.clone(),
6365 LanguageServerToQuery::Other(server_id),
6366 GetCompletions {
6367 position,
6368 context: context.clone(),
6369 server_id: Some(server_id),
6370 },
6371 cx,
6372 ).fuse();
6373 let new_task = cx.background_spawn(async move {
6374 select_biased! {
6375 response = lsp_request => anyhow::Ok(Some(response?)),
6376 timeout_happened = timeout => {
6377 if timeout_happened {
6378 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6379 Ok(None)
6380 } else {
6381 let completions = lsp_request.await?;
6382 Ok(Some(completions))
6383 }
6384 },
6385 }
6386 });
6387 tasks.push((lsp_adapter, new_task));
6388 }
6389 })?;
6390
6391 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6392 let completion_response = task.await.ok()??;
6393 let completions = populate_labels_for_completions(
6394 completion_response.completions,
6395 language.clone(),
6396 lsp_adapter,
6397 )
6398 .await;
6399 Some(CompletionResponse {
6400 completions,
6401 display_options: CompletionDisplayOptions::default(),
6402 is_incomplete: completion_response.is_incomplete,
6403 })
6404 });
6405
6406 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6407
6408 Ok(responses.into_iter().flatten().collect())
6409 })
6410 } else {
6411 Task::ready(Err(anyhow!("No upstream client or local language server")))
6412 }
6413 }
6414
6415 pub fn resolve_completions(
6416 &self,
6417 buffer: Entity<Buffer>,
6418 completion_indices: Vec<usize>,
6419 completions: Rc<RefCell<Box<[Completion]>>>,
6420 cx: &mut Context<Self>,
6421 ) -> Task<Result<bool>> {
6422 let client = self.upstream_client();
6423 let buffer_id = buffer.read(cx).remote_id();
6424 let buffer_snapshot = buffer.read(cx).snapshot();
6425
6426 if !self.check_if_capable_for_proto_request(
6427 &buffer,
6428 GetCompletions::can_resolve_completions,
6429 cx,
6430 ) {
6431 return Task::ready(Ok(false));
6432 }
6433 cx.spawn(async move |lsp_store, cx| {
6434 let mut did_resolve = false;
6435 if let Some((client, project_id)) = client {
6436 for completion_index in completion_indices {
6437 let server_id = {
6438 let completion = &completions.borrow()[completion_index];
6439 completion.source.server_id()
6440 };
6441 if let Some(server_id) = server_id {
6442 if Self::resolve_completion_remote(
6443 project_id,
6444 server_id,
6445 buffer_id,
6446 completions.clone(),
6447 completion_index,
6448 client.clone(),
6449 )
6450 .await
6451 .log_err()
6452 .is_some()
6453 {
6454 did_resolve = true;
6455 }
6456 } else {
6457 resolve_word_completion(
6458 &buffer_snapshot,
6459 &mut completions.borrow_mut()[completion_index],
6460 );
6461 }
6462 }
6463 } else {
6464 for completion_index in completion_indices {
6465 let server_id = {
6466 let completion = &completions.borrow()[completion_index];
6467 completion.source.server_id()
6468 };
6469 if let Some(server_id) = server_id {
6470 let server_and_adapter = lsp_store
6471 .read_with(cx, |lsp_store, _| {
6472 let server = lsp_store.language_server_for_id(server_id)?;
6473 let adapter =
6474 lsp_store.language_server_adapter_for_id(server.server_id())?;
6475 Some((server, adapter))
6476 })
6477 .ok()
6478 .flatten();
6479 let Some((server, adapter)) = server_and_adapter else {
6480 continue;
6481 };
6482
6483 let resolved = Self::resolve_completion_local(
6484 server,
6485 completions.clone(),
6486 completion_index,
6487 )
6488 .await
6489 .log_err()
6490 .is_some();
6491 if resolved {
6492 Self::regenerate_completion_labels(
6493 adapter,
6494 &buffer_snapshot,
6495 completions.clone(),
6496 completion_index,
6497 )
6498 .await
6499 .log_err();
6500 did_resolve = true;
6501 }
6502 } else {
6503 resolve_word_completion(
6504 &buffer_snapshot,
6505 &mut completions.borrow_mut()[completion_index],
6506 );
6507 }
6508 }
6509 }
6510
6511 Ok(did_resolve)
6512 })
6513 }
6514
6515 async fn resolve_completion_local(
6516 server: Arc<lsp::LanguageServer>,
6517 completions: Rc<RefCell<Box<[Completion]>>>,
6518 completion_index: usize,
6519 ) -> Result<()> {
6520 let server_id = server.server_id();
6521 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6522 return Ok(());
6523 }
6524
6525 let request = {
6526 let completion = &completions.borrow()[completion_index];
6527 match &completion.source {
6528 CompletionSource::Lsp {
6529 lsp_completion,
6530 resolved,
6531 server_id: completion_server_id,
6532 ..
6533 } => {
6534 if *resolved {
6535 return Ok(());
6536 }
6537 anyhow::ensure!(
6538 server_id == *completion_server_id,
6539 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6540 );
6541 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6542 }
6543 CompletionSource::BufferWord { .. }
6544 | CompletionSource::Dap { .. }
6545 | CompletionSource::Custom => {
6546 return Ok(());
6547 }
6548 }
6549 };
6550 let resolved_completion = request
6551 .await
6552 .into_response()
6553 .context("resolve completion")?;
6554
6555 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6556 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6557
6558 let mut completions = completions.borrow_mut();
6559 let completion = &mut completions[completion_index];
6560 if let CompletionSource::Lsp {
6561 lsp_completion,
6562 resolved,
6563 server_id: completion_server_id,
6564 ..
6565 } = &mut completion.source
6566 {
6567 if *resolved {
6568 return Ok(());
6569 }
6570 anyhow::ensure!(
6571 server_id == *completion_server_id,
6572 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6573 );
6574 **lsp_completion = resolved_completion;
6575 *resolved = true;
6576 }
6577 Ok(())
6578 }
6579
6580 async fn regenerate_completion_labels(
6581 adapter: Arc<CachedLspAdapter>,
6582 snapshot: &BufferSnapshot,
6583 completions: Rc<RefCell<Box<[Completion]>>>,
6584 completion_index: usize,
6585 ) -> Result<()> {
6586 let completion_item = completions.borrow()[completion_index]
6587 .source
6588 .lsp_completion(true)
6589 .map(Cow::into_owned);
6590 if let Some(lsp_documentation) = completion_item
6591 .as_ref()
6592 .and_then(|completion_item| completion_item.documentation.clone())
6593 {
6594 let mut completions = completions.borrow_mut();
6595 let completion = &mut completions[completion_index];
6596 completion.documentation = Some(lsp_documentation.into());
6597 } else {
6598 let mut completions = completions.borrow_mut();
6599 let completion = &mut completions[completion_index];
6600 completion.documentation = Some(CompletionDocumentation::Undocumented);
6601 }
6602
6603 let mut new_label = match completion_item {
6604 Some(completion_item) => {
6605 // Some language servers always return `detail` lazily via resolve, regardless of
6606 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6607 // See: https://github.com/yioneko/vtsls/issues/213
6608 let language = snapshot.language();
6609 match language {
6610 Some(language) => {
6611 adapter
6612 .labels_for_completions(
6613 std::slice::from_ref(&completion_item),
6614 language,
6615 )
6616 .await?
6617 }
6618 None => Vec::new(),
6619 }
6620 .pop()
6621 .flatten()
6622 .unwrap_or_else(|| {
6623 CodeLabel::fallback_for_completion(
6624 &completion_item,
6625 language.map(|language| language.as_ref()),
6626 )
6627 })
6628 }
6629 None => CodeLabel::plain(
6630 completions.borrow()[completion_index].new_text.clone(),
6631 None,
6632 ),
6633 };
6634 ensure_uniform_list_compatible_label(&mut new_label);
6635
6636 let mut completions = completions.borrow_mut();
6637 let completion = &mut completions[completion_index];
6638 if completion.label.filter_text() == new_label.filter_text() {
6639 completion.label = new_label;
6640 } else {
6641 log::error!(
6642 "Resolved completion changed display label from {} to {}. \
6643 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6644 completion.label.text(),
6645 new_label.text(),
6646 completion.label.filter_text(),
6647 new_label.filter_text()
6648 );
6649 }
6650
6651 Ok(())
6652 }
6653
6654 async fn resolve_completion_remote(
6655 project_id: u64,
6656 server_id: LanguageServerId,
6657 buffer_id: BufferId,
6658 completions: Rc<RefCell<Box<[Completion]>>>,
6659 completion_index: usize,
6660 client: AnyProtoClient,
6661 ) -> Result<()> {
6662 let lsp_completion = {
6663 let completion = &completions.borrow()[completion_index];
6664 match &completion.source {
6665 CompletionSource::Lsp {
6666 lsp_completion,
6667 resolved,
6668 server_id: completion_server_id,
6669 ..
6670 } => {
6671 anyhow::ensure!(
6672 server_id == *completion_server_id,
6673 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6674 );
6675 if *resolved {
6676 return Ok(());
6677 }
6678 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6679 }
6680 CompletionSource::Custom
6681 | CompletionSource::Dap { .. }
6682 | CompletionSource::BufferWord { .. } => {
6683 return Ok(());
6684 }
6685 }
6686 };
6687 let request = proto::ResolveCompletionDocumentation {
6688 project_id,
6689 language_server_id: server_id.0 as u64,
6690 lsp_completion,
6691 buffer_id: buffer_id.into(),
6692 };
6693
6694 let response = client
6695 .request(request)
6696 .await
6697 .context("completion documentation resolve proto request")?;
6698 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6699
6700 let documentation = if response.documentation.is_empty() {
6701 CompletionDocumentation::Undocumented
6702 } else if response.documentation_is_markdown {
6703 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6704 } else if response.documentation.lines().count() <= 1 {
6705 CompletionDocumentation::SingleLine(response.documentation.into())
6706 } else {
6707 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6708 };
6709
6710 let mut completions = completions.borrow_mut();
6711 let completion = &mut completions[completion_index];
6712 completion.documentation = Some(documentation);
6713 if let CompletionSource::Lsp {
6714 insert_range,
6715 lsp_completion,
6716 resolved,
6717 server_id: completion_server_id,
6718 lsp_defaults: _,
6719 } = &mut completion.source
6720 {
6721 let completion_insert_range = response
6722 .old_insert_start
6723 .and_then(deserialize_anchor)
6724 .zip(response.old_insert_end.and_then(deserialize_anchor));
6725 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6726
6727 if *resolved {
6728 return Ok(());
6729 }
6730 anyhow::ensure!(
6731 server_id == *completion_server_id,
6732 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6733 );
6734 **lsp_completion = resolved_lsp_completion;
6735 *resolved = true;
6736 }
6737
6738 let replace_range = response
6739 .old_replace_start
6740 .and_then(deserialize_anchor)
6741 .zip(response.old_replace_end.and_then(deserialize_anchor));
6742 if let Some((old_replace_start, old_replace_end)) = replace_range
6743 && !response.new_text.is_empty()
6744 {
6745 completion.new_text = response.new_text;
6746 completion.replace_range = old_replace_start..old_replace_end;
6747 }
6748
6749 Ok(())
6750 }
6751
6752 pub fn apply_additional_edits_for_completion(
6753 &self,
6754 buffer_handle: Entity<Buffer>,
6755 completions: Rc<RefCell<Box<[Completion]>>>,
6756 completion_index: usize,
6757 push_to_history: bool,
6758 cx: &mut Context<Self>,
6759 ) -> Task<Result<Option<Transaction>>> {
6760 if let Some((client, project_id)) = self.upstream_client() {
6761 let buffer = buffer_handle.read(cx);
6762 let buffer_id = buffer.remote_id();
6763 cx.spawn(async move |_, cx| {
6764 let request = {
6765 let completion = completions.borrow()[completion_index].clone();
6766 proto::ApplyCompletionAdditionalEdits {
6767 project_id,
6768 buffer_id: buffer_id.into(),
6769 completion: Some(Self::serialize_completion(&CoreCompletion {
6770 replace_range: completion.replace_range,
6771 new_text: completion.new_text,
6772 source: completion.source,
6773 })),
6774 }
6775 };
6776
6777 if let Some(transaction) = client.request(request).await?.transaction {
6778 let transaction = language::proto::deserialize_transaction(transaction)?;
6779 buffer_handle
6780 .update(cx, |buffer, _| {
6781 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6782 })
6783 .await?;
6784 if push_to_history {
6785 buffer_handle.update(cx, |buffer, _| {
6786 buffer.push_transaction(transaction.clone(), Instant::now());
6787 buffer.finalize_last_transaction();
6788 });
6789 }
6790 Ok(Some(transaction))
6791 } else {
6792 Ok(None)
6793 }
6794 })
6795 } else {
6796 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6797 let completion = &completions.borrow()[completion_index];
6798 let server_id = completion.source.server_id()?;
6799 Some(
6800 self.language_server_for_local_buffer(buffer, server_id, cx)?
6801 .1
6802 .clone(),
6803 )
6804 }) else {
6805 return Task::ready(Ok(None));
6806 };
6807
6808 cx.spawn(async move |this, cx| {
6809 Self::resolve_completion_local(
6810 server.clone(),
6811 completions.clone(),
6812 completion_index,
6813 )
6814 .await
6815 .context("resolving completion")?;
6816 let completion = completions.borrow()[completion_index].clone();
6817 let additional_text_edits = completion
6818 .source
6819 .lsp_completion(true)
6820 .as_ref()
6821 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6822 if let Some(edits) = additional_text_edits {
6823 let edits = this
6824 .update(cx, |this, cx| {
6825 this.as_local_mut().unwrap().edits_from_lsp(
6826 &buffer_handle,
6827 edits,
6828 server.server_id(),
6829 None,
6830 cx,
6831 )
6832 })?
6833 .await?;
6834
6835 buffer_handle.update(cx, |buffer, cx| {
6836 buffer.finalize_last_transaction();
6837 buffer.start_transaction();
6838
6839 for (range, text) in edits {
6840 let primary = &completion.replace_range;
6841
6842 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6843 // and the primary completion is just an insertion (empty range), then this is likely
6844 // an auto-import scenario and should not be considered overlapping
6845 // https://github.com/zed-industries/zed/issues/26136
6846 let is_file_start_auto_import = {
6847 let snapshot = buffer.snapshot();
6848 let primary_start_point = primary.start.to_point(&snapshot);
6849 let range_start_point = range.start.to_point(&snapshot);
6850
6851 let result = primary_start_point.row == 0
6852 && primary_start_point.column == 0
6853 && range_start_point.row == 0
6854 && range_start_point.column == 0;
6855
6856 result
6857 };
6858
6859 let has_overlap = if is_file_start_auto_import {
6860 false
6861 } else {
6862 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6863 && primary.end.cmp(&range.start, buffer).is_ge();
6864 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6865 && range.end.cmp(&primary.end, buffer).is_ge();
6866 let result = start_within || end_within;
6867 result
6868 };
6869
6870 //Skip additional edits which overlap with the primary completion edit
6871 //https://github.com/zed-industries/zed/pull/1871
6872 if !has_overlap {
6873 buffer.edit([(range, text)], None, cx);
6874 }
6875 }
6876
6877 let transaction = if buffer.end_transaction(cx).is_some() {
6878 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6879 if !push_to_history {
6880 buffer.forget_transaction(transaction.id);
6881 }
6882 Some(transaction)
6883 } else {
6884 None
6885 };
6886 Ok(transaction)
6887 })
6888 } else {
6889 Ok(None)
6890 }
6891 })
6892 }
6893 }
6894
6895 pub fn pull_diagnostics(
6896 &mut self,
6897 buffer: Entity<Buffer>,
6898 cx: &mut Context<Self>,
6899 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6900 let buffer_id = buffer.read(cx).remote_id();
6901
6902 if let Some((client, upstream_project_id)) = self.upstream_client() {
6903 let mut suitable_capabilities = None;
6904 // Are we capable for proto request?
6905 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6906 &buffer,
6907 |capabilities| {
6908 if let Some(caps) = &capabilities.diagnostic_provider {
6909 suitable_capabilities = Some(caps.clone());
6910 true
6911 } else {
6912 false
6913 }
6914 },
6915 cx,
6916 );
6917 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6918 let Some(dynamic_caps) = suitable_capabilities else {
6919 return Task::ready(Ok(None));
6920 };
6921 assert!(any_server_has_diagnostics_provider);
6922
6923 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6924 let request = GetDocumentDiagnostics {
6925 previous_result_id: None,
6926 identifier,
6927 registration_id: None,
6928 };
6929 let request_task = client.request_lsp(
6930 upstream_project_id,
6931 None,
6932 LSP_REQUEST_TIMEOUT,
6933 cx.background_executor().clone(),
6934 request.to_proto(upstream_project_id, buffer.read(cx)),
6935 );
6936 cx.background_spawn(async move {
6937 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6938 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6939 // Do not attempt to further process the dummy responses here.
6940 let _response = request_task.await?;
6941 Ok(None)
6942 })
6943 } else {
6944 let servers = buffer.update(cx, |buffer, cx| {
6945 self.running_language_servers_for_local_buffer(buffer, cx)
6946 .map(|(_, server)| server.clone())
6947 .collect::<Vec<_>>()
6948 });
6949
6950 let pull_diagnostics = servers
6951 .into_iter()
6952 .flat_map(|server| {
6953 let result = maybe!({
6954 let local = self.as_local()?;
6955 let server_id = server.server_id();
6956 let providers_with_identifiers = local
6957 .language_server_dynamic_registrations
6958 .get(&server_id)
6959 .into_iter()
6960 .flat_map(|registrations| registrations.diagnostics.clone())
6961 .collect::<Vec<_>>();
6962 Some(
6963 providers_with_identifiers
6964 .into_iter()
6965 .map(|(registration_id, dynamic_caps)| {
6966 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6967 let registration_id = registration_id.map(SharedString::from);
6968 let result_id = self.result_id_for_buffer_pull(
6969 server_id,
6970 buffer_id,
6971 ®istration_id,
6972 cx,
6973 );
6974 self.request_lsp(
6975 buffer.clone(),
6976 LanguageServerToQuery::Other(server_id),
6977 GetDocumentDiagnostics {
6978 previous_result_id: result_id,
6979 registration_id,
6980 identifier,
6981 },
6982 cx,
6983 )
6984 })
6985 .collect::<Vec<_>>(),
6986 )
6987 });
6988
6989 result.unwrap_or_default()
6990 })
6991 .collect::<Vec<_>>();
6992
6993 cx.background_spawn(async move {
6994 let mut responses = Vec::new();
6995 for diagnostics in join_all(pull_diagnostics).await {
6996 responses.extend(diagnostics?);
6997 }
6998 Ok(Some(responses))
6999 })
7000 }
7001 }
7002
7003 pub fn applicable_inlay_chunks(
7004 &mut self,
7005 buffer: &Entity<Buffer>,
7006 ranges: &[Range<text::Anchor>],
7007 cx: &mut Context<Self>,
7008 ) -> Vec<Range<BufferRow>> {
7009 let buffer_snapshot = buffer.read(cx).snapshot();
7010 let ranges = ranges
7011 .iter()
7012 .map(|range| range.to_point(&buffer_snapshot))
7013 .collect::<Vec<_>>();
7014
7015 self.latest_lsp_data(buffer, cx)
7016 .inlay_hints
7017 .applicable_chunks(ranges.as_slice())
7018 .map(|chunk| chunk.row_range())
7019 .collect()
7020 }
7021
7022 pub fn invalidate_inlay_hints<'a>(
7023 &'a mut self,
7024 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7025 ) {
7026 for buffer_id in for_buffers {
7027 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7028 lsp_data.inlay_hints.clear();
7029 }
7030 }
7031 }
7032
7033 pub fn inlay_hints(
7034 &mut self,
7035 invalidate: InvalidationStrategy,
7036 buffer: Entity<Buffer>,
7037 ranges: Vec<Range<text::Anchor>>,
7038 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7039 cx: &mut Context<Self>,
7040 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7041 let next_hint_id = self.next_hint_id.clone();
7042 let lsp_data = self.latest_lsp_data(&buffer, cx);
7043 let query_version = lsp_data.buffer_version.clone();
7044 let mut lsp_refresh_requested = false;
7045 let for_server = if let InvalidationStrategy::RefreshRequested {
7046 server_id,
7047 request_id,
7048 } = invalidate
7049 {
7050 let invalidated = lsp_data
7051 .inlay_hints
7052 .invalidate_for_server_refresh(server_id, request_id);
7053 lsp_refresh_requested = invalidated;
7054 Some(server_id)
7055 } else {
7056 None
7057 };
7058 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7059 let known_chunks = known_chunks
7060 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7061 .map(|(_, known_chunks)| known_chunks)
7062 .unwrap_or_default();
7063
7064 let buffer_snapshot = buffer.read(cx).snapshot();
7065 let ranges = ranges
7066 .iter()
7067 .map(|range| range.to_point(&buffer_snapshot))
7068 .collect::<Vec<_>>();
7069
7070 let mut hint_fetch_tasks = Vec::new();
7071 let mut cached_inlay_hints = None;
7072 let mut ranges_to_query = None;
7073 let applicable_chunks = existing_inlay_hints
7074 .applicable_chunks(ranges.as_slice())
7075 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7076 .collect::<Vec<_>>();
7077 if applicable_chunks.is_empty() {
7078 return HashMap::default();
7079 }
7080
7081 for row_chunk in applicable_chunks {
7082 match (
7083 existing_inlay_hints
7084 .cached_hints(&row_chunk)
7085 .filter(|_| !lsp_refresh_requested)
7086 .cloned(),
7087 existing_inlay_hints
7088 .fetched_hints(&row_chunk)
7089 .as_ref()
7090 .filter(|_| !lsp_refresh_requested)
7091 .cloned(),
7092 ) {
7093 (None, None) => {
7094 let chunk_range = row_chunk.anchor_range();
7095 ranges_to_query
7096 .get_or_insert_with(Vec::new)
7097 .push((row_chunk, chunk_range));
7098 }
7099 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7100 (Some(cached_hints), None) => {
7101 for (server_id, cached_hints) in cached_hints {
7102 if for_server.is_none_or(|for_server| for_server == server_id) {
7103 cached_inlay_hints
7104 .get_or_insert_with(HashMap::default)
7105 .entry(row_chunk.row_range())
7106 .or_insert_with(HashMap::default)
7107 .entry(server_id)
7108 .or_insert_with(Vec::new)
7109 .extend(cached_hints);
7110 }
7111 }
7112 }
7113 (Some(cached_hints), Some(fetched_hints)) => {
7114 hint_fetch_tasks.push((row_chunk, fetched_hints));
7115 for (server_id, cached_hints) in cached_hints {
7116 if for_server.is_none_or(|for_server| for_server == server_id) {
7117 cached_inlay_hints
7118 .get_or_insert_with(HashMap::default)
7119 .entry(row_chunk.row_range())
7120 .or_insert_with(HashMap::default)
7121 .entry(server_id)
7122 .or_insert_with(Vec::new)
7123 .extend(cached_hints);
7124 }
7125 }
7126 }
7127 }
7128 }
7129
7130 if hint_fetch_tasks.is_empty()
7131 && ranges_to_query
7132 .as_ref()
7133 .is_none_or(|ranges| ranges.is_empty())
7134 && let Some(cached_inlay_hints) = cached_inlay_hints
7135 {
7136 cached_inlay_hints
7137 .into_iter()
7138 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7139 .collect()
7140 } else {
7141 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7142 let next_hint_id = next_hint_id.clone();
7143 let buffer = buffer.clone();
7144 let query_version = query_version.clone();
7145 let new_inlay_hints = cx
7146 .spawn(async move |lsp_store, cx| {
7147 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7148 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7149 })?;
7150 new_fetch_task
7151 .await
7152 .and_then(|new_hints_by_server| {
7153 lsp_store.update(cx, |lsp_store, cx| {
7154 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7155 let update_cache = lsp_data.buffer_version == query_version;
7156 if new_hints_by_server.is_empty() {
7157 if update_cache {
7158 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7159 }
7160 HashMap::default()
7161 } else {
7162 new_hints_by_server
7163 .into_iter()
7164 .map(|(server_id, new_hints)| {
7165 let new_hints = new_hints
7166 .into_iter()
7167 .map(|new_hint| {
7168 (
7169 InlayId::Hint(next_hint_id.fetch_add(
7170 1,
7171 atomic::Ordering::AcqRel,
7172 )),
7173 new_hint,
7174 )
7175 })
7176 .collect::<Vec<_>>();
7177 if update_cache {
7178 lsp_data.inlay_hints.insert_new_hints(
7179 chunk,
7180 server_id,
7181 new_hints.clone(),
7182 );
7183 }
7184 (server_id, new_hints)
7185 })
7186 .collect()
7187 }
7188 })
7189 })
7190 .map_err(Arc::new)
7191 })
7192 .shared();
7193
7194 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7195 *fetch_task = Some(new_inlay_hints.clone());
7196 hint_fetch_tasks.push((chunk, new_inlay_hints));
7197 }
7198
7199 cached_inlay_hints
7200 .unwrap_or_default()
7201 .into_iter()
7202 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7203 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7204 (
7205 chunk.row_range(),
7206 cx.spawn(async move |_, _| {
7207 hints_fetch.await.map_err(|e| {
7208 if e.error_code() != ErrorCode::Internal {
7209 anyhow!(e.error_code())
7210 } else {
7211 anyhow!("{e:#}")
7212 }
7213 })
7214 }),
7215 )
7216 }))
7217 .collect()
7218 }
7219 }
7220
7221 fn fetch_inlay_hints(
7222 &mut self,
7223 for_server: Option<LanguageServerId>,
7224 buffer: &Entity<Buffer>,
7225 range: Range<Anchor>,
7226 cx: &mut Context<Self>,
7227 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7228 let request = InlayHints {
7229 range: range.clone(),
7230 };
7231 if let Some((upstream_client, project_id)) = self.upstream_client() {
7232 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7233 return Task::ready(Ok(HashMap::default()));
7234 }
7235 let request_task = upstream_client.request_lsp(
7236 project_id,
7237 for_server.map(|id| id.to_proto()),
7238 LSP_REQUEST_TIMEOUT,
7239 cx.background_executor().clone(),
7240 request.to_proto(project_id, buffer.read(cx)),
7241 );
7242 let buffer = buffer.clone();
7243 cx.spawn(async move |weak_lsp_store, cx| {
7244 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7245 return Ok(HashMap::default());
7246 };
7247 let Some(responses) = request_task.await? else {
7248 return Ok(HashMap::default());
7249 };
7250
7251 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7252 let lsp_store = lsp_store.clone();
7253 let buffer = buffer.clone();
7254 let cx = cx.clone();
7255 let request = request.clone();
7256 async move {
7257 (
7258 LanguageServerId::from_proto(response.server_id),
7259 request
7260 .response_from_proto(response.response, lsp_store, buffer, cx)
7261 .await,
7262 )
7263 }
7264 }))
7265 .await;
7266
7267 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7268 let mut has_errors = false;
7269 let inlay_hints = inlay_hints
7270 .into_iter()
7271 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7272 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7273 Err(e) => {
7274 has_errors = true;
7275 log::error!("{e:#}");
7276 None
7277 }
7278 })
7279 .map(|(server_id, mut new_hints)| {
7280 new_hints.retain(|hint| {
7281 hint.position.is_valid(&buffer_snapshot)
7282 && range.start.is_valid(&buffer_snapshot)
7283 && range.end.is_valid(&buffer_snapshot)
7284 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7285 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7286 });
7287 (server_id, new_hints)
7288 })
7289 .collect::<HashMap<_, _>>();
7290 anyhow::ensure!(
7291 !has_errors || !inlay_hints.is_empty(),
7292 "Failed to fetch inlay hints"
7293 );
7294 Ok(inlay_hints)
7295 })
7296 } else {
7297 let inlay_hints_task = match for_server {
7298 Some(server_id) => {
7299 let server_task = self.request_lsp(
7300 buffer.clone(),
7301 LanguageServerToQuery::Other(server_id),
7302 request,
7303 cx,
7304 );
7305 cx.background_spawn(async move {
7306 let mut responses = Vec::new();
7307 match server_task.await {
7308 Ok(response) => responses.push((server_id, response)),
7309 // rust-analyzer likes to error with this when its still loading up
7310 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7311 Err(e) => log::error!(
7312 "Error handling response for inlay hints request: {e:#}"
7313 ),
7314 }
7315 responses
7316 })
7317 }
7318 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7319 };
7320 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7321 cx.background_spawn(async move {
7322 Ok(inlay_hints_task
7323 .await
7324 .into_iter()
7325 .map(|(server_id, mut new_hints)| {
7326 new_hints.retain(|hint| {
7327 hint.position.is_valid(&buffer_snapshot)
7328 && range.start.is_valid(&buffer_snapshot)
7329 && range.end.is_valid(&buffer_snapshot)
7330 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7331 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7332 });
7333 (server_id, new_hints)
7334 })
7335 .collect())
7336 })
7337 }
7338 }
7339
7340 fn diagnostic_registration_exists(
7341 &self,
7342 server_id: LanguageServerId,
7343 registration_id: &Option<SharedString>,
7344 ) -> bool {
7345 let Some(local) = self.as_local() else {
7346 return false;
7347 };
7348 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7349 else {
7350 return false;
7351 };
7352 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7353 registrations.diagnostics.contains_key(®istration_key)
7354 }
7355
7356 pub fn pull_diagnostics_for_buffer(
7357 &mut self,
7358 buffer: Entity<Buffer>,
7359 cx: &mut Context<Self>,
7360 ) -> Task<anyhow::Result<()>> {
7361 let diagnostics = self.pull_diagnostics(buffer, cx);
7362 cx.spawn(async move |lsp_store, cx| {
7363 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7364 return Ok(());
7365 };
7366 lsp_store.update(cx, |lsp_store, cx| {
7367 if lsp_store.as_local().is_none() {
7368 return;
7369 }
7370
7371 let mut unchanged_buffers = HashMap::default();
7372 let server_diagnostics_updates = diagnostics
7373 .into_iter()
7374 .filter_map(|diagnostics_set| match diagnostics_set {
7375 LspPullDiagnostics::Response {
7376 server_id,
7377 uri,
7378 diagnostics,
7379 registration_id,
7380 } => Some((server_id, uri, diagnostics, registration_id)),
7381 LspPullDiagnostics::Default => None,
7382 })
7383 .filter(|(server_id, _, _, registration_id)| {
7384 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7385 })
7386 .fold(
7387 HashMap::default(),
7388 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7389 let (result_id, diagnostics) = match diagnostics {
7390 PulledDiagnostics::Unchanged { result_id } => {
7391 unchanged_buffers
7392 .entry(new_registration_id.clone())
7393 .or_insert_with(HashSet::default)
7394 .insert(uri.clone());
7395 (Some(result_id), Vec::new())
7396 }
7397 PulledDiagnostics::Changed {
7398 result_id,
7399 diagnostics,
7400 } => (result_id, diagnostics),
7401 };
7402 let disk_based_sources = Cow::Owned(
7403 lsp_store
7404 .language_server_adapter_for_id(server_id)
7405 .as_ref()
7406 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7407 .unwrap_or(&[])
7408 .to_vec(),
7409 );
7410 acc.entry(server_id)
7411 .or_insert_with(HashMap::default)
7412 .entry(new_registration_id.clone())
7413 .or_insert_with(Vec::new)
7414 .push(DocumentDiagnosticsUpdate {
7415 server_id,
7416 diagnostics: lsp::PublishDiagnosticsParams {
7417 uri,
7418 diagnostics,
7419 version: None,
7420 },
7421 result_id,
7422 disk_based_sources,
7423 registration_id: new_registration_id,
7424 });
7425 acc
7426 },
7427 );
7428
7429 for diagnostic_updates in server_diagnostics_updates.into_values() {
7430 for (registration_id, diagnostic_updates) in diagnostic_updates {
7431 lsp_store
7432 .merge_lsp_diagnostics(
7433 DiagnosticSourceKind::Pulled,
7434 diagnostic_updates,
7435 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7436 DiagnosticSourceKind::Pulled => {
7437 old_diagnostic.registration_id != registration_id
7438 || unchanged_buffers
7439 .get(&old_diagnostic.registration_id)
7440 .is_some_and(|unchanged_buffers| {
7441 unchanged_buffers.contains(&document_uri)
7442 })
7443 }
7444 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7445 true
7446 }
7447 },
7448 cx,
7449 )
7450 .log_err();
7451 }
7452 }
7453 })
7454 })
7455 }
7456
7457 pub fn document_colors(
7458 &mut self,
7459 known_cache_version: Option<usize>,
7460 buffer: Entity<Buffer>,
7461 cx: &mut Context<Self>,
7462 ) -> Option<DocumentColorTask> {
7463 let version_queried_for = buffer.read(cx).version();
7464 let buffer_id = buffer.read(cx).remote_id();
7465
7466 let current_language_servers = self.as_local().map(|local| {
7467 local
7468 .buffers_opened_in_servers
7469 .get(&buffer_id)
7470 .cloned()
7471 .unwrap_or_default()
7472 });
7473
7474 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7475 if let Some(cached_colors) = &lsp_data.document_colors {
7476 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7477 let has_different_servers =
7478 current_language_servers.is_some_and(|current_language_servers| {
7479 current_language_servers
7480 != cached_colors.colors.keys().copied().collect()
7481 });
7482 if !has_different_servers {
7483 let cache_version = cached_colors.cache_version;
7484 if Some(cache_version) == known_cache_version {
7485 return None;
7486 } else {
7487 return Some(
7488 Task::ready(Ok(DocumentColors {
7489 colors: cached_colors
7490 .colors
7491 .values()
7492 .flatten()
7493 .cloned()
7494 .collect(),
7495 cache_version: Some(cache_version),
7496 }))
7497 .shared(),
7498 );
7499 }
7500 }
7501 }
7502 }
7503 }
7504
7505 let color_lsp_data = self
7506 .latest_lsp_data(&buffer, cx)
7507 .document_colors
7508 .get_or_insert_default();
7509 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7510 && !version_queried_for.changed_since(updating_for)
7511 {
7512 return Some(running_update.clone());
7513 }
7514 let buffer_version_queried_for = version_queried_for.clone();
7515 let new_task = cx
7516 .spawn(async move |lsp_store, cx| {
7517 cx.background_executor()
7518 .timer(Duration::from_millis(30))
7519 .await;
7520 let fetched_colors = lsp_store
7521 .update(cx, |lsp_store, cx| {
7522 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7523 })?
7524 .await
7525 .context("fetching document colors")
7526 .map_err(Arc::new);
7527 let fetched_colors = match fetched_colors {
7528 Ok(fetched_colors) => {
7529 if buffer.update(cx, |buffer, _| {
7530 buffer.version() != buffer_version_queried_for
7531 }) {
7532 return Ok(DocumentColors::default());
7533 }
7534 fetched_colors
7535 }
7536 Err(e) => {
7537 lsp_store
7538 .update(cx, |lsp_store, _| {
7539 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7540 if let Some(document_colors) = &mut lsp_data.document_colors {
7541 document_colors.colors_update = None;
7542 }
7543 }
7544 })
7545 .ok();
7546 return Err(e);
7547 }
7548 };
7549
7550 lsp_store
7551 .update(cx, |lsp_store, cx| {
7552 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7553 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7554
7555 if let Some(fetched_colors) = fetched_colors {
7556 if lsp_data.buffer_version == buffer_version_queried_for {
7557 lsp_colors.colors.extend(fetched_colors);
7558 lsp_colors.cache_version += 1;
7559 } else if !lsp_data
7560 .buffer_version
7561 .changed_since(&buffer_version_queried_for)
7562 {
7563 lsp_data.buffer_version = buffer_version_queried_for;
7564 lsp_colors.colors = fetched_colors;
7565 lsp_colors.cache_version += 1;
7566 }
7567 }
7568 lsp_colors.colors_update = None;
7569 let colors = lsp_colors
7570 .colors
7571 .values()
7572 .flatten()
7573 .cloned()
7574 .collect::<HashSet<_>>();
7575 DocumentColors {
7576 colors,
7577 cache_version: Some(lsp_colors.cache_version),
7578 }
7579 })
7580 .map_err(Arc::new)
7581 })
7582 .shared();
7583 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7584 Some(new_task)
7585 }
7586
7587 fn fetch_document_colors_for_buffer(
7588 &mut self,
7589 buffer: &Entity<Buffer>,
7590 cx: &mut Context<Self>,
7591 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7592 if let Some((client, project_id)) = self.upstream_client() {
7593 let request = GetDocumentColor {};
7594 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7595 return Task::ready(Ok(None));
7596 }
7597
7598 let request_task = client.request_lsp(
7599 project_id,
7600 None,
7601 LSP_REQUEST_TIMEOUT,
7602 cx.background_executor().clone(),
7603 request.to_proto(project_id, buffer.read(cx)),
7604 );
7605 let buffer = buffer.clone();
7606 cx.spawn(async move |lsp_store, cx| {
7607 let Some(lsp_store) = lsp_store.upgrade() else {
7608 return Ok(None);
7609 };
7610 let colors = join_all(
7611 request_task
7612 .await
7613 .log_err()
7614 .flatten()
7615 .map(|response| response.payload)
7616 .unwrap_or_default()
7617 .into_iter()
7618 .map(|color_response| {
7619 let response = request.response_from_proto(
7620 color_response.response,
7621 lsp_store.clone(),
7622 buffer.clone(),
7623 cx.clone(),
7624 );
7625 async move {
7626 (
7627 LanguageServerId::from_proto(color_response.server_id),
7628 response.await.log_err().unwrap_or_default(),
7629 )
7630 }
7631 }),
7632 )
7633 .await
7634 .into_iter()
7635 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7636 acc.entry(server_id)
7637 .or_insert_with(HashSet::default)
7638 .extend(colors);
7639 acc
7640 });
7641 Ok(Some(colors))
7642 })
7643 } else {
7644 let document_colors_task =
7645 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7646 cx.background_spawn(async move {
7647 Ok(Some(
7648 document_colors_task
7649 .await
7650 .into_iter()
7651 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7652 acc.entry(server_id)
7653 .or_insert_with(HashSet::default)
7654 .extend(colors);
7655 acc
7656 })
7657 .into_iter()
7658 .collect(),
7659 ))
7660 })
7661 }
7662 }
7663
7664 pub fn signature_help<T: ToPointUtf16>(
7665 &mut self,
7666 buffer: &Entity<Buffer>,
7667 position: T,
7668 cx: &mut Context<Self>,
7669 ) -> Task<Option<Vec<SignatureHelp>>> {
7670 let position = position.to_point_utf16(buffer.read(cx));
7671
7672 if let Some((client, upstream_project_id)) = self.upstream_client() {
7673 let request = GetSignatureHelp { position };
7674 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7675 return Task::ready(None);
7676 }
7677 let request_task = client.request_lsp(
7678 upstream_project_id,
7679 None,
7680 LSP_REQUEST_TIMEOUT,
7681 cx.background_executor().clone(),
7682 request.to_proto(upstream_project_id, buffer.read(cx)),
7683 );
7684 let buffer = buffer.clone();
7685 cx.spawn(async move |weak_lsp_store, cx| {
7686 let lsp_store = weak_lsp_store.upgrade()?;
7687 let signatures = join_all(
7688 request_task
7689 .await
7690 .log_err()
7691 .flatten()
7692 .map(|response| response.payload)
7693 .unwrap_or_default()
7694 .into_iter()
7695 .map(|response| {
7696 let response = GetSignatureHelp { position }.response_from_proto(
7697 response.response,
7698 lsp_store.clone(),
7699 buffer.clone(),
7700 cx.clone(),
7701 );
7702 async move { response.await.log_err().flatten() }
7703 }),
7704 )
7705 .await
7706 .into_iter()
7707 .flatten()
7708 .collect();
7709 Some(signatures)
7710 })
7711 } else {
7712 let all_actions_task = self.request_multiple_lsp_locally(
7713 buffer,
7714 Some(position),
7715 GetSignatureHelp { position },
7716 cx,
7717 );
7718 cx.background_spawn(async move {
7719 Some(
7720 all_actions_task
7721 .await
7722 .into_iter()
7723 .flat_map(|(_, actions)| actions)
7724 .collect::<Vec<_>>(),
7725 )
7726 })
7727 }
7728 }
7729
7730 pub fn hover(
7731 &mut self,
7732 buffer: &Entity<Buffer>,
7733 position: PointUtf16,
7734 cx: &mut Context<Self>,
7735 ) -> Task<Option<Vec<Hover>>> {
7736 if let Some((client, upstream_project_id)) = self.upstream_client() {
7737 let request = GetHover { position };
7738 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7739 return Task::ready(None);
7740 }
7741 let request_task = client.request_lsp(
7742 upstream_project_id,
7743 None,
7744 LSP_REQUEST_TIMEOUT,
7745 cx.background_executor().clone(),
7746 request.to_proto(upstream_project_id, buffer.read(cx)),
7747 );
7748 let buffer = buffer.clone();
7749 cx.spawn(async move |weak_lsp_store, cx| {
7750 let lsp_store = weak_lsp_store.upgrade()?;
7751 let hovers = join_all(
7752 request_task
7753 .await
7754 .log_err()
7755 .flatten()
7756 .map(|response| response.payload)
7757 .unwrap_or_default()
7758 .into_iter()
7759 .map(|response| {
7760 let response = GetHover { position }.response_from_proto(
7761 response.response,
7762 lsp_store.clone(),
7763 buffer.clone(),
7764 cx.clone(),
7765 );
7766 async move {
7767 response
7768 .await
7769 .log_err()
7770 .flatten()
7771 .and_then(remove_empty_hover_blocks)
7772 }
7773 }),
7774 )
7775 .await
7776 .into_iter()
7777 .flatten()
7778 .collect();
7779 Some(hovers)
7780 })
7781 } else {
7782 let all_actions_task = self.request_multiple_lsp_locally(
7783 buffer,
7784 Some(position),
7785 GetHover { position },
7786 cx,
7787 );
7788 cx.background_spawn(async move {
7789 Some(
7790 all_actions_task
7791 .await
7792 .into_iter()
7793 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7794 .collect::<Vec<Hover>>(),
7795 )
7796 })
7797 }
7798 }
7799
7800 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7801 let language_registry = self.languages.clone();
7802
7803 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7804 let request = upstream_client.request(proto::GetProjectSymbols {
7805 project_id: *project_id,
7806 query: query.to_string(),
7807 });
7808 cx.foreground_executor().spawn(async move {
7809 let response = request.await?;
7810 let mut symbols = Vec::new();
7811 let core_symbols = response
7812 .symbols
7813 .into_iter()
7814 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7815 .collect::<Vec<_>>();
7816 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7817 .await;
7818 Ok(symbols)
7819 })
7820 } else if let Some(local) = self.as_local() {
7821 struct WorkspaceSymbolsResult {
7822 server_id: LanguageServerId,
7823 lsp_adapter: Arc<CachedLspAdapter>,
7824 worktree: WeakEntity<Worktree>,
7825 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7826 }
7827
7828 let mut requests = Vec::new();
7829 let mut requested_servers = BTreeSet::new();
7830 for (seed, state) in local.language_server_ids.iter() {
7831 let Some(worktree_handle) = self
7832 .worktree_store
7833 .read(cx)
7834 .worktree_for_id(seed.worktree_id, cx)
7835 else {
7836 continue;
7837 };
7838 let worktree = worktree_handle.read(cx);
7839 if !worktree.is_visible() {
7840 continue;
7841 }
7842
7843 if !requested_servers.insert(state.id) {
7844 continue;
7845 }
7846
7847 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7848 Some(LanguageServerState::Running {
7849 adapter, server, ..
7850 }) => (adapter.clone(), server),
7851
7852 _ => continue,
7853 };
7854 let supports_workspace_symbol_request =
7855 match server.capabilities().workspace_symbol_provider {
7856 Some(OneOf::Left(supported)) => supported,
7857 Some(OneOf::Right(_)) => true,
7858 None => false,
7859 };
7860 if !supports_workspace_symbol_request {
7861 continue;
7862 }
7863 let worktree_handle = worktree_handle.clone();
7864 let server_id = server.server_id();
7865 requests.push(
7866 server
7867 .request::<lsp::request::WorkspaceSymbolRequest>(
7868 lsp::WorkspaceSymbolParams {
7869 query: query.to_string(),
7870 ..Default::default()
7871 },
7872 )
7873 .map(move |response| {
7874 let lsp_symbols = response
7875 .into_response()
7876 .context("workspace symbols request")
7877 .log_err()
7878 .flatten()
7879 .map(|symbol_response| match symbol_response {
7880 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7881 flat_responses
7882 .into_iter()
7883 .map(|lsp_symbol| {
7884 (
7885 lsp_symbol.name,
7886 lsp_symbol.kind,
7887 lsp_symbol.location,
7888 )
7889 })
7890 .collect::<Vec<_>>()
7891 }
7892 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7893 nested_responses
7894 .into_iter()
7895 .filter_map(|lsp_symbol| {
7896 let location = match lsp_symbol.location {
7897 OneOf::Left(location) => location,
7898 OneOf::Right(_) => {
7899 log::error!(
7900 "Unexpected: client capabilities \
7901 forbid symbol resolutions in \
7902 workspace.symbol.resolveSupport"
7903 );
7904 return None;
7905 }
7906 };
7907 Some((lsp_symbol.name, lsp_symbol.kind, location))
7908 })
7909 .collect::<Vec<_>>()
7910 }
7911 })
7912 .unwrap_or_default();
7913
7914 WorkspaceSymbolsResult {
7915 server_id,
7916 lsp_adapter,
7917 worktree: worktree_handle.downgrade(),
7918 lsp_symbols,
7919 }
7920 }),
7921 );
7922 }
7923
7924 cx.spawn(async move |this, cx| {
7925 let responses = futures::future::join_all(requests).await;
7926 let this = match this.upgrade() {
7927 Some(this) => this,
7928 None => return Ok(Vec::new()),
7929 };
7930
7931 let mut symbols = Vec::new();
7932 for result in responses {
7933 let core_symbols = this.update(cx, |this, cx| {
7934 result
7935 .lsp_symbols
7936 .into_iter()
7937 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7938 let abs_path = symbol_location.uri.to_file_path().ok()?;
7939 let source_worktree = result.worktree.upgrade()?;
7940 let source_worktree_id = source_worktree.read(cx).id();
7941
7942 let path = if let Some((tree, rel_path)) =
7943 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7944 {
7945 let worktree_id = tree.read(cx).id();
7946 SymbolLocation::InProject(ProjectPath {
7947 worktree_id,
7948 path: rel_path,
7949 })
7950 } else {
7951 SymbolLocation::OutsideProject {
7952 signature: this.symbol_signature(&abs_path),
7953 abs_path: abs_path.into(),
7954 }
7955 };
7956
7957 Some(CoreSymbol {
7958 source_language_server_id: result.server_id,
7959 language_server_name: result.lsp_adapter.name.clone(),
7960 source_worktree_id,
7961 path,
7962 kind: symbol_kind,
7963 name: symbol_name,
7964 range: range_from_lsp(symbol_location.range),
7965 })
7966 })
7967 .collect::<Vec<_>>()
7968 });
7969
7970 populate_labels_for_symbols(
7971 core_symbols,
7972 &language_registry,
7973 Some(result.lsp_adapter),
7974 &mut symbols,
7975 )
7976 .await;
7977 }
7978
7979 Ok(symbols)
7980 })
7981 } else {
7982 Task::ready(Err(anyhow!("No upstream client or local language server")))
7983 }
7984 }
7985
7986 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7987 let mut summary = DiagnosticSummary::default();
7988 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7989 summary.error_count += path_summary.error_count;
7990 summary.warning_count += path_summary.warning_count;
7991 }
7992 summary
7993 }
7994
7995 /// Returns the diagnostic summary for a specific project path.
7996 pub fn diagnostic_summary_for_path(
7997 &self,
7998 project_path: &ProjectPath,
7999 _: &App,
8000 ) -> DiagnosticSummary {
8001 if let Some(summaries) = self
8002 .diagnostic_summaries
8003 .get(&project_path.worktree_id)
8004 .and_then(|map| map.get(&project_path.path))
8005 {
8006 let (error_count, warning_count) = summaries.iter().fold(
8007 (0, 0),
8008 |(error_count, warning_count), (_language_server_id, summary)| {
8009 (
8010 error_count + summary.error_count,
8011 warning_count + summary.warning_count,
8012 )
8013 },
8014 );
8015
8016 DiagnosticSummary {
8017 error_count,
8018 warning_count,
8019 }
8020 } else {
8021 DiagnosticSummary::default()
8022 }
8023 }
8024
8025 pub fn diagnostic_summaries<'a>(
8026 &'a self,
8027 include_ignored: bool,
8028 cx: &'a App,
8029 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
8030 self.worktree_store
8031 .read(cx)
8032 .visible_worktrees(cx)
8033 .filter_map(|worktree| {
8034 let worktree = worktree.read(cx);
8035 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
8036 })
8037 .flat_map(move |(worktree, summaries)| {
8038 let worktree_id = worktree.id();
8039 summaries
8040 .iter()
8041 .filter(move |(path, _)| {
8042 include_ignored
8043 || worktree
8044 .entry_for_path(path.as_ref())
8045 .is_some_and(|entry| !entry.is_ignored)
8046 })
8047 .flat_map(move |(path, summaries)| {
8048 summaries.iter().map(move |(server_id, summary)| {
8049 (
8050 ProjectPath {
8051 worktree_id,
8052 path: path.clone(),
8053 },
8054 *server_id,
8055 *summary,
8056 )
8057 })
8058 })
8059 })
8060 }
8061
8062 pub fn on_buffer_edited(
8063 &mut self,
8064 buffer: Entity<Buffer>,
8065 cx: &mut Context<Self>,
8066 ) -> Option<()> {
8067 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8068 Some(
8069 self.as_local()?
8070 .language_servers_for_buffer(buffer, cx)
8071 .map(|i| i.1.clone())
8072 .collect(),
8073 )
8074 })?;
8075
8076 let buffer = buffer.read(cx);
8077 let file = File::from_dyn(buffer.file())?;
8078 let abs_path = file.as_local()?.abs_path(cx);
8079 let uri = lsp::Uri::from_file_path(&abs_path)
8080 .ok()
8081 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8082 .log_err()?;
8083 let next_snapshot = buffer.text_snapshot();
8084 for language_server in language_servers {
8085 let language_server = language_server.clone();
8086
8087 let buffer_snapshots = self
8088 .as_local_mut()?
8089 .buffer_snapshots
8090 .get_mut(&buffer.remote_id())
8091 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8092 let previous_snapshot = buffer_snapshots.last()?;
8093
8094 let build_incremental_change = || {
8095 buffer
8096 .edits_since::<Dimensions<PointUtf16, usize>>(
8097 previous_snapshot.snapshot.version(),
8098 )
8099 .map(|edit| {
8100 let edit_start = edit.new.start.0;
8101 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8102 let new_text = next_snapshot
8103 .text_for_range(edit.new.start.1..edit.new.end.1)
8104 .collect();
8105 lsp::TextDocumentContentChangeEvent {
8106 range: Some(lsp::Range::new(
8107 point_to_lsp(edit_start),
8108 point_to_lsp(edit_end),
8109 )),
8110 range_length: None,
8111 text: new_text,
8112 }
8113 })
8114 .collect()
8115 };
8116
8117 let document_sync_kind = language_server
8118 .capabilities()
8119 .text_document_sync
8120 .as_ref()
8121 .and_then(|sync| match sync {
8122 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8123 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8124 });
8125
8126 let content_changes: Vec<_> = match document_sync_kind {
8127 Some(lsp::TextDocumentSyncKind::FULL) => {
8128 vec![lsp::TextDocumentContentChangeEvent {
8129 range: None,
8130 range_length: None,
8131 text: next_snapshot.text(),
8132 }]
8133 }
8134 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8135 _ => {
8136 #[cfg(any(test, feature = "test-support"))]
8137 {
8138 build_incremental_change()
8139 }
8140
8141 #[cfg(not(any(test, feature = "test-support")))]
8142 {
8143 continue;
8144 }
8145 }
8146 };
8147
8148 let next_version = previous_snapshot.version + 1;
8149 buffer_snapshots.push(LspBufferSnapshot {
8150 version: next_version,
8151 snapshot: next_snapshot.clone(),
8152 });
8153
8154 language_server
8155 .notify::<lsp::notification::DidChangeTextDocument>(
8156 lsp::DidChangeTextDocumentParams {
8157 text_document: lsp::VersionedTextDocumentIdentifier::new(
8158 uri.clone(),
8159 next_version,
8160 ),
8161 content_changes,
8162 },
8163 )
8164 .ok();
8165 self.pull_workspace_diagnostics(language_server.server_id());
8166 }
8167
8168 None
8169 }
8170
8171 pub fn on_buffer_saved(
8172 &mut self,
8173 buffer: Entity<Buffer>,
8174 cx: &mut Context<Self>,
8175 ) -> Option<()> {
8176 let file = File::from_dyn(buffer.read(cx).file())?;
8177 let worktree_id = file.worktree_id(cx);
8178 let abs_path = file.as_local()?.abs_path(cx);
8179 let text_document = lsp::TextDocumentIdentifier {
8180 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8181 };
8182 let local = self.as_local()?;
8183
8184 for server in local.language_servers_for_worktree(worktree_id) {
8185 if let Some(include_text) = include_text(server.as_ref()) {
8186 let text = if include_text {
8187 Some(buffer.read(cx).text())
8188 } else {
8189 None
8190 };
8191 server
8192 .notify::<lsp::notification::DidSaveTextDocument>(
8193 lsp::DidSaveTextDocumentParams {
8194 text_document: text_document.clone(),
8195 text,
8196 },
8197 )
8198 .ok();
8199 }
8200 }
8201
8202 let language_servers = buffer.update(cx, |buffer, cx| {
8203 local.language_server_ids_for_buffer(buffer, cx)
8204 });
8205 for language_server_id in language_servers {
8206 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8207 }
8208
8209 None
8210 }
8211
8212 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8213 maybe!(async move {
8214 let mut refreshed_servers = HashSet::default();
8215 let servers = lsp_store
8216 .update(cx, |lsp_store, cx| {
8217 let local = lsp_store.as_local()?;
8218
8219 let servers = local
8220 .language_server_ids
8221 .iter()
8222 .filter_map(|(seed, state)| {
8223 let worktree = lsp_store
8224 .worktree_store
8225 .read(cx)
8226 .worktree_for_id(seed.worktree_id, cx);
8227 let delegate: Arc<dyn LspAdapterDelegate> =
8228 worktree.map(|worktree| {
8229 LocalLspAdapterDelegate::new(
8230 local.languages.clone(),
8231 &local.environment,
8232 cx.weak_entity(),
8233 &worktree,
8234 local.http_client.clone(),
8235 local.fs.clone(),
8236 cx,
8237 )
8238 })?;
8239 let server_id = state.id;
8240
8241 let states = local.language_servers.get(&server_id)?;
8242
8243 match states {
8244 LanguageServerState::Starting { .. } => None,
8245 LanguageServerState::Running {
8246 adapter, server, ..
8247 } => {
8248 let adapter = adapter.clone();
8249 let server = server.clone();
8250 refreshed_servers.insert(server.name());
8251 let toolchain = seed.toolchain.clone();
8252 Some(cx.spawn(async move |_, cx| {
8253 let settings =
8254 LocalLspStore::workspace_configuration_for_adapter(
8255 adapter.adapter.clone(),
8256 &delegate,
8257 toolchain,
8258 None,
8259 cx,
8260 )
8261 .await
8262 .ok()?;
8263 server
8264 .notify::<lsp::notification::DidChangeConfiguration>(
8265 lsp::DidChangeConfigurationParams { settings },
8266 )
8267 .ok()?;
8268 Some(())
8269 }))
8270 }
8271 }
8272 })
8273 .collect::<Vec<_>>();
8274
8275 Some(servers)
8276 })
8277 .ok()
8278 .flatten()?;
8279
8280 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8281 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8282 // to stop and unregister its language server wrapper.
8283 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8284 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8285 let _: Vec<Option<()>> = join_all(servers).await;
8286
8287 Some(())
8288 })
8289 .await;
8290 }
8291
8292 fn maintain_workspace_config(
8293 external_refresh_requests: watch::Receiver<()>,
8294 cx: &mut Context<Self>,
8295 ) -> Task<Result<()>> {
8296 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8297 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8298
8299 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8300 *settings_changed_tx.borrow_mut() = ();
8301 });
8302
8303 let mut joint_future =
8304 futures::stream::select(settings_changed_rx, external_refresh_requests);
8305 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8306 // - 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).
8307 // - 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.
8308 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8309 // - 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,
8310 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8311 cx.spawn(async move |this, cx| {
8312 while let Some(()) = joint_future.next().await {
8313 this.update(cx, |this, cx| {
8314 this.refresh_server_tree(cx);
8315 })
8316 .ok();
8317
8318 Self::refresh_workspace_configurations(&this, cx).await;
8319 }
8320
8321 drop(settings_observation);
8322 anyhow::Ok(())
8323 })
8324 }
8325
8326 pub fn running_language_servers_for_local_buffer<'a>(
8327 &'a self,
8328 buffer: &Buffer,
8329 cx: &mut App,
8330 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8331 let local = self.as_local();
8332 let language_server_ids = local
8333 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8334 .unwrap_or_default();
8335
8336 language_server_ids
8337 .into_iter()
8338 .filter_map(
8339 move |server_id| match local?.language_servers.get(&server_id)? {
8340 LanguageServerState::Running {
8341 adapter, server, ..
8342 } => Some((adapter, server)),
8343 _ => None,
8344 },
8345 )
8346 }
8347
8348 pub fn language_servers_for_local_buffer(
8349 &self,
8350 buffer: &Buffer,
8351 cx: &mut App,
8352 ) -> Vec<LanguageServerId> {
8353 let local = self.as_local();
8354 local
8355 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8356 .unwrap_or_default()
8357 }
8358
8359 pub fn language_server_for_local_buffer<'a>(
8360 &'a self,
8361 buffer: &'a Buffer,
8362 server_id: LanguageServerId,
8363 cx: &'a mut App,
8364 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8365 self.as_local()?
8366 .language_servers_for_buffer(buffer, cx)
8367 .find(|(_, s)| s.server_id() == server_id)
8368 }
8369
8370 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8371 self.diagnostic_summaries.remove(&id_to_remove);
8372 if let Some(local) = self.as_local_mut() {
8373 let to_remove = local.remove_worktree(id_to_remove, cx);
8374 for server in to_remove {
8375 self.language_server_statuses.remove(&server);
8376 }
8377 }
8378 }
8379
8380 pub fn shared(
8381 &mut self,
8382 project_id: u64,
8383 downstream_client: AnyProtoClient,
8384 _: &mut Context<Self>,
8385 ) {
8386 self.downstream_client = Some((downstream_client.clone(), project_id));
8387
8388 for (server_id, status) in &self.language_server_statuses {
8389 if let Some(server) = self.language_server_for_id(*server_id) {
8390 downstream_client
8391 .send(proto::StartLanguageServer {
8392 project_id,
8393 server: Some(proto::LanguageServer {
8394 id: server_id.to_proto(),
8395 name: status.name.to_string(),
8396 worktree_id: status.worktree.map(|id| id.to_proto()),
8397 }),
8398 capabilities: serde_json::to_string(&server.capabilities())
8399 .expect("serializing server LSP capabilities"),
8400 })
8401 .log_err();
8402 }
8403 }
8404 }
8405
8406 pub fn disconnected_from_host(&mut self) {
8407 self.downstream_client.take();
8408 }
8409
8410 pub fn disconnected_from_ssh_remote(&mut self) {
8411 if let LspStoreMode::Remote(RemoteLspStore {
8412 upstream_client, ..
8413 }) = &mut self.mode
8414 {
8415 upstream_client.take();
8416 }
8417 }
8418
8419 pub(crate) fn set_language_server_statuses_from_proto(
8420 &mut self,
8421 project: WeakEntity<Project>,
8422 language_servers: Vec<proto::LanguageServer>,
8423 server_capabilities: Vec<String>,
8424 cx: &mut Context<Self>,
8425 ) {
8426 let lsp_logs = cx
8427 .try_global::<GlobalLogStore>()
8428 .map(|lsp_store| lsp_store.0.clone());
8429
8430 self.language_server_statuses = language_servers
8431 .into_iter()
8432 .zip(server_capabilities)
8433 .map(|(server, server_capabilities)| {
8434 let server_id = LanguageServerId(server.id as usize);
8435 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8436 self.lsp_server_capabilities
8437 .insert(server_id, server_capabilities);
8438 }
8439
8440 let name = LanguageServerName::from_proto(server.name);
8441 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8442
8443 if let Some(lsp_logs) = &lsp_logs {
8444 lsp_logs.update(cx, |lsp_logs, cx| {
8445 lsp_logs.add_language_server(
8446 // Only remote clients get their language servers set from proto
8447 LanguageServerKind::Remote {
8448 project: project.clone(),
8449 },
8450 server_id,
8451 Some(name.clone()),
8452 worktree,
8453 None,
8454 cx,
8455 );
8456 });
8457 }
8458
8459 (
8460 server_id,
8461 LanguageServerStatus {
8462 name,
8463 server_version: None,
8464 pending_work: Default::default(),
8465 has_pending_diagnostic_updates: false,
8466 progress_tokens: Default::default(),
8467 worktree,
8468 binary: None,
8469 configuration: None,
8470 workspace_folders: BTreeSet::new(),
8471 },
8472 )
8473 })
8474 .collect();
8475 }
8476
8477 #[cfg(feature = "test-support")]
8478 pub fn update_diagnostic_entries(
8479 &mut self,
8480 server_id: LanguageServerId,
8481 abs_path: PathBuf,
8482 result_id: Option<SharedString>,
8483 version: Option<i32>,
8484 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8485 cx: &mut Context<Self>,
8486 ) -> anyhow::Result<()> {
8487 self.merge_diagnostic_entries(
8488 vec![DocumentDiagnosticsUpdate {
8489 diagnostics: DocumentDiagnostics {
8490 diagnostics,
8491 document_abs_path: abs_path,
8492 version,
8493 },
8494 result_id,
8495 server_id,
8496 disk_based_sources: Cow::Borrowed(&[]),
8497 registration_id: None,
8498 }],
8499 |_, _, _| false,
8500 cx,
8501 )?;
8502 Ok(())
8503 }
8504
8505 pub fn merge_diagnostic_entries<'a>(
8506 &mut self,
8507 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8508 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8509 cx: &mut Context<Self>,
8510 ) -> anyhow::Result<()> {
8511 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8512 let mut updated_diagnostics_paths = HashMap::default();
8513 for mut update in diagnostic_updates {
8514 let abs_path = &update.diagnostics.document_abs_path;
8515 let server_id = update.server_id;
8516 let Some((worktree, relative_path)) =
8517 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8518 else {
8519 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8520 return Ok(());
8521 };
8522
8523 let worktree_id = worktree.read(cx).id();
8524 let project_path = ProjectPath {
8525 worktree_id,
8526 path: relative_path,
8527 };
8528
8529 let document_uri = lsp::Uri::from_file_path(abs_path)
8530 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8531 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8532 let snapshot = buffer_handle.read(cx).snapshot();
8533 let buffer = buffer_handle.read(cx);
8534 let reused_diagnostics = buffer
8535 .buffer_diagnostics(Some(server_id))
8536 .iter()
8537 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8538 .map(|v| {
8539 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8540 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8541 DiagnosticEntry {
8542 range: start..end,
8543 diagnostic: v.diagnostic.clone(),
8544 }
8545 })
8546 .collect::<Vec<_>>();
8547
8548 self.as_local_mut()
8549 .context("cannot merge diagnostics on a remote LspStore")?
8550 .update_buffer_diagnostics(
8551 &buffer_handle,
8552 server_id,
8553 Some(update.registration_id),
8554 update.result_id,
8555 update.diagnostics.version,
8556 update.diagnostics.diagnostics.clone(),
8557 reused_diagnostics.clone(),
8558 cx,
8559 )?;
8560
8561 update.diagnostics.diagnostics.extend(reused_diagnostics);
8562 } else if let Some(local) = self.as_local() {
8563 let reused_diagnostics = local
8564 .diagnostics
8565 .get(&worktree_id)
8566 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8567 .and_then(|diagnostics_by_server_id| {
8568 diagnostics_by_server_id
8569 .binary_search_by_key(&server_id, |e| e.0)
8570 .ok()
8571 .map(|ix| &diagnostics_by_server_id[ix].1)
8572 })
8573 .into_iter()
8574 .flatten()
8575 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8576
8577 update
8578 .diagnostics
8579 .diagnostics
8580 .extend(reused_diagnostics.cloned());
8581 }
8582
8583 let updated = worktree.update(cx, |worktree, cx| {
8584 self.update_worktree_diagnostics(
8585 worktree.id(),
8586 server_id,
8587 project_path.path.clone(),
8588 update.diagnostics.diagnostics,
8589 cx,
8590 )
8591 })?;
8592 match updated {
8593 ControlFlow::Continue(new_summary) => {
8594 if let Some((project_id, new_summary)) = new_summary {
8595 match &mut diagnostics_summary {
8596 Some(diagnostics_summary) => {
8597 diagnostics_summary
8598 .more_summaries
8599 .push(proto::DiagnosticSummary {
8600 path: project_path.path.as_ref().to_proto(),
8601 language_server_id: server_id.0 as u64,
8602 error_count: new_summary.error_count,
8603 warning_count: new_summary.warning_count,
8604 })
8605 }
8606 None => {
8607 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8608 project_id,
8609 worktree_id: worktree_id.to_proto(),
8610 summary: Some(proto::DiagnosticSummary {
8611 path: project_path.path.as_ref().to_proto(),
8612 language_server_id: server_id.0 as u64,
8613 error_count: new_summary.error_count,
8614 warning_count: new_summary.warning_count,
8615 }),
8616 more_summaries: Vec::new(),
8617 })
8618 }
8619 }
8620 }
8621 updated_diagnostics_paths
8622 .entry(server_id)
8623 .or_insert_with(Vec::new)
8624 .push(project_path);
8625 }
8626 ControlFlow::Break(()) => {}
8627 }
8628 }
8629
8630 if let Some((diagnostics_summary, (downstream_client, _))) =
8631 diagnostics_summary.zip(self.downstream_client.as_ref())
8632 {
8633 downstream_client.send(diagnostics_summary).log_err();
8634 }
8635 for (server_id, paths) in updated_diagnostics_paths {
8636 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8637 }
8638 Ok(())
8639 }
8640
8641 fn update_worktree_diagnostics(
8642 &mut self,
8643 worktree_id: WorktreeId,
8644 server_id: LanguageServerId,
8645 path_in_worktree: Arc<RelPath>,
8646 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8647 _: &mut Context<Worktree>,
8648 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8649 let local = match &mut self.mode {
8650 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8651 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8652 };
8653
8654 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8655 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8656 let summaries_by_server_id = summaries_for_tree
8657 .entry(path_in_worktree.clone())
8658 .or_default();
8659
8660 let old_summary = summaries_by_server_id
8661 .remove(&server_id)
8662 .unwrap_or_default();
8663
8664 let new_summary = DiagnosticSummary::new(&diagnostics);
8665 if diagnostics.is_empty() {
8666 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8667 {
8668 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8669 diagnostics_by_server_id.remove(ix);
8670 }
8671 if diagnostics_by_server_id.is_empty() {
8672 diagnostics_for_tree.remove(&path_in_worktree);
8673 }
8674 }
8675 } else {
8676 summaries_by_server_id.insert(server_id, new_summary);
8677 let diagnostics_by_server_id = diagnostics_for_tree
8678 .entry(path_in_worktree.clone())
8679 .or_default();
8680 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8681 Ok(ix) => {
8682 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8683 }
8684 Err(ix) => {
8685 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8686 }
8687 }
8688 }
8689
8690 if !old_summary.is_empty() || !new_summary.is_empty() {
8691 if let Some((_, project_id)) = &self.downstream_client {
8692 Ok(ControlFlow::Continue(Some((
8693 *project_id,
8694 proto::DiagnosticSummary {
8695 path: path_in_worktree.to_proto(),
8696 language_server_id: server_id.0 as u64,
8697 error_count: new_summary.error_count as u32,
8698 warning_count: new_summary.warning_count as u32,
8699 },
8700 ))))
8701 } else {
8702 Ok(ControlFlow::Continue(None))
8703 }
8704 } else {
8705 Ok(ControlFlow::Break(()))
8706 }
8707 }
8708
8709 pub fn open_buffer_for_symbol(
8710 &mut self,
8711 symbol: &Symbol,
8712 cx: &mut Context<Self>,
8713 ) -> Task<Result<Entity<Buffer>>> {
8714 if let Some((client, project_id)) = self.upstream_client() {
8715 let request = client.request(proto::OpenBufferForSymbol {
8716 project_id,
8717 symbol: Some(Self::serialize_symbol(symbol)),
8718 });
8719 cx.spawn(async move |this, cx| {
8720 let response = request.await?;
8721 let buffer_id = BufferId::new(response.buffer_id)?;
8722 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8723 .await
8724 })
8725 } else if let Some(local) = self.as_local() {
8726 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8727 seed.worktree_id == symbol.source_worktree_id
8728 && state.id == symbol.source_language_server_id
8729 && symbol.language_server_name == seed.name
8730 });
8731 if !is_valid {
8732 return Task::ready(Err(anyhow!(
8733 "language server for worktree and language not found"
8734 )));
8735 };
8736
8737 let symbol_abs_path = match &symbol.path {
8738 SymbolLocation::InProject(project_path) => self
8739 .worktree_store
8740 .read(cx)
8741 .absolutize(&project_path, cx)
8742 .context("no such worktree"),
8743 SymbolLocation::OutsideProject {
8744 abs_path,
8745 signature: _,
8746 } => Ok(abs_path.to_path_buf()),
8747 };
8748 let symbol_abs_path = match symbol_abs_path {
8749 Ok(abs_path) => abs_path,
8750 Err(err) => return Task::ready(Err(err)),
8751 };
8752 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8753 uri
8754 } else {
8755 return Task::ready(Err(anyhow!("invalid symbol path")));
8756 };
8757
8758 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8759 } else {
8760 Task::ready(Err(anyhow!("no upstream client or local store")))
8761 }
8762 }
8763
8764 pub(crate) fn open_local_buffer_via_lsp(
8765 &mut self,
8766 abs_path: lsp::Uri,
8767 language_server_id: LanguageServerId,
8768 cx: &mut Context<Self>,
8769 ) -> Task<Result<Entity<Buffer>>> {
8770 let path_style = self.worktree_store.read(cx).path_style();
8771 cx.spawn(async move |lsp_store, cx| {
8772 // Escape percent-encoded string.
8773 let current_scheme = abs_path.scheme().to_owned();
8774 // Uri is immutable, so we can't modify the scheme
8775
8776 let abs_path = abs_path
8777 .to_file_path_ext(path_style)
8778 .map_err(|()| anyhow!("can't convert URI to path"))?;
8779 let p = abs_path.clone();
8780 let yarn_worktree = lsp_store
8781 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8782 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8783 cx.spawn(async move |this, cx| {
8784 let t = this
8785 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8786 .ok()?;
8787 t.await
8788 })
8789 }),
8790 None => Task::ready(None),
8791 })?
8792 .await;
8793 let (worktree_root_target, known_relative_path) =
8794 if let Some((zip_root, relative_path)) = yarn_worktree {
8795 (zip_root, Some(relative_path))
8796 } else {
8797 (Arc::<Path>::from(abs_path.as_path()), None)
8798 };
8799 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8800 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8801 worktree_store.find_worktree(&worktree_root_target, cx)
8802 })
8803 })?;
8804 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8805 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8806 (result.0, relative_path, None)
8807 } else {
8808 let worktree = lsp_store
8809 .update(cx, |lsp_store, cx| {
8810 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8811 worktree_store.create_worktree(&worktree_root_target, false, cx)
8812 })
8813 })?
8814 .await?;
8815 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8816 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8817 lsp_store
8818 .update(cx, |lsp_store, cx| {
8819 if let Some(local) = lsp_store.as_local_mut() {
8820 local.register_language_server_for_invisible_worktree(
8821 &worktree,
8822 language_server_id,
8823 cx,
8824 )
8825 }
8826 match lsp_store.language_server_statuses.get(&language_server_id) {
8827 Some(status) => status.worktree,
8828 None => None,
8829 }
8830 })
8831 .ok()
8832 .flatten()
8833 .zip(Some(worktree_root.clone()))
8834 } else {
8835 None
8836 };
8837 let relative_path = if let Some(known_path) = known_relative_path {
8838 known_path
8839 } else {
8840 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8841 .into_arc()
8842 };
8843 (worktree, relative_path, source_ws)
8844 };
8845 let project_path = ProjectPath {
8846 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8847 path: relative_path,
8848 };
8849 let buffer = lsp_store
8850 .update(cx, |lsp_store, cx| {
8851 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8852 buffer_store.open_buffer(project_path, cx)
8853 })
8854 })?
8855 .await?;
8856 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8857 if let Some((source_ws, worktree_root)) = source_ws {
8858 buffer.update(cx, |buffer, cx| {
8859 let settings = WorktreeSettings::get(
8860 Some(
8861 (&ProjectPath {
8862 worktree_id: source_ws,
8863 path: Arc::from(RelPath::empty()),
8864 })
8865 .into(),
8866 ),
8867 cx,
8868 );
8869 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8870 if is_read_only {
8871 buffer.set_capability(Capability::ReadOnly, cx);
8872 }
8873 });
8874 }
8875 Ok(buffer)
8876 })
8877 }
8878
8879 fn request_multiple_lsp_locally<P, R>(
8880 &mut self,
8881 buffer: &Entity<Buffer>,
8882 position: Option<P>,
8883 request: R,
8884 cx: &mut Context<Self>,
8885 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8886 where
8887 P: ToOffset,
8888 R: LspCommand + Clone,
8889 <R::LspRequest as lsp::request::Request>::Result: Send,
8890 <R::LspRequest as lsp::request::Request>::Params: Send,
8891 {
8892 let Some(local) = self.as_local() else {
8893 return Task::ready(Vec::new());
8894 };
8895
8896 let snapshot = buffer.read(cx).snapshot();
8897 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8898
8899 let server_ids = buffer.update(cx, |buffer, cx| {
8900 local
8901 .language_servers_for_buffer(buffer, cx)
8902 .filter(|(adapter, _)| {
8903 scope
8904 .as_ref()
8905 .map(|scope| scope.language_allowed(&adapter.name))
8906 .unwrap_or(true)
8907 })
8908 .map(|(_, server)| server.server_id())
8909 .filter(|server_id| {
8910 self.as_local().is_none_or(|local| {
8911 local
8912 .buffers_opened_in_servers
8913 .get(&snapshot.remote_id())
8914 .is_some_and(|servers| servers.contains(server_id))
8915 })
8916 })
8917 .collect::<Vec<_>>()
8918 });
8919
8920 let mut response_results = server_ids
8921 .into_iter()
8922 .map(|server_id| {
8923 let task = self.request_lsp(
8924 buffer.clone(),
8925 LanguageServerToQuery::Other(server_id),
8926 request.clone(),
8927 cx,
8928 );
8929 async move { (server_id, task.await) }
8930 })
8931 .collect::<FuturesUnordered<_>>();
8932
8933 cx.background_spawn(async move {
8934 let mut responses = Vec::with_capacity(response_results.len());
8935 while let Some((server_id, response_result)) = response_results.next().await {
8936 match response_result {
8937 Ok(response) => responses.push((server_id, response)),
8938 // rust-analyzer likes to error with this when its still loading up
8939 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8940 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8941 }
8942 }
8943 responses
8944 })
8945 }
8946
8947 async fn handle_lsp_get_completions(
8948 this: Entity<Self>,
8949 envelope: TypedEnvelope<proto::GetCompletions>,
8950 mut cx: AsyncApp,
8951 ) -> Result<proto::GetCompletionsResponse> {
8952 let sender_id = envelope.original_sender_id().unwrap_or_default();
8953
8954 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8955 let buffer_handle = this.update(&mut cx, |this, cx| {
8956 this.buffer_store.read(cx).get_existing(buffer_id)
8957 })?;
8958 let request = GetCompletions::from_proto(
8959 envelope.payload,
8960 this.clone(),
8961 buffer_handle.clone(),
8962 cx.clone(),
8963 )
8964 .await?;
8965
8966 let server_to_query = match request.server_id {
8967 Some(server_id) => LanguageServerToQuery::Other(server_id),
8968 None => LanguageServerToQuery::FirstCapable,
8969 };
8970
8971 let response = this
8972 .update(&mut cx, |this, cx| {
8973 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8974 })
8975 .await?;
8976 this.update(&mut cx, |this, cx| {
8977 Ok(GetCompletions::response_to_proto(
8978 response,
8979 this,
8980 sender_id,
8981 &buffer_handle.read(cx).version(),
8982 cx,
8983 ))
8984 })
8985 }
8986
8987 async fn handle_lsp_command<T: LspCommand>(
8988 this: Entity<Self>,
8989 envelope: TypedEnvelope<T::ProtoRequest>,
8990 mut cx: AsyncApp,
8991 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8992 where
8993 <T::LspRequest as lsp::request::Request>::Params: Send,
8994 <T::LspRequest as lsp::request::Request>::Result: Send,
8995 {
8996 let sender_id = envelope.original_sender_id().unwrap_or_default();
8997 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8998 let buffer_handle = this.update(&mut cx, |this, cx| {
8999 this.buffer_store.read(cx).get_existing(buffer_id)
9000 })?;
9001 let request = T::from_proto(
9002 envelope.payload,
9003 this.clone(),
9004 buffer_handle.clone(),
9005 cx.clone(),
9006 )
9007 .await?;
9008 let response = this
9009 .update(&mut cx, |this, cx| {
9010 this.request_lsp(
9011 buffer_handle.clone(),
9012 LanguageServerToQuery::FirstCapable,
9013 request,
9014 cx,
9015 )
9016 })
9017 .await?;
9018 this.update(&mut cx, |this, cx| {
9019 Ok(T::response_to_proto(
9020 response,
9021 this,
9022 sender_id,
9023 &buffer_handle.read(cx).version(),
9024 cx,
9025 ))
9026 })
9027 }
9028
9029 async fn handle_lsp_query(
9030 lsp_store: Entity<Self>,
9031 envelope: TypedEnvelope<proto::LspQuery>,
9032 mut cx: AsyncApp,
9033 ) -> Result<proto::Ack> {
9034 use proto::lsp_query::Request;
9035 let sender_id = envelope.original_sender_id().unwrap_or_default();
9036 let lsp_query = envelope.payload;
9037 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
9038 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
9039 match lsp_query.request.context("invalid LSP query request")? {
9040 Request::GetReferences(get_references) => {
9041 let position = get_references.position.clone().and_then(deserialize_anchor);
9042 Self::query_lsp_locally::<GetReferences>(
9043 lsp_store,
9044 server_id,
9045 sender_id,
9046 lsp_request_id,
9047 get_references,
9048 position,
9049 &mut cx,
9050 )
9051 .await?;
9052 }
9053 Request::GetDocumentColor(get_document_color) => {
9054 Self::query_lsp_locally::<GetDocumentColor>(
9055 lsp_store,
9056 server_id,
9057 sender_id,
9058 lsp_request_id,
9059 get_document_color,
9060 None,
9061 &mut cx,
9062 )
9063 .await?;
9064 }
9065 Request::GetHover(get_hover) => {
9066 let position = get_hover.position.clone().and_then(deserialize_anchor);
9067 Self::query_lsp_locally::<GetHover>(
9068 lsp_store,
9069 server_id,
9070 sender_id,
9071 lsp_request_id,
9072 get_hover,
9073 position,
9074 &mut cx,
9075 )
9076 .await?;
9077 }
9078 Request::GetCodeActions(get_code_actions) => {
9079 Self::query_lsp_locally::<GetCodeActions>(
9080 lsp_store,
9081 server_id,
9082 sender_id,
9083 lsp_request_id,
9084 get_code_actions,
9085 None,
9086 &mut cx,
9087 )
9088 .await?;
9089 }
9090 Request::GetSignatureHelp(get_signature_help) => {
9091 let position = get_signature_help
9092 .position
9093 .clone()
9094 .and_then(deserialize_anchor);
9095 Self::query_lsp_locally::<GetSignatureHelp>(
9096 lsp_store,
9097 server_id,
9098 sender_id,
9099 lsp_request_id,
9100 get_signature_help,
9101 position,
9102 &mut cx,
9103 )
9104 .await?;
9105 }
9106 Request::GetCodeLens(get_code_lens) => {
9107 Self::query_lsp_locally::<GetCodeLens>(
9108 lsp_store,
9109 server_id,
9110 sender_id,
9111 lsp_request_id,
9112 get_code_lens,
9113 None,
9114 &mut cx,
9115 )
9116 .await?;
9117 }
9118 Request::GetDefinition(get_definition) => {
9119 let position = get_definition.position.clone().and_then(deserialize_anchor);
9120 Self::query_lsp_locally::<GetDefinitions>(
9121 lsp_store,
9122 server_id,
9123 sender_id,
9124 lsp_request_id,
9125 get_definition,
9126 position,
9127 &mut cx,
9128 )
9129 .await?;
9130 }
9131 Request::GetDeclaration(get_declaration) => {
9132 let position = get_declaration
9133 .position
9134 .clone()
9135 .and_then(deserialize_anchor);
9136 Self::query_lsp_locally::<GetDeclarations>(
9137 lsp_store,
9138 server_id,
9139 sender_id,
9140 lsp_request_id,
9141 get_declaration,
9142 position,
9143 &mut cx,
9144 )
9145 .await?;
9146 }
9147 Request::GetTypeDefinition(get_type_definition) => {
9148 let position = get_type_definition
9149 .position
9150 .clone()
9151 .and_then(deserialize_anchor);
9152 Self::query_lsp_locally::<GetTypeDefinitions>(
9153 lsp_store,
9154 server_id,
9155 sender_id,
9156 lsp_request_id,
9157 get_type_definition,
9158 position,
9159 &mut cx,
9160 )
9161 .await?;
9162 }
9163 Request::GetImplementation(get_implementation) => {
9164 let position = get_implementation
9165 .position
9166 .clone()
9167 .and_then(deserialize_anchor);
9168 Self::query_lsp_locally::<GetImplementations>(
9169 lsp_store,
9170 server_id,
9171 sender_id,
9172 lsp_request_id,
9173 get_implementation,
9174 position,
9175 &mut cx,
9176 )
9177 .await?;
9178 }
9179 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9180 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9181 let version = deserialize_version(get_document_diagnostics.buffer_version());
9182 let buffer = lsp_store.update(&mut cx, |this, cx| {
9183 this.buffer_store.read(cx).get_existing(buffer_id)
9184 })?;
9185 buffer
9186 .update(&mut cx, |buffer, _| {
9187 buffer.wait_for_version(version.clone())
9188 })
9189 .await?;
9190 lsp_store.update(&mut cx, |lsp_store, cx| {
9191 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9192 let key = LspKey {
9193 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9194 server_queried: server_id,
9195 };
9196 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9197 ) {
9198 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9199 lsp_requests.clear();
9200 };
9201 }
9202
9203 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9204 existing_queries.insert(
9205 lsp_request_id,
9206 cx.spawn(async move |lsp_store, cx| {
9207 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9208 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9209 });
9210 if let Ok(diagnostics_pull) = diagnostics_pull {
9211 match diagnostics_pull.await {
9212 Ok(()) => {}
9213 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9214 };
9215 }
9216 }),
9217 );
9218 });
9219 }
9220 Request::InlayHints(inlay_hints) => {
9221 let query_start = inlay_hints
9222 .start
9223 .clone()
9224 .and_then(deserialize_anchor)
9225 .context("invalid inlay hints range start")?;
9226 let query_end = inlay_hints
9227 .end
9228 .clone()
9229 .and_then(deserialize_anchor)
9230 .context("invalid inlay hints range end")?;
9231 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9232 &lsp_store,
9233 server_id,
9234 lsp_request_id,
9235 &inlay_hints,
9236 query_start..query_end,
9237 &mut cx,
9238 )
9239 .await
9240 .context("preparing inlay hints request")?;
9241 Self::query_lsp_locally::<InlayHints>(
9242 lsp_store,
9243 server_id,
9244 sender_id,
9245 lsp_request_id,
9246 inlay_hints,
9247 None,
9248 &mut cx,
9249 )
9250 .await
9251 .context("querying for inlay hints")?
9252 }
9253 }
9254 Ok(proto::Ack {})
9255 }
9256
9257 async fn handle_lsp_query_response(
9258 lsp_store: Entity<Self>,
9259 envelope: TypedEnvelope<proto::LspQueryResponse>,
9260 cx: AsyncApp,
9261 ) -> Result<()> {
9262 lsp_store.read_with(&cx, |lsp_store, _| {
9263 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9264 upstream_client.handle_lsp_response(envelope.clone());
9265 }
9266 });
9267 Ok(())
9268 }
9269
9270 async fn handle_apply_code_action(
9271 this: Entity<Self>,
9272 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9273 mut cx: AsyncApp,
9274 ) -> Result<proto::ApplyCodeActionResponse> {
9275 let sender_id = envelope.original_sender_id().unwrap_or_default();
9276 let action =
9277 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9278 let apply_code_action = this.update(&mut cx, |this, cx| {
9279 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9280 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9281 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9282 })?;
9283
9284 let project_transaction = apply_code_action.await?;
9285 let project_transaction = this.update(&mut cx, |this, cx| {
9286 this.buffer_store.update(cx, |buffer_store, cx| {
9287 buffer_store.serialize_project_transaction_for_peer(
9288 project_transaction,
9289 sender_id,
9290 cx,
9291 )
9292 })
9293 });
9294 Ok(proto::ApplyCodeActionResponse {
9295 transaction: Some(project_transaction),
9296 })
9297 }
9298
9299 async fn handle_register_buffer_with_language_servers(
9300 this: Entity<Self>,
9301 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9302 mut cx: AsyncApp,
9303 ) -> Result<proto::Ack> {
9304 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9305 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9306 this.update(&mut cx, |this, cx| {
9307 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9308 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9309 project_id: upstream_project_id,
9310 buffer_id: buffer_id.to_proto(),
9311 only_servers: envelope.payload.only_servers,
9312 });
9313 }
9314
9315 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9316 anyhow::bail!("buffer is not open");
9317 };
9318
9319 let handle = this.register_buffer_with_language_servers(
9320 &buffer,
9321 envelope
9322 .payload
9323 .only_servers
9324 .into_iter()
9325 .filter_map(|selector| {
9326 Some(match selector.selector? {
9327 proto::language_server_selector::Selector::ServerId(server_id) => {
9328 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9329 }
9330 proto::language_server_selector::Selector::Name(name) => {
9331 LanguageServerSelector::Name(LanguageServerName(
9332 SharedString::from(name),
9333 ))
9334 }
9335 })
9336 })
9337 .collect(),
9338 false,
9339 cx,
9340 );
9341 // Pull diagnostics for the buffer even if it was already registered.
9342 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9343 // but it's unclear if we need it.
9344 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9345 .detach();
9346 this.buffer_store().update(cx, |buffer_store, _| {
9347 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9348 });
9349
9350 Ok(())
9351 })?;
9352 Ok(proto::Ack {})
9353 }
9354
9355 async fn handle_rename_project_entry(
9356 this: Entity<Self>,
9357 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9358 mut cx: AsyncApp,
9359 ) -> Result<proto::ProjectEntryResponse> {
9360 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9361 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9362 let new_path =
9363 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9364
9365 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9366 .update(&mut cx, |this, cx| {
9367 let (worktree, entry) = this
9368 .worktree_store
9369 .read(cx)
9370 .worktree_and_entry_for_id(entry_id, cx)?;
9371 let new_worktree = this
9372 .worktree_store
9373 .read(cx)
9374 .worktree_for_id(new_worktree_id, cx)?;
9375 Some((
9376 this.worktree_store.clone(),
9377 worktree,
9378 new_worktree,
9379 entry.clone(),
9380 ))
9381 })
9382 .context("worktree not found")?;
9383 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9384 (worktree.absolutize(&old_entry.path), worktree.id())
9385 });
9386 let new_abs_path =
9387 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9388
9389 let _transaction = Self::will_rename_entry(
9390 this.downgrade(),
9391 old_worktree_id,
9392 &old_abs_path,
9393 &new_abs_path,
9394 old_entry.is_dir(),
9395 cx.clone(),
9396 )
9397 .await;
9398 let response = WorktreeStore::handle_rename_project_entry(
9399 worktree_store,
9400 envelope.payload,
9401 cx.clone(),
9402 )
9403 .await;
9404 this.read_with(&cx, |this, _| {
9405 this.did_rename_entry(
9406 old_worktree_id,
9407 &old_abs_path,
9408 &new_abs_path,
9409 old_entry.is_dir(),
9410 );
9411 });
9412 response
9413 }
9414
9415 async fn handle_update_diagnostic_summary(
9416 this: Entity<Self>,
9417 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9418 mut cx: AsyncApp,
9419 ) -> Result<()> {
9420 this.update(&mut cx, |lsp_store, cx| {
9421 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9422 let mut updated_diagnostics_paths = HashMap::default();
9423 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9424 for message_summary in envelope
9425 .payload
9426 .summary
9427 .into_iter()
9428 .chain(envelope.payload.more_summaries)
9429 {
9430 let project_path = ProjectPath {
9431 worktree_id,
9432 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9433 };
9434 let path = project_path.path.clone();
9435 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9436 let summary = DiagnosticSummary {
9437 error_count: message_summary.error_count as usize,
9438 warning_count: message_summary.warning_count as usize,
9439 };
9440
9441 if summary.is_empty() {
9442 if let Some(worktree_summaries) =
9443 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9444 && let Some(summaries) = worktree_summaries.get_mut(&path)
9445 {
9446 summaries.remove(&server_id);
9447 if summaries.is_empty() {
9448 worktree_summaries.remove(&path);
9449 }
9450 }
9451 } else {
9452 lsp_store
9453 .diagnostic_summaries
9454 .entry(worktree_id)
9455 .or_default()
9456 .entry(path)
9457 .or_default()
9458 .insert(server_id, summary);
9459 }
9460
9461 if let Some((_, project_id)) = &lsp_store.downstream_client {
9462 match &mut diagnostics_summary {
9463 Some(diagnostics_summary) => {
9464 diagnostics_summary
9465 .more_summaries
9466 .push(proto::DiagnosticSummary {
9467 path: project_path.path.as_ref().to_proto(),
9468 language_server_id: server_id.0 as u64,
9469 error_count: summary.error_count as u32,
9470 warning_count: summary.warning_count as u32,
9471 })
9472 }
9473 None => {
9474 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9475 project_id: *project_id,
9476 worktree_id: worktree_id.to_proto(),
9477 summary: Some(proto::DiagnosticSummary {
9478 path: project_path.path.as_ref().to_proto(),
9479 language_server_id: server_id.0 as u64,
9480 error_count: summary.error_count as u32,
9481 warning_count: summary.warning_count as u32,
9482 }),
9483 more_summaries: Vec::new(),
9484 })
9485 }
9486 }
9487 }
9488 updated_diagnostics_paths
9489 .entry(server_id)
9490 .or_insert_with(Vec::new)
9491 .push(project_path);
9492 }
9493
9494 if let Some((diagnostics_summary, (downstream_client, _))) =
9495 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9496 {
9497 downstream_client.send(diagnostics_summary).log_err();
9498 }
9499 for (server_id, paths) in updated_diagnostics_paths {
9500 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9501 }
9502 Ok(())
9503 })
9504 }
9505
9506 async fn handle_start_language_server(
9507 lsp_store: Entity<Self>,
9508 envelope: TypedEnvelope<proto::StartLanguageServer>,
9509 mut cx: AsyncApp,
9510 ) -> Result<()> {
9511 let server = envelope.payload.server.context("invalid server")?;
9512 let server_capabilities =
9513 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9514 .with_context(|| {
9515 format!(
9516 "incorrect server capabilities {}",
9517 envelope.payload.capabilities
9518 )
9519 })?;
9520 lsp_store.update(&mut cx, |lsp_store, cx| {
9521 let server_id = LanguageServerId(server.id as usize);
9522 let server_name = LanguageServerName::from_proto(server.name.clone());
9523 lsp_store
9524 .lsp_server_capabilities
9525 .insert(server_id, server_capabilities);
9526 lsp_store.language_server_statuses.insert(
9527 server_id,
9528 LanguageServerStatus {
9529 name: server_name.clone(),
9530 server_version: None,
9531 pending_work: Default::default(),
9532 has_pending_diagnostic_updates: false,
9533 progress_tokens: Default::default(),
9534 worktree: server.worktree_id.map(WorktreeId::from_proto),
9535 binary: None,
9536 configuration: None,
9537 workspace_folders: BTreeSet::new(),
9538 },
9539 );
9540 cx.emit(LspStoreEvent::LanguageServerAdded(
9541 server_id,
9542 server_name,
9543 server.worktree_id.map(WorktreeId::from_proto),
9544 ));
9545 cx.notify();
9546 });
9547 Ok(())
9548 }
9549
9550 async fn handle_update_language_server(
9551 lsp_store: Entity<Self>,
9552 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9553 mut cx: AsyncApp,
9554 ) -> Result<()> {
9555 lsp_store.update(&mut cx, |lsp_store, cx| {
9556 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9557
9558 match envelope.payload.variant.context("invalid variant")? {
9559 proto::update_language_server::Variant::WorkStart(payload) => {
9560 lsp_store.on_lsp_work_start(
9561 language_server_id,
9562 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9563 .context("invalid progress token value")?,
9564 LanguageServerProgress {
9565 title: payload.title,
9566 is_disk_based_diagnostics_progress: false,
9567 is_cancellable: payload.is_cancellable.unwrap_or(false),
9568 message: payload.message,
9569 percentage: payload.percentage.map(|p| p as usize),
9570 last_update_at: cx.background_executor().now(),
9571 },
9572 cx,
9573 );
9574 }
9575 proto::update_language_server::Variant::WorkProgress(payload) => {
9576 lsp_store.on_lsp_work_progress(
9577 language_server_id,
9578 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9579 .context("invalid progress token value")?,
9580 LanguageServerProgress {
9581 title: None,
9582 is_disk_based_diagnostics_progress: false,
9583 is_cancellable: payload.is_cancellable.unwrap_or(false),
9584 message: payload.message,
9585 percentage: payload.percentage.map(|p| p as usize),
9586 last_update_at: cx.background_executor().now(),
9587 },
9588 cx,
9589 );
9590 }
9591
9592 proto::update_language_server::Variant::WorkEnd(payload) => {
9593 lsp_store.on_lsp_work_end(
9594 language_server_id,
9595 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9596 .context("invalid progress token value")?,
9597 cx,
9598 );
9599 }
9600
9601 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9602 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9603 }
9604
9605 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9606 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9607 }
9608
9609 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9610 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9611 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9612 cx.emit(LspStoreEvent::LanguageServerUpdate {
9613 language_server_id,
9614 name: envelope
9615 .payload
9616 .server_name
9617 .map(SharedString::new)
9618 .map(LanguageServerName),
9619 message: non_lsp,
9620 });
9621 }
9622 }
9623
9624 Ok(())
9625 })
9626 }
9627
9628 async fn handle_language_server_log(
9629 this: Entity<Self>,
9630 envelope: TypedEnvelope<proto::LanguageServerLog>,
9631 mut cx: AsyncApp,
9632 ) -> Result<()> {
9633 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9634 let log_type = envelope
9635 .payload
9636 .log_type
9637 .map(LanguageServerLogType::from_proto)
9638 .context("invalid language server log type")?;
9639
9640 let message = envelope.payload.message;
9641
9642 this.update(&mut cx, |_, cx| {
9643 cx.emit(LspStoreEvent::LanguageServerLog(
9644 language_server_id,
9645 log_type,
9646 message,
9647 ));
9648 });
9649 Ok(())
9650 }
9651
9652 async fn handle_lsp_ext_cancel_flycheck(
9653 lsp_store: Entity<Self>,
9654 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9655 cx: AsyncApp,
9656 ) -> Result<proto::Ack> {
9657 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9658 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9659 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9660 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9661 } else {
9662 None
9663 }
9664 });
9665 if let Some(task) = task {
9666 task.context("handling lsp ext cancel flycheck")?;
9667 }
9668
9669 Ok(proto::Ack {})
9670 }
9671
9672 async fn handle_lsp_ext_run_flycheck(
9673 lsp_store: Entity<Self>,
9674 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9675 mut cx: AsyncApp,
9676 ) -> Result<proto::Ack> {
9677 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9678 lsp_store.update(&mut cx, |lsp_store, cx| {
9679 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9680 let text_document = if envelope.payload.current_file_only {
9681 let buffer_id = envelope
9682 .payload
9683 .buffer_id
9684 .map(|id| BufferId::new(id))
9685 .transpose()?;
9686 buffer_id
9687 .and_then(|buffer_id| {
9688 lsp_store
9689 .buffer_store()
9690 .read(cx)
9691 .get(buffer_id)
9692 .and_then(|buffer| {
9693 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9694 })
9695 .map(|path| make_text_document_identifier(&path))
9696 })
9697 .transpose()?
9698 } else {
9699 None
9700 };
9701 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9702 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9703 )?;
9704 }
9705 anyhow::Ok(())
9706 })?;
9707
9708 Ok(proto::Ack {})
9709 }
9710
9711 async fn handle_lsp_ext_clear_flycheck(
9712 lsp_store: Entity<Self>,
9713 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9714 cx: AsyncApp,
9715 ) -> Result<proto::Ack> {
9716 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9717 lsp_store.read_with(&cx, |lsp_store, _| {
9718 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9719 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9720 } else {
9721 None
9722 }
9723 });
9724
9725 Ok(proto::Ack {})
9726 }
9727
9728 pub fn disk_based_diagnostics_started(
9729 &mut self,
9730 language_server_id: LanguageServerId,
9731 cx: &mut Context<Self>,
9732 ) {
9733 if let Some(language_server_status) =
9734 self.language_server_statuses.get_mut(&language_server_id)
9735 {
9736 language_server_status.has_pending_diagnostic_updates = true;
9737 }
9738
9739 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9740 cx.emit(LspStoreEvent::LanguageServerUpdate {
9741 language_server_id,
9742 name: self
9743 .language_server_adapter_for_id(language_server_id)
9744 .map(|adapter| adapter.name()),
9745 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9746 Default::default(),
9747 ),
9748 })
9749 }
9750
9751 pub fn disk_based_diagnostics_finished(
9752 &mut self,
9753 language_server_id: LanguageServerId,
9754 cx: &mut Context<Self>,
9755 ) {
9756 if let Some(language_server_status) =
9757 self.language_server_statuses.get_mut(&language_server_id)
9758 {
9759 language_server_status.has_pending_diagnostic_updates = false;
9760 }
9761
9762 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9763 cx.emit(LspStoreEvent::LanguageServerUpdate {
9764 language_server_id,
9765 name: self
9766 .language_server_adapter_for_id(language_server_id)
9767 .map(|adapter| adapter.name()),
9768 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9769 Default::default(),
9770 ),
9771 })
9772 }
9773
9774 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9775 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9776 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9777 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9778 // the language server might take some time to publish diagnostics.
9779 fn simulate_disk_based_diagnostics_events_if_needed(
9780 &mut self,
9781 language_server_id: LanguageServerId,
9782 cx: &mut Context<Self>,
9783 ) {
9784 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9785
9786 let Some(LanguageServerState::Running {
9787 simulate_disk_based_diagnostics_completion,
9788 adapter,
9789 ..
9790 }) = self
9791 .as_local_mut()
9792 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9793 else {
9794 return;
9795 };
9796
9797 if adapter.disk_based_diagnostics_progress_token.is_some() {
9798 return;
9799 }
9800
9801 let prev_task =
9802 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9803 cx.background_executor()
9804 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9805 .await;
9806
9807 this.update(cx, |this, cx| {
9808 this.disk_based_diagnostics_finished(language_server_id, cx);
9809
9810 if let Some(LanguageServerState::Running {
9811 simulate_disk_based_diagnostics_completion,
9812 ..
9813 }) = this.as_local_mut().and_then(|local_store| {
9814 local_store.language_servers.get_mut(&language_server_id)
9815 }) {
9816 *simulate_disk_based_diagnostics_completion = None;
9817 }
9818 })
9819 .ok();
9820 }));
9821
9822 if prev_task.is_none() {
9823 self.disk_based_diagnostics_started(language_server_id, cx);
9824 }
9825 }
9826
9827 pub fn language_server_statuses(
9828 &self,
9829 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9830 self.language_server_statuses
9831 .iter()
9832 .map(|(key, value)| (*key, value))
9833 }
9834
9835 pub(super) fn did_rename_entry(
9836 &self,
9837 worktree_id: WorktreeId,
9838 old_path: &Path,
9839 new_path: &Path,
9840 is_dir: bool,
9841 ) {
9842 maybe!({
9843 let local_store = self.as_local()?;
9844
9845 let old_uri = lsp::Uri::from_file_path(old_path)
9846 .ok()
9847 .map(|uri| uri.to_string())?;
9848 let new_uri = lsp::Uri::from_file_path(new_path)
9849 .ok()
9850 .map(|uri| uri.to_string())?;
9851
9852 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9853 let Some(filter) = local_store
9854 .language_server_paths_watched_for_rename
9855 .get(&language_server.server_id())
9856 else {
9857 continue;
9858 };
9859
9860 if filter.should_send_did_rename(&old_uri, is_dir) {
9861 language_server
9862 .notify::<DidRenameFiles>(RenameFilesParams {
9863 files: vec![FileRename {
9864 old_uri: old_uri.clone(),
9865 new_uri: new_uri.clone(),
9866 }],
9867 })
9868 .ok();
9869 }
9870 }
9871 Some(())
9872 });
9873 }
9874
9875 pub(super) fn will_rename_entry(
9876 this: WeakEntity<Self>,
9877 worktree_id: WorktreeId,
9878 old_path: &Path,
9879 new_path: &Path,
9880 is_dir: bool,
9881 cx: AsyncApp,
9882 ) -> Task<ProjectTransaction> {
9883 let old_uri = lsp::Uri::from_file_path(old_path)
9884 .ok()
9885 .map(|uri| uri.to_string());
9886 let new_uri = lsp::Uri::from_file_path(new_path)
9887 .ok()
9888 .map(|uri| uri.to_string());
9889 cx.spawn(async move |cx| {
9890 let mut tasks = vec![];
9891 this.update(cx, |this, cx| {
9892 let local_store = this.as_local()?;
9893 let old_uri = old_uri?;
9894 let new_uri = new_uri?;
9895 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9896 let Some(filter) = local_store
9897 .language_server_paths_watched_for_rename
9898 .get(&language_server.server_id())
9899 else {
9900 continue;
9901 };
9902
9903 if filter.should_send_will_rename(&old_uri, is_dir) {
9904 let apply_edit = cx.spawn({
9905 let old_uri = old_uri.clone();
9906 let new_uri = new_uri.clone();
9907 let language_server = language_server.clone();
9908 async move |this, cx| {
9909 let edit = language_server
9910 .request::<WillRenameFiles>(RenameFilesParams {
9911 files: vec![FileRename { old_uri, new_uri }],
9912 })
9913 .await
9914 .into_response()
9915 .context("will rename files")
9916 .log_err()
9917 .flatten()?;
9918
9919 let transaction = LocalLspStore::deserialize_workspace_edit(
9920 this.upgrade()?,
9921 edit,
9922 false,
9923 language_server.clone(),
9924 cx,
9925 )
9926 .await
9927 .ok()?;
9928 Some(transaction)
9929 }
9930 });
9931 tasks.push(apply_edit);
9932 }
9933 }
9934 Some(())
9935 })
9936 .ok()
9937 .flatten();
9938 let mut merged_transaction = ProjectTransaction::default();
9939 for task in tasks {
9940 // Await on tasks sequentially so that the order of application of edits is deterministic
9941 // (at least with regards to the order of registration of language servers)
9942 if let Some(transaction) = task.await {
9943 for (buffer, buffer_transaction) in transaction.0 {
9944 merged_transaction.0.insert(buffer, buffer_transaction);
9945 }
9946 }
9947 }
9948 merged_transaction
9949 })
9950 }
9951
9952 fn lsp_notify_abs_paths_changed(
9953 &mut self,
9954 server_id: LanguageServerId,
9955 changes: Vec<PathEvent>,
9956 ) {
9957 maybe!({
9958 let server = self.language_server_for_id(server_id)?;
9959 let changes = changes
9960 .into_iter()
9961 .filter_map(|event| {
9962 let typ = match event.kind? {
9963 PathEventKind::Created => lsp::FileChangeType::CREATED,
9964 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9965 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9966 };
9967 Some(lsp::FileEvent {
9968 uri: file_path_to_lsp_url(&event.path).log_err()?,
9969 typ,
9970 })
9971 })
9972 .collect::<Vec<_>>();
9973 if !changes.is_empty() {
9974 server
9975 .notify::<lsp::notification::DidChangeWatchedFiles>(
9976 lsp::DidChangeWatchedFilesParams { changes },
9977 )
9978 .ok();
9979 }
9980 Some(())
9981 });
9982 }
9983
9984 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9985 self.as_local()?.language_server_for_id(id)
9986 }
9987
9988 fn on_lsp_progress(
9989 &mut self,
9990 progress_params: lsp::ProgressParams,
9991 language_server_id: LanguageServerId,
9992 disk_based_diagnostics_progress_token: Option<String>,
9993 cx: &mut Context<Self>,
9994 ) {
9995 match progress_params.value {
9996 lsp::ProgressParamsValue::WorkDone(progress) => {
9997 self.handle_work_done_progress(
9998 progress,
9999 language_server_id,
10000 disk_based_diagnostics_progress_token,
10001 ProgressToken::from_lsp(progress_params.token),
10002 cx,
10003 );
10004 }
10005 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10006 let registration_id = match progress_params.token {
10007 lsp::NumberOrString::Number(_) => None,
10008 lsp::NumberOrString::String(token) => token
10009 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10010 .map(|(_, id)| id.to_owned()),
10011 };
10012 if let Some(LanguageServerState::Running {
10013 workspace_diagnostics_refresh_tasks,
10014 ..
10015 }) = self
10016 .as_local_mut()
10017 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10018 && let Some(workspace_diagnostics) =
10019 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10020 {
10021 workspace_diagnostics.progress_tx.try_send(()).ok();
10022 self.apply_workspace_diagnostic_report(
10023 language_server_id,
10024 report,
10025 registration_id.map(SharedString::from),
10026 cx,
10027 )
10028 }
10029 }
10030 }
10031 }
10032
10033 fn handle_work_done_progress(
10034 &mut self,
10035 progress: lsp::WorkDoneProgress,
10036 language_server_id: LanguageServerId,
10037 disk_based_diagnostics_progress_token: Option<String>,
10038 token: ProgressToken,
10039 cx: &mut Context<Self>,
10040 ) {
10041 let language_server_status =
10042 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10043 status
10044 } else {
10045 return;
10046 };
10047
10048 if !language_server_status.progress_tokens.contains(&token) {
10049 return;
10050 }
10051
10052 let is_disk_based_diagnostics_progress =
10053 if let (Some(disk_based_token), ProgressToken::String(token)) =
10054 (&disk_based_diagnostics_progress_token, &token)
10055 {
10056 token.starts_with(disk_based_token)
10057 } else {
10058 false
10059 };
10060
10061 match progress {
10062 lsp::WorkDoneProgress::Begin(report) => {
10063 if is_disk_based_diagnostics_progress {
10064 self.disk_based_diagnostics_started(language_server_id, cx);
10065 }
10066 self.on_lsp_work_start(
10067 language_server_id,
10068 token.clone(),
10069 LanguageServerProgress {
10070 title: Some(report.title),
10071 is_disk_based_diagnostics_progress,
10072 is_cancellable: report.cancellable.unwrap_or(false),
10073 message: report.message.clone(),
10074 percentage: report.percentage.map(|p| p as usize),
10075 last_update_at: cx.background_executor().now(),
10076 },
10077 cx,
10078 );
10079 }
10080 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10081 language_server_id,
10082 token,
10083 LanguageServerProgress {
10084 title: None,
10085 is_disk_based_diagnostics_progress,
10086 is_cancellable: report.cancellable.unwrap_or(false),
10087 message: report.message,
10088 percentage: report.percentage.map(|p| p as usize),
10089 last_update_at: cx.background_executor().now(),
10090 },
10091 cx,
10092 ),
10093 lsp::WorkDoneProgress::End(_) => {
10094 language_server_status.progress_tokens.remove(&token);
10095 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10096 if is_disk_based_diagnostics_progress {
10097 self.disk_based_diagnostics_finished(language_server_id, cx);
10098 }
10099 }
10100 }
10101 }
10102
10103 fn on_lsp_work_start(
10104 &mut self,
10105 language_server_id: LanguageServerId,
10106 token: ProgressToken,
10107 progress: LanguageServerProgress,
10108 cx: &mut Context<Self>,
10109 ) {
10110 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10111 status.pending_work.insert(token.clone(), progress.clone());
10112 cx.notify();
10113 }
10114 cx.emit(LspStoreEvent::LanguageServerUpdate {
10115 language_server_id,
10116 name: self
10117 .language_server_adapter_for_id(language_server_id)
10118 .map(|adapter| adapter.name()),
10119 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10120 token: Some(token.to_proto()),
10121 title: progress.title,
10122 message: progress.message,
10123 percentage: progress.percentage.map(|p| p as u32),
10124 is_cancellable: Some(progress.is_cancellable),
10125 }),
10126 })
10127 }
10128
10129 fn on_lsp_work_progress(
10130 &mut self,
10131 language_server_id: LanguageServerId,
10132 token: ProgressToken,
10133 progress: LanguageServerProgress,
10134 cx: &mut Context<Self>,
10135 ) {
10136 let mut did_update = false;
10137 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10138 match status.pending_work.entry(token.clone()) {
10139 btree_map::Entry::Vacant(entry) => {
10140 entry.insert(progress.clone());
10141 did_update = true;
10142 }
10143 btree_map::Entry::Occupied(mut entry) => {
10144 let entry = entry.get_mut();
10145 if (progress.last_update_at - entry.last_update_at)
10146 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10147 {
10148 entry.last_update_at = progress.last_update_at;
10149 if progress.message.is_some() {
10150 entry.message = progress.message.clone();
10151 }
10152 if progress.percentage.is_some() {
10153 entry.percentage = progress.percentage;
10154 }
10155 if progress.is_cancellable != entry.is_cancellable {
10156 entry.is_cancellable = progress.is_cancellable;
10157 }
10158 did_update = true;
10159 }
10160 }
10161 }
10162 }
10163
10164 if did_update {
10165 cx.emit(LspStoreEvent::LanguageServerUpdate {
10166 language_server_id,
10167 name: self
10168 .language_server_adapter_for_id(language_server_id)
10169 .map(|adapter| adapter.name()),
10170 message: proto::update_language_server::Variant::WorkProgress(
10171 proto::LspWorkProgress {
10172 token: Some(token.to_proto()),
10173 message: progress.message,
10174 percentage: progress.percentage.map(|p| p as u32),
10175 is_cancellable: Some(progress.is_cancellable),
10176 },
10177 ),
10178 })
10179 }
10180 }
10181
10182 fn on_lsp_work_end(
10183 &mut self,
10184 language_server_id: LanguageServerId,
10185 token: ProgressToken,
10186 cx: &mut Context<Self>,
10187 ) {
10188 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10189 if let Some(work) = status.pending_work.remove(&token)
10190 && !work.is_disk_based_diagnostics_progress
10191 {
10192 cx.emit(LspStoreEvent::RefreshInlayHints {
10193 server_id: language_server_id,
10194 request_id: None,
10195 });
10196 }
10197 cx.notify();
10198 }
10199
10200 cx.emit(LspStoreEvent::LanguageServerUpdate {
10201 language_server_id,
10202 name: self
10203 .language_server_adapter_for_id(language_server_id)
10204 .map(|adapter| adapter.name()),
10205 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10206 token: Some(token.to_proto()),
10207 }),
10208 })
10209 }
10210
10211 pub async fn handle_resolve_completion_documentation(
10212 this: Entity<Self>,
10213 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10214 mut cx: AsyncApp,
10215 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10216 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10217
10218 let completion = this
10219 .read_with(&cx, |this, cx| {
10220 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10221 let server = this
10222 .language_server_for_id(id)
10223 .with_context(|| format!("No language server {id}"))?;
10224
10225 anyhow::Ok(cx.background_spawn(async move {
10226 let can_resolve = server
10227 .capabilities()
10228 .completion_provider
10229 .as_ref()
10230 .and_then(|options| options.resolve_provider)
10231 .unwrap_or(false);
10232 if can_resolve {
10233 server
10234 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10235 .await
10236 .into_response()
10237 .context("resolve completion item")
10238 } else {
10239 anyhow::Ok(lsp_completion)
10240 }
10241 }))
10242 })?
10243 .await?;
10244
10245 let mut documentation_is_markdown = false;
10246 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10247 let documentation = match completion.documentation {
10248 Some(lsp::Documentation::String(text)) => text,
10249
10250 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10251 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10252 value
10253 }
10254
10255 _ => String::new(),
10256 };
10257
10258 // If we have a new buffer_id, that means we're talking to a new client
10259 // and want to check for new text_edits in the completion too.
10260 let mut old_replace_start = None;
10261 let mut old_replace_end = None;
10262 let mut old_insert_start = None;
10263 let mut old_insert_end = None;
10264 let mut new_text = String::default();
10265 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10266 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10267 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10268 anyhow::Ok(buffer.read(cx).snapshot())
10269 })?;
10270
10271 if let Some(text_edit) = completion.text_edit.as_ref() {
10272 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10273
10274 if let Some(mut edit) = edit {
10275 LineEnding::normalize(&mut edit.new_text);
10276
10277 new_text = edit.new_text;
10278 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10279 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10280 if let Some(insert_range) = edit.insert_range {
10281 old_insert_start = Some(serialize_anchor(&insert_range.start));
10282 old_insert_end = Some(serialize_anchor(&insert_range.end));
10283 }
10284 }
10285 }
10286 }
10287
10288 Ok(proto::ResolveCompletionDocumentationResponse {
10289 documentation,
10290 documentation_is_markdown,
10291 old_replace_start,
10292 old_replace_end,
10293 new_text,
10294 lsp_completion,
10295 old_insert_start,
10296 old_insert_end,
10297 })
10298 }
10299
10300 async fn handle_on_type_formatting(
10301 this: Entity<Self>,
10302 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10303 mut cx: AsyncApp,
10304 ) -> Result<proto::OnTypeFormattingResponse> {
10305 let on_type_formatting = this.update(&mut cx, |this, cx| {
10306 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10307 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10308 let position = envelope
10309 .payload
10310 .position
10311 .and_then(deserialize_anchor)
10312 .context("invalid position")?;
10313 anyhow::Ok(this.apply_on_type_formatting(
10314 buffer,
10315 position,
10316 envelope.payload.trigger.clone(),
10317 cx,
10318 ))
10319 })?;
10320
10321 let transaction = on_type_formatting
10322 .await?
10323 .as_ref()
10324 .map(language::proto::serialize_transaction);
10325 Ok(proto::OnTypeFormattingResponse { transaction })
10326 }
10327
10328 async fn handle_refresh_inlay_hints(
10329 lsp_store: Entity<Self>,
10330 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10331 mut cx: AsyncApp,
10332 ) -> Result<proto::Ack> {
10333 lsp_store.update(&mut cx, |_, cx| {
10334 cx.emit(LspStoreEvent::RefreshInlayHints {
10335 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10336 request_id: envelope.payload.request_id.map(|id| id as usize),
10337 });
10338 });
10339 Ok(proto::Ack {})
10340 }
10341
10342 async fn handle_pull_workspace_diagnostics(
10343 lsp_store: Entity<Self>,
10344 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10345 mut cx: AsyncApp,
10346 ) -> Result<proto::Ack> {
10347 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10348 lsp_store.update(&mut cx, |lsp_store, _| {
10349 lsp_store.pull_workspace_diagnostics(server_id);
10350 });
10351 Ok(proto::Ack {})
10352 }
10353
10354 async fn handle_get_color_presentation(
10355 lsp_store: Entity<Self>,
10356 envelope: TypedEnvelope<proto::GetColorPresentation>,
10357 mut cx: AsyncApp,
10358 ) -> Result<proto::GetColorPresentationResponse> {
10359 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10360 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10361 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10362 })?;
10363
10364 let color = envelope
10365 .payload
10366 .color
10367 .context("invalid color resolve request")?;
10368 let start = color
10369 .lsp_range_start
10370 .context("invalid color resolve request")?;
10371 let end = color
10372 .lsp_range_end
10373 .context("invalid color resolve request")?;
10374
10375 let color = DocumentColor {
10376 lsp_range: lsp::Range {
10377 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10378 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10379 },
10380 color: lsp::Color {
10381 red: color.red,
10382 green: color.green,
10383 blue: color.blue,
10384 alpha: color.alpha,
10385 },
10386 resolved: false,
10387 color_presentations: Vec::new(),
10388 };
10389 let resolved_color = lsp_store
10390 .update(&mut cx, |lsp_store, cx| {
10391 lsp_store.resolve_color_presentation(
10392 color,
10393 buffer.clone(),
10394 LanguageServerId(envelope.payload.server_id as usize),
10395 cx,
10396 )
10397 })
10398 .await
10399 .context("resolving color presentation")?;
10400
10401 Ok(proto::GetColorPresentationResponse {
10402 presentations: resolved_color
10403 .color_presentations
10404 .into_iter()
10405 .map(|presentation| proto::ColorPresentation {
10406 label: presentation.label.to_string(),
10407 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10408 additional_text_edits: presentation
10409 .additional_text_edits
10410 .into_iter()
10411 .map(serialize_lsp_edit)
10412 .collect(),
10413 })
10414 .collect(),
10415 })
10416 }
10417
10418 async fn handle_resolve_inlay_hint(
10419 lsp_store: Entity<Self>,
10420 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10421 mut cx: AsyncApp,
10422 ) -> Result<proto::ResolveInlayHintResponse> {
10423 let proto_hint = envelope
10424 .payload
10425 .hint
10426 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10427 let hint = InlayHints::proto_to_project_hint(proto_hint)
10428 .context("resolved proto inlay hint conversion")?;
10429 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10430 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10431 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10432 })?;
10433 let response_hint = lsp_store
10434 .update(&mut cx, |lsp_store, cx| {
10435 lsp_store.resolve_inlay_hint(
10436 hint,
10437 buffer,
10438 LanguageServerId(envelope.payload.language_server_id as usize),
10439 cx,
10440 )
10441 })
10442 .await
10443 .context("inlay hints fetch")?;
10444 Ok(proto::ResolveInlayHintResponse {
10445 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10446 })
10447 }
10448
10449 async fn handle_refresh_code_lens(
10450 this: Entity<Self>,
10451 _: TypedEnvelope<proto::RefreshCodeLens>,
10452 mut cx: AsyncApp,
10453 ) -> Result<proto::Ack> {
10454 this.update(&mut cx, |_, cx| {
10455 cx.emit(LspStoreEvent::RefreshCodeLens);
10456 });
10457 Ok(proto::Ack {})
10458 }
10459
10460 async fn handle_open_buffer_for_symbol(
10461 this: Entity<Self>,
10462 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10463 mut cx: AsyncApp,
10464 ) -> Result<proto::OpenBufferForSymbolResponse> {
10465 let peer_id = envelope.original_sender_id().unwrap_or_default();
10466 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10467 let symbol = Self::deserialize_symbol(symbol)?;
10468 this.read_with(&cx, |this, _| {
10469 if let SymbolLocation::OutsideProject {
10470 abs_path,
10471 signature,
10472 } = &symbol.path
10473 {
10474 let new_signature = this.symbol_signature(&abs_path);
10475 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10476 }
10477 Ok(())
10478 })?;
10479 let buffer = this
10480 .update(&mut cx, |this, cx| {
10481 this.open_buffer_for_symbol(
10482 &Symbol {
10483 language_server_name: symbol.language_server_name,
10484 source_worktree_id: symbol.source_worktree_id,
10485 source_language_server_id: symbol.source_language_server_id,
10486 path: symbol.path,
10487 name: symbol.name,
10488 kind: symbol.kind,
10489 range: symbol.range,
10490 label: CodeLabel::default(),
10491 },
10492 cx,
10493 )
10494 })
10495 .await?;
10496
10497 this.update(&mut cx, |this, cx| {
10498 let is_private = buffer
10499 .read(cx)
10500 .file()
10501 .map(|f| f.is_private())
10502 .unwrap_or_default();
10503 if is_private {
10504 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10505 } else {
10506 this.buffer_store
10507 .update(cx, |buffer_store, cx| {
10508 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10509 })
10510 .detach_and_log_err(cx);
10511 let buffer_id = buffer.read(cx).remote_id().to_proto();
10512 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10513 }
10514 })
10515 }
10516
10517 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10518 let mut hasher = Sha256::new();
10519 hasher.update(abs_path.to_string_lossy().as_bytes());
10520 hasher.update(self.nonce.to_be_bytes());
10521 hasher.finalize().as_slice().try_into().unwrap()
10522 }
10523
10524 pub async fn handle_get_project_symbols(
10525 this: Entity<Self>,
10526 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10527 mut cx: AsyncApp,
10528 ) -> Result<proto::GetProjectSymbolsResponse> {
10529 let symbols = this
10530 .update(&mut cx, |this, cx| {
10531 this.symbols(&envelope.payload.query, cx)
10532 })
10533 .await?;
10534
10535 Ok(proto::GetProjectSymbolsResponse {
10536 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10537 })
10538 }
10539
10540 pub async fn handle_restart_language_servers(
10541 this: Entity<Self>,
10542 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10543 mut cx: AsyncApp,
10544 ) -> Result<proto::Ack> {
10545 this.update(&mut cx, |lsp_store, cx| {
10546 let buffers =
10547 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10548 lsp_store.restart_language_servers_for_buffers(
10549 buffers,
10550 envelope
10551 .payload
10552 .only_servers
10553 .into_iter()
10554 .filter_map(|selector| {
10555 Some(match selector.selector? {
10556 proto::language_server_selector::Selector::ServerId(server_id) => {
10557 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10558 }
10559 proto::language_server_selector::Selector::Name(name) => {
10560 LanguageServerSelector::Name(LanguageServerName(
10561 SharedString::from(name),
10562 ))
10563 }
10564 })
10565 })
10566 .collect(),
10567 cx,
10568 );
10569 });
10570
10571 Ok(proto::Ack {})
10572 }
10573
10574 pub async fn handle_stop_language_servers(
10575 lsp_store: Entity<Self>,
10576 envelope: TypedEnvelope<proto::StopLanguageServers>,
10577 mut cx: AsyncApp,
10578 ) -> Result<proto::Ack> {
10579 lsp_store.update(&mut cx, |lsp_store, cx| {
10580 if envelope.payload.all
10581 && envelope.payload.also_servers.is_empty()
10582 && envelope.payload.buffer_ids.is_empty()
10583 {
10584 lsp_store.stop_all_language_servers(cx);
10585 } else {
10586 let buffers =
10587 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10588 lsp_store
10589 .stop_language_servers_for_buffers(
10590 buffers,
10591 envelope
10592 .payload
10593 .also_servers
10594 .into_iter()
10595 .filter_map(|selector| {
10596 Some(match selector.selector? {
10597 proto::language_server_selector::Selector::ServerId(
10598 server_id,
10599 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10600 server_id,
10601 )),
10602 proto::language_server_selector::Selector::Name(name) => {
10603 LanguageServerSelector::Name(LanguageServerName(
10604 SharedString::from(name),
10605 ))
10606 }
10607 })
10608 })
10609 .collect(),
10610 cx,
10611 )
10612 .detach_and_log_err(cx);
10613 }
10614 });
10615
10616 Ok(proto::Ack {})
10617 }
10618
10619 pub async fn handle_cancel_language_server_work(
10620 lsp_store: Entity<Self>,
10621 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10622 mut cx: AsyncApp,
10623 ) -> Result<proto::Ack> {
10624 lsp_store.update(&mut cx, |lsp_store, cx| {
10625 if let Some(work) = envelope.payload.work {
10626 match work {
10627 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10628 let buffers =
10629 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10630 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10631 }
10632 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10633 let server_id = LanguageServerId::from_proto(work.language_server_id);
10634 let token = work
10635 .token
10636 .map(|token| {
10637 ProgressToken::from_proto(token)
10638 .context("invalid work progress token")
10639 })
10640 .transpose()?;
10641 lsp_store.cancel_language_server_work(server_id, token, cx);
10642 }
10643 }
10644 }
10645 anyhow::Ok(())
10646 })?;
10647
10648 Ok(proto::Ack {})
10649 }
10650
10651 fn buffer_ids_to_buffers(
10652 &mut self,
10653 buffer_ids: impl Iterator<Item = u64>,
10654 cx: &mut Context<Self>,
10655 ) -> Vec<Entity<Buffer>> {
10656 buffer_ids
10657 .into_iter()
10658 .flat_map(|buffer_id| {
10659 self.buffer_store
10660 .read(cx)
10661 .get(BufferId::new(buffer_id).log_err()?)
10662 })
10663 .collect::<Vec<_>>()
10664 }
10665
10666 async fn handle_apply_additional_edits_for_completion(
10667 this: Entity<Self>,
10668 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10669 mut cx: AsyncApp,
10670 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10671 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10672 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10673 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10674 let completion = Self::deserialize_completion(
10675 envelope.payload.completion.context("invalid completion")?,
10676 )?;
10677 anyhow::Ok((buffer, completion))
10678 })?;
10679
10680 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10681 this.apply_additional_edits_for_completion(
10682 buffer,
10683 Rc::new(RefCell::new(Box::new([Completion {
10684 replace_range: completion.replace_range,
10685 new_text: completion.new_text,
10686 source: completion.source,
10687 documentation: None,
10688 label: CodeLabel::default(),
10689 match_start: None,
10690 snippet_deduplication_key: None,
10691 insert_text_mode: None,
10692 icon_path: None,
10693 confirm: None,
10694 }]))),
10695 0,
10696 false,
10697 cx,
10698 )
10699 });
10700
10701 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10702 transaction: apply_additional_edits
10703 .await?
10704 .as_ref()
10705 .map(language::proto::serialize_transaction),
10706 })
10707 }
10708
10709 pub fn last_formatting_failure(&self) -> Option<&str> {
10710 self.last_formatting_failure.as_deref()
10711 }
10712
10713 pub fn reset_last_formatting_failure(&mut self) {
10714 self.last_formatting_failure = None;
10715 }
10716
10717 pub fn environment_for_buffer(
10718 &self,
10719 buffer: &Entity<Buffer>,
10720 cx: &mut Context<Self>,
10721 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10722 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10723 environment.update(cx, |env, cx| {
10724 env.buffer_environment(buffer, &self.worktree_store, cx)
10725 })
10726 } else {
10727 Task::ready(None).shared()
10728 }
10729 }
10730
10731 pub fn format(
10732 &mut self,
10733 buffers: HashSet<Entity<Buffer>>,
10734 target: LspFormatTarget,
10735 push_to_history: bool,
10736 trigger: FormatTrigger,
10737 cx: &mut Context<Self>,
10738 ) -> Task<anyhow::Result<ProjectTransaction>> {
10739 let logger = zlog::scoped!("format");
10740 if self.as_local().is_some() {
10741 zlog::trace!(logger => "Formatting locally");
10742 let logger = zlog::scoped!(logger => "local");
10743 let buffers = buffers
10744 .into_iter()
10745 .map(|buffer_handle| {
10746 let buffer = buffer_handle.read(cx);
10747 let buffer_abs_path = File::from_dyn(buffer.file())
10748 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10749
10750 (buffer_handle, buffer_abs_path, buffer.remote_id())
10751 })
10752 .collect::<Vec<_>>();
10753
10754 cx.spawn(async move |lsp_store, cx| {
10755 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10756
10757 for (handle, abs_path, id) in buffers {
10758 let env = lsp_store
10759 .update(cx, |lsp_store, cx| {
10760 lsp_store.environment_for_buffer(&handle, cx)
10761 })?
10762 .await;
10763
10764 let ranges = match &target {
10765 LspFormatTarget::Buffers => None,
10766 LspFormatTarget::Ranges(ranges) => {
10767 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10768 }
10769 };
10770
10771 formattable_buffers.push(FormattableBuffer {
10772 handle,
10773 abs_path,
10774 env,
10775 ranges,
10776 });
10777 }
10778 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10779
10780 let format_timer = zlog::time!(logger => "Formatting buffers");
10781 let result = LocalLspStore::format_locally(
10782 lsp_store.clone(),
10783 formattable_buffers,
10784 push_to_history,
10785 trigger,
10786 logger,
10787 cx,
10788 )
10789 .await;
10790 format_timer.end();
10791
10792 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10793
10794 lsp_store.update(cx, |lsp_store, _| {
10795 lsp_store.update_last_formatting_failure(&result);
10796 })?;
10797
10798 result
10799 })
10800 } else if let Some((client, project_id)) = self.upstream_client() {
10801 zlog::trace!(logger => "Formatting remotely");
10802 let logger = zlog::scoped!(logger => "remote");
10803
10804 let buffer_ranges = match &target {
10805 LspFormatTarget::Buffers => Vec::new(),
10806 LspFormatTarget::Ranges(ranges) => ranges
10807 .iter()
10808 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10809 buffer_id: buffer_id.to_proto(),
10810 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10811 })
10812 .collect(),
10813 };
10814
10815 let buffer_store = self.buffer_store();
10816 cx.spawn(async move |lsp_store, cx| {
10817 zlog::trace!(logger => "Sending remote format request");
10818 let request_timer = zlog::time!(logger => "remote format request");
10819 let result = client
10820 .request(proto::FormatBuffers {
10821 project_id,
10822 trigger: trigger as i32,
10823 buffer_ids: buffers
10824 .iter()
10825 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10826 .collect(),
10827 buffer_ranges,
10828 })
10829 .await
10830 .and_then(|result| result.transaction.context("missing transaction"));
10831 request_timer.end();
10832
10833 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10834
10835 lsp_store.update(cx, |lsp_store, _| {
10836 lsp_store.update_last_formatting_failure(&result);
10837 })?;
10838
10839 let transaction_response = result?;
10840 let _timer = zlog::time!(logger => "deserializing project transaction");
10841 buffer_store
10842 .update(cx, |buffer_store, cx| {
10843 buffer_store.deserialize_project_transaction(
10844 transaction_response,
10845 push_to_history,
10846 cx,
10847 )
10848 })
10849 .await
10850 })
10851 } else {
10852 zlog::trace!(logger => "Not formatting");
10853 Task::ready(Ok(ProjectTransaction::default()))
10854 }
10855 }
10856
10857 async fn handle_format_buffers(
10858 this: Entity<Self>,
10859 envelope: TypedEnvelope<proto::FormatBuffers>,
10860 mut cx: AsyncApp,
10861 ) -> Result<proto::FormatBuffersResponse> {
10862 let sender_id = envelope.original_sender_id().unwrap_or_default();
10863 let format = this.update(&mut cx, |this, cx| {
10864 let mut buffers = HashSet::default();
10865 for buffer_id in &envelope.payload.buffer_ids {
10866 let buffer_id = BufferId::new(*buffer_id)?;
10867 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10868 }
10869
10870 let target = if envelope.payload.buffer_ranges.is_empty() {
10871 LspFormatTarget::Buffers
10872 } else {
10873 let mut ranges_map = BTreeMap::new();
10874 for buffer_range in &envelope.payload.buffer_ranges {
10875 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10876 let ranges: Result<Vec<_>> = buffer_range
10877 .ranges
10878 .iter()
10879 .map(|range| {
10880 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10881 })
10882 .collect();
10883 ranges_map.insert(buffer_id, ranges?);
10884 }
10885 LspFormatTarget::Ranges(ranges_map)
10886 };
10887
10888 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10889 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10890 })?;
10891
10892 let project_transaction = format.await?;
10893 let project_transaction = this.update(&mut cx, |this, cx| {
10894 this.buffer_store.update(cx, |buffer_store, cx| {
10895 buffer_store.serialize_project_transaction_for_peer(
10896 project_transaction,
10897 sender_id,
10898 cx,
10899 )
10900 })
10901 });
10902 Ok(proto::FormatBuffersResponse {
10903 transaction: Some(project_transaction),
10904 })
10905 }
10906
10907 async fn handle_apply_code_action_kind(
10908 this: Entity<Self>,
10909 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10910 mut cx: AsyncApp,
10911 ) -> Result<proto::ApplyCodeActionKindResponse> {
10912 let sender_id = envelope.original_sender_id().unwrap_or_default();
10913 let format = this.update(&mut cx, |this, cx| {
10914 let mut buffers = HashSet::default();
10915 for buffer_id in &envelope.payload.buffer_ids {
10916 let buffer_id = BufferId::new(*buffer_id)?;
10917 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10918 }
10919 let kind = match envelope.payload.kind.as_str() {
10920 "" => CodeActionKind::EMPTY,
10921 "quickfix" => CodeActionKind::QUICKFIX,
10922 "refactor" => CodeActionKind::REFACTOR,
10923 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10924 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10925 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10926 "source" => CodeActionKind::SOURCE,
10927 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10928 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10929 _ => anyhow::bail!(
10930 "Invalid code action kind {}",
10931 envelope.payload.kind.as_str()
10932 ),
10933 };
10934 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10935 })?;
10936
10937 let project_transaction = format.await?;
10938 let project_transaction = this.update(&mut cx, |this, cx| {
10939 this.buffer_store.update(cx, |buffer_store, cx| {
10940 buffer_store.serialize_project_transaction_for_peer(
10941 project_transaction,
10942 sender_id,
10943 cx,
10944 )
10945 })
10946 });
10947 Ok(proto::ApplyCodeActionKindResponse {
10948 transaction: Some(project_transaction),
10949 })
10950 }
10951
10952 async fn shutdown_language_server(
10953 server_state: Option<LanguageServerState>,
10954 name: LanguageServerName,
10955 cx: &mut AsyncApp,
10956 ) {
10957 let server = match server_state {
10958 Some(LanguageServerState::Starting { startup, .. }) => {
10959 let mut timer = cx
10960 .background_executor()
10961 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10962 .fuse();
10963
10964 select! {
10965 server = startup.fuse() => server,
10966 () = timer => {
10967 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10968 None
10969 },
10970 }
10971 }
10972
10973 Some(LanguageServerState::Running { server, .. }) => Some(server),
10974
10975 None => None,
10976 };
10977
10978 if let Some(server) = server
10979 && let Some(shutdown) = server.shutdown()
10980 {
10981 shutdown.await;
10982 }
10983 }
10984
10985 // Returns a list of all of the worktrees which no longer have a language server and the root path
10986 // for the stopped server
10987 fn stop_local_language_server(
10988 &mut self,
10989 server_id: LanguageServerId,
10990 cx: &mut Context<Self>,
10991 ) -> Task<()> {
10992 let local = match &mut self.mode {
10993 LspStoreMode::Local(local) => local,
10994 _ => {
10995 return Task::ready(());
10996 }
10997 };
10998
10999 // Remove this server ID from all entries in the given worktree.
11000 local
11001 .language_server_ids
11002 .retain(|_, state| state.id != server_id);
11003 self.buffer_store.update(cx, |buffer_store, cx| {
11004 for buffer in buffer_store.buffers() {
11005 buffer.update(cx, |buffer, cx| {
11006 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
11007 buffer.set_completion_triggers(server_id, Default::default(), cx);
11008 });
11009 }
11010 });
11011
11012 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
11013 summaries.retain(|path, summaries_by_server_id| {
11014 if summaries_by_server_id.remove(&server_id).is_some() {
11015 if let Some((client, project_id)) = self.downstream_client.clone() {
11016 client
11017 .send(proto::UpdateDiagnosticSummary {
11018 project_id,
11019 worktree_id: worktree_id.to_proto(),
11020 summary: Some(proto::DiagnosticSummary {
11021 path: path.as_ref().to_proto(),
11022 language_server_id: server_id.0 as u64,
11023 error_count: 0,
11024 warning_count: 0,
11025 }),
11026 more_summaries: Vec::new(),
11027 })
11028 .log_err();
11029 }
11030 !summaries_by_server_id.is_empty()
11031 } else {
11032 true
11033 }
11034 });
11035 }
11036
11037 let local = self.as_local_mut().unwrap();
11038 for diagnostics in local.diagnostics.values_mut() {
11039 diagnostics.retain(|_, diagnostics_by_server_id| {
11040 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11041 diagnostics_by_server_id.remove(ix);
11042 !diagnostics_by_server_id.is_empty()
11043 } else {
11044 true
11045 }
11046 });
11047 }
11048 local.language_server_watched_paths.remove(&server_id);
11049
11050 let server_state = local.language_servers.remove(&server_id);
11051 self.cleanup_lsp_data(server_id);
11052 let name = self
11053 .language_server_statuses
11054 .remove(&server_id)
11055 .map(|status| status.name)
11056 .or_else(|| {
11057 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11058 Some(adapter.name())
11059 } else {
11060 None
11061 }
11062 });
11063
11064 if let Some(name) = name {
11065 log::info!("stopping language server {name}");
11066 self.languages
11067 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11068 cx.notify();
11069
11070 return cx.spawn(async move |lsp_store, cx| {
11071 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11072 lsp_store
11073 .update(cx, |lsp_store, cx| {
11074 lsp_store
11075 .languages
11076 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11077 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11078 cx.notify();
11079 })
11080 .ok();
11081 });
11082 }
11083
11084 if server_state.is_some() {
11085 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11086 }
11087 Task::ready(())
11088 }
11089
11090 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11091 self.shutdown_all_language_servers(cx).detach();
11092 }
11093
11094 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11095 if let Some((client, project_id)) = self.upstream_client() {
11096 let request = client.request(proto::StopLanguageServers {
11097 project_id,
11098 buffer_ids: Vec::new(),
11099 also_servers: Vec::new(),
11100 all: true,
11101 });
11102 cx.background_spawn(async move {
11103 request.await.ok();
11104 })
11105 } else {
11106 let Some(local) = self.as_local_mut() else {
11107 return Task::ready(());
11108 };
11109 let language_servers_to_stop = local
11110 .language_server_ids
11111 .values()
11112 .map(|state| state.id)
11113 .collect();
11114 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11115 let tasks = language_servers_to_stop
11116 .into_iter()
11117 .map(|server| self.stop_local_language_server(server, cx))
11118 .collect::<Vec<_>>();
11119 cx.background_spawn(async move {
11120 futures::future::join_all(tasks).await;
11121 })
11122 }
11123 }
11124
11125 pub fn restart_language_servers_for_buffers(
11126 &mut self,
11127 buffers: Vec<Entity<Buffer>>,
11128 only_restart_servers: HashSet<LanguageServerSelector>,
11129 cx: &mut Context<Self>,
11130 ) {
11131 if let Some((client, project_id)) = self.upstream_client() {
11132 let request = client.request(proto::RestartLanguageServers {
11133 project_id,
11134 buffer_ids: buffers
11135 .into_iter()
11136 .map(|b| b.read(cx).remote_id().to_proto())
11137 .collect(),
11138 only_servers: only_restart_servers
11139 .into_iter()
11140 .map(|selector| {
11141 let selector = match selector {
11142 LanguageServerSelector::Id(language_server_id) => {
11143 proto::language_server_selector::Selector::ServerId(
11144 language_server_id.to_proto(),
11145 )
11146 }
11147 LanguageServerSelector::Name(language_server_name) => {
11148 proto::language_server_selector::Selector::Name(
11149 language_server_name.to_string(),
11150 )
11151 }
11152 };
11153 proto::LanguageServerSelector {
11154 selector: Some(selector),
11155 }
11156 })
11157 .collect(),
11158 all: false,
11159 });
11160 cx.background_spawn(request).detach_and_log_err(cx);
11161 } else {
11162 let stop_task = if only_restart_servers.is_empty() {
11163 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11164 } else {
11165 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11166 };
11167 cx.spawn(async move |lsp_store, cx| {
11168 stop_task.await;
11169 lsp_store.update(cx, |lsp_store, cx| {
11170 for buffer in buffers {
11171 lsp_store.register_buffer_with_language_servers(
11172 &buffer,
11173 only_restart_servers.clone(),
11174 true,
11175 cx,
11176 );
11177 }
11178 })
11179 })
11180 .detach();
11181 }
11182 }
11183
11184 pub fn stop_language_servers_for_buffers(
11185 &mut self,
11186 buffers: Vec<Entity<Buffer>>,
11187 also_stop_servers: HashSet<LanguageServerSelector>,
11188 cx: &mut Context<Self>,
11189 ) -> Task<Result<()>> {
11190 if let Some((client, project_id)) = self.upstream_client() {
11191 let request = client.request(proto::StopLanguageServers {
11192 project_id,
11193 buffer_ids: buffers
11194 .into_iter()
11195 .map(|b| b.read(cx).remote_id().to_proto())
11196 .collect(),
11197 also_servers: also_stop_servers
11198 .into_iter()
11199 .map(|selector| {
11200 let selector = match selector {
11201 LanguageServerSelector::Id(language_server_id) => {
11202 proto::language_server_selector::Selector::ServerId(
11203 language_server_id.to_proto(),
11204 )
11205 }
11206 LanguageServerSelector::Name(language_server_name) => {
11207 proto::language_server_selector::Selector::Name(
11208 language_server_name.to_string(),
11209 )
11210 }
11211 };
11212 proto::LanguageServerSelector {
11213 selector: Some(selector),
11214 }
11215 })
11216 .collect(),
11217 all: false,
11218 });
11219 cx.background_spawn(async move {
11220 let _ = request.await?;
11221 Ok(())
11222 })
11223 } else {
11224 let task =
11225 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11226 cx.background_spawn(async move {
11227 task.await;
11228 Ok(())
11229 })
11230 }
11231 }
11232
11233 fn stop_local_language_servers_for_buffers(
11234 &mut self,
11235 buffers: &[Entity<Buffer>],
11236 also_stop_servers: HashSet<LanguageServerSelector>,
11237 cx: &mut Context<Self>,
11238 ) -> Task<()> {
11239 let Some(local) = self.as_local_mut() else {
11240 return Task::ready(());
11241 };
11242 let mut language_server_names_to_stop = BTreeSet::default();
11243 let mut language_servers_to_stop = also_stop_servers
11244 .into_iter()
11245 .flat_map(|selector| match selector {
11246 LanguageServerSelector::Id(id) => Some(id),
11247 LanguageServerSelector::Name(name) => {
11248 language_server_names_to_stop.insert(name);
11249 None
11250 }
11251 })
11252 .collect::<BTreeSet<_>>();
11253
11254 let mut covered_worktrees = HashSet::default();
11255 for buffer in buffers {
11256 buffer.update(cx, |buffer, cx| {
11257 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11258 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11259 && covered_worktrees.insert(worktree_id)
11260 {
11261 language_server_names_to_stop.retain(|name| {
11262 let old_ids_count = language_servers_to_stop.len();
11263 let all_language_servers_with_this_name = local
11264 .language_server_ids
11265 .iter()
11266 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11267 language_servers_to_stop.extend(all_language_servers_with_this_name);
11268 old_ids_count == language_servers_to_stop.len()
11269 });
11270 }
11271 });
11272 }
11273 for name in language_server_names_to_stop {
11274 language_servers_to_stop.extend(
11275 local
11276 .language_server_ids
11277 .iter()
11278 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11279 );
11280 }
11281
11282 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11283 let tasks = language_servers_to_stop
11284 .into_iter()
11285 .map(|server| self.stop_local_language_server(server, cx))
11286 .collect::<Vec<_>>();
11287
11288 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11289 }
11290
11291 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11292 let (worktree, relative_path) =
11293 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11294
11295 let project_path = ProjectPath {
11296 worktree_id: worktree.read(cx).id(),
11297 path: relative_path,
11298 };
11299
11300 Some(
11301 self.buffer_store()
11302 .read(cx)
11303 .get_by_path(&project_path)?
11304 .read(cx),
11305 )
11306 }
11307
11308 #[cfg(any(test, feature = "test-support"))]
11309 pub fn update_diagnostics(
11310 &mut self,
11311 server_id: LanguageServerId,
11312 diagnostics: lsp::PublishDiagnosticsParams,
11313 result_id: Option<SharedString>,
11314 source_kind: DiagnosticSourceKind,
11315 disk_based_sources: &[String],
11316 cx: &mut Context<Self>,
11317 ) -> Result<()> {
11318 self.merge_lsp_diagnostics(
11319 source_kind,
11320 vec![DocumentDiagnosticsUpdate {
11321 diagnostics,
11322 result_id,
11323 server_id,
11324 disk_based_sources: Cow::Borrowed(disk_based_sources),
11325 registration_id: None,
11326 }],
11327 |_, _, _| false,
11328 cx,
11329 )
11330 }
11331
11332 pub fn merge_lsp_diagnostics(
11333 &mut self,
11334 source_kind: DiagnosticSourceKind,
11335 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11336 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11337 cx: &mut Context<Self>,
11338 ) -> Result<()> {
11339 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11340 let updates = lsp_diagnostics
11341 .into_iter()
11342 .filter_map(|update| {
11343 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11344 Some(DocumentDiagnosticsUpdate {
11345 diagnostics: self.lsp_to_document_diagnostics(
11346 abs_path,
11347 source_kind,
11348 update.server_id,
11349 update.diagnostics,
11350 &update.disk_based_sources,
11351 update.registration_id.clone(),
11352 ),
11353 result_id: update.result_id,
11354 server_id: update.server_id,
11355 disk_based_sources: update.disk_based_sources,
11356 registration_id: update.registration_id,
11357 })
11358 })
11359 .collect();
11360 self.merge_diagnostic_entries(updates, merge, cx)?;
11361 Ok(())
11362 }
11363
11364 fn lsp_to_document_diagnostics(
11365 &mut self,
11366 document_abs_path: PathBuf,
11367 source_kind: DiagnosticSourceKind,
11368 server_id: LanguageServerId,
11369 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11370 disk_based_sources: &[String],
11371 registration_id: Option<SharedString>,
11372 ) -> DocumentDiagnostics {
11373 let mut diagnostics = Vec::default();
11374 let mut primary_diagnostic_group_ids = HashMap::default();
11375 let mut sources_by_group_id = HashMap::default();
11376 let mut supporting_diagnostics = HashMap::default();
11377
11378 let adapter = self.language_server_adapter_for_id(server_id);
11379
11380 // Ensure that primary diagnostics are always the most severe
11381 lsp_diagnostics
11382 .diagnostics
11383 .sort_by_key(|item| item.severity);
11384
11385 for diagnostic in &lsp_diagnostics.diagnostics {
11386 let source = diagnostic.source.as_ref();
11387 let range = range_from_lsp(diagnostic.range);
11388 let is_supporting = diagnostic
11389 .related_information
11390 .as_ref()
11391 .is_some_and(|infos| {
11392 infos.iter().any(|info| {
11393 primary_diagnostic_group_ids.contains_key(&(
11394 source,
11395 diagnostic.code.clone(),
11396 range_from_lsp(info.location.range),
11397 ))
11398 })
11399 });
11400
11401 let is_unnecessary = diagnostic
11402 .tags
11403 .as_ref()
11404 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11405
11406 let underline = self
11407 .language_server_adapter_for_id(server_id)
11408 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11409
11410 if is_supporting {
11411 supporting_diagnostics.insert(
11412 (source, diagnostic.code.clone(), range),
11413 (diagnostic.severity, is_unnecessary),
11414 );
11415 } else {
11416 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11417 let is_disk_based =
11418 source.is_some_and(|source| disk_based_sources.contains(source));
11419
11420 sources_by_group_id.insert(group_id, source);
11421 primary_diagnostic_group_ids
11422 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11423
11424 diagnostics.push(DiagnosticEntry {
11425 range,
11426 diagnostic: Diagnostic {
11427 source: diagnostic.source.clone(),
11428 source_kind,
11429 code: diagnostic.code.clone(),
11430 code_description: diagnostic
11431 .code_description
11432 .as_ref()
11433 .and_then(|d| d.href.clone()),
11434 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11435 markdown: adapter.as_ref().and_then(|adapter| {
11436 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11437 }),
11438 message: diagnostic.message.trim().to_string(),
11439 group_id,
11440 is_primary: true,
11441 is_disk_based,
11442 is_unnecessary,
11443 underline,
11444 data: diagnostic.data.clone(),
11445 registration_id: registration_id.clone(),
11446 },
11447 });
11448 if let Some(infos) = &diagnostic.related_information {
11449 for info in infos {
11450 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11451 let range = range_from_lsp(info.location.range);
11452 diagnostics.push(DiagnosticEntry {
11453 range,
11454 diagnostic: Diagnostic {
11455 source: diagnostic.source.clone(),
11456 source_kind,
11457 code: diagnostic.code.clone(),
11458 code_description: diagnostic
11459 .code_description
11460 .as_ref()
11461 .and_then(|d| d.href.clone()),
11462 severity: DiagnosticSeverity::INFORMATION,
11463 markdown: adapter.as_ref().and_then(|adapter| {
11464 adapter.diagnostic_message_to_markdown(&info.message)
11465 }),
11466 message: info.message.trim().to_string(),
11467 group_id,
11468 is_primary: false,
11469 is_disk_based,
11470 is_unnecessary: false,
11471 underline,
11472 data: diagnostic.data.clone(),
11473 registration_id: registration_id.clone(),
11474 },
11475 });
11476 }
11477 }
11478 }
11479 }
11480 }
11481
11482 for entry in &mut diagnostics {
11483 let diagnostic = &mut entry.diagnostic;
11484 if !diagnostic.is_primary {
11485 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11486 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11487 source,
11488 diagnostic.code.clone(),
11489 entry.range.clone(),
11490 )) {
11491 if let Some(severity) = severity {
11492 diagnostic.severity = severity;
11493 }
11494 diagnostic.is_unnecessary = is_unnecessary;
11495 }
11496 }
11497 }
11498
11499 DocumentDiagnostics {
11500 diagnostics,
11501 document_abs_path,
11502 version: lsp_diagnostics.version,
11503 }
11504 }
11505
11506 fn insert_newly_running_language_server(
11507 &mut self,
11508 adapter: Arc<CachedLspAdapter>,
11509 language_server: Arc<LanguageServer>,
11510 server_id: LanguageServerId,
11511 key: LanguageServerSeed,
11512 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11513 cx: &mut Context<Self>,
11514 ) {
11515 let Some(local) = self.as_local_mut() else {
11516 return;
11517 };
11518 // If the language server for this key doesn't match the server id, don't store the
11519 // server. Which will cause it to be dropped, killing the process
11520 if local
11521 .language_server_ids
11522 .get(&key)
11523 .map(|state| state.id != server_id)
11524 .unwrap_or(false)
11525 {
11526 return;
11527 }
11528
11529 // Update language_servers collection with Running variant of LanguageServerState
11530 // indicating that the server is up and running and ready
11531 let workspace_folders = workspace_folders.lock().clone();
11532 language_server.set_workspace_folders(workspace_folders);
11533
11534 let workspace_diagnostics_refresh_tasks = language_server
11535 .capabilities()
11536 .diagnostic_provider
11537 .and_then(|provider| {
11538 local
11539 .language_server_dynamic_registrations
11540 .entry(server_id)
11541 .or_default()
11542 .diagnostics
11543 .entry(None)
11544 .or_insert(provider.clone());
11545 let workspace_refresher =
11546 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11547
11548 Some((None, workspace_refresher))
11549 })
11550 .into_iter()
11551 .collect();
11552 local.language_servers.insert(
11553 server_id,
11554 LanguageServerState::Running {
11555 workspace_diagnostics_refresh_tasks,
11556 adapter: adapter.clone(),
11557 server: language_server.clone(),
11558 simulate_disk_based_diagnostics_completion: None,
11559 },
11560 );
11561 local
11562 .languages
11563 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11564 if let Some(file_ops_caps) = language_server
11565 .capabilities()
11566 .workspace
11567 .as_ref()
11568 .and_then(|ws| ws.file_operations.as_ref())
11569 {
11570 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11571 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11572 if did_rename_caps.or(will_rename_caps).is_some() {
11573 let watcher = RenamePathsWatchedForServer::default()
11574 .with_did_rename_patterns(did_rename_caps)
11575 .with_will_rename_patterns(will_rename_caps);
11576 local
11577 .language_server_paths_watched_for_rename
11578 .insert(server_id, watcher);
11579 }
11580 }
11581
11582 self.language_server_statuses.insert(
11583 server_id,
11584 LanguageServerStatus {
11585 name: language_server.name(),
11586 server_version: language_server.version(),
11587 pending_work: Default::default(),
11588 has_pending_diagnostic_updates: false,
11589 progress_tokens: Default::default(),
11590 worktree: Some(key.worktree_id),
11591 binary: Some(language_server.binary().clone()),
11592 configuration: Some(language_server.configuration().clone()),
11593 workspace_folders: language_server.workspace_folders(),
11594 },
11595 );
11596
11597 cx.emit(LspStoreEvent::LanguageServerAdded(
11598 server_id,
11599 language_server.name(),
11600 Some(key.worktree_id),
11601 ));
11602
11603 let server_capabilities = language_server.capabilities();
11604 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11605 downstream_client
11606 .send(proto::StartLanguageServer {
11607 project_id: *project_id,
11608 server: Some(proto::LanguageServer {
11609 id: server_id.to_proto(),
11610 name: language_server.name().to_string(),
11611 worktree_id: Some(key.worktree_id.to_proto()),
11612 }),
11613 capabilities: serde_json::to_string(&server_capabilities)
11614 .expect("serializing server LSP capabilities"),
11615 })
11616 .log_err();
11617 }
11618 self.lsp_server_capabilities
11619 .insert(server_id, server_capabilities);
11620
11621 // Tell the language server about every open buffer in the worktree that matches the language.
11622 // Also check for buffers in worktrees that reused this server
11623 let mut worktrees_using_server = vec![key.worktree_id];
11624 if let Some(local) = self.as_local() {
11625 // Find all worktrees that have this server in their language server tree
11626 for (worktree_id, servers) in &local.lsp_tree.instances {
11627 if *worktree_id != key.worktree_id {
11628 for server_map in servers.roots.values() {
11629 if server_map
11630 .values()
11631 .any(|(node, _)| node.id() == Some(server_id))
11632 {
11633 worktrees_using_server.push(*worktree_id);
11634 }
11635 }
11636 }
11637 }
11638 }
11639
11640 let mut buffer_paths_registered = Vec::new();
11641 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11642 let mut lsp_adapters = HashMap::default();
11643 for buffer_handle in buffer_store.buffers() {
11644 let buffer = buffer_handle.read(cx);
11645 let file = match File::from_dyn(buffer.file()) {
11646 Some(file) => file,
11647 None => continue,
11648 };
11649 let language = match buffer.language() {
11650 Some(language) => language,
11651 None => continue,
11652 };
11653
11654 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11655 || !lsp_adapters
11656 .entry(language.name())
11657 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11658 .iter()
11659 .any(|a| a.name == key.name)
11660 {
11661 continue;
11662 }
11663 // didOpen
11664 let file = match file.as_local() {
11665 Some(file) => file,
11666 None => continue,
11667 };
11668
11669 let local = self.as_local_mut().unwrap();
11670
11671 let buffer_id = buffer.remote_id();
11672 if local.registered_buffers.contains_key(&buffer_id) {
11673 let versions = local
11674 .buffer_snapshots
11675 .entry(buffer_id)
11676 .or_default()
11677 .entry(server_id)
11678 .and_modify(|_| {
11679 assert!(
11680 false,
11681 "There should not be an existing snapshot for a newly inserted buffer"
11682 )
11683 })
11684 .or_insert_with(|| {
11685 vec![LspBufferSnapshot {
11686 version: 0,
11687 snapshot: buffer.text_snapshot(),
11688 }]
11689 });
11690
11691 let snapshot = versions.last().unwrap();
11692 let version = snapshot.version;
11693 let initial_snapshot = &snapshot.snapshot;
11694 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11695 language_server.register_buffer(
11696 uri,
11697 adapter.language_id(&language.name()),
11698 version,
11699 initial_snapshot.text(),
11700 );
11701 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11702 local
11703 .buffers_opened_in_servers
11704 .entry(buffer_id)
11705 .or_default()
11706 .insert(server_id);
11707 }
11708 buffer_handle.update(cx, |buffer, cx| {
11709 buffer.set_completion_triggers(
11710 server_id,
11711 language_server
11712 .capabilities()
11713 .completion_provider
11714 .as_ref()
11715 .and_then(|provider| {
11716 provider
11717 .trigger_characters
11718 .as_ref()
11719 .map(|characters| characters.iter().cloned().collect())
11720 })
11721 .unwrap_or_default(),
11722 cx,
11723 )
11724 });
11725 }
11726 });
11727
11728 for (buffer_id, abs_path) in buffer_paths_registered {
11729 cx.emit(LspStoreEvent::LanguageServerUpdate {
11730 language_server_id: server_id,
11731 name: Some(adapter.name()),
11732 message: proto::update_language_server::Variant::RegisteredForBuffer(
11733 proto::RegisteredForBuffer {
11734 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11735 buffer_id: buffer_id.to_proto(),
11736 },
11737 ),
11738 });
11739 }
11740
11741 cx.notify();
11742 }
11743
11744 pub fn language_servers_running_disk_based_diagnostics(
11745 &self,
11746 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11747 self.language_server_statuses
11748 .iter()
11749 .filter_map(|(id, status)| {
11750 if status.has_pending_diagnostic_updates {
11751 Some(*id)
11752 } else {
11753 None
11754 }
11755 })
11756 }
11757
11758 pub(crate) fn cancel_language_server_work_for_buffers(
11759 &mut self,
11760 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11761 cx: &mut Context<Self>,
11762 ) {
11763 if let Some((client, project_id)) = self.upstream_client() {
11764 let request = client.request(proto::CancelLanguageServerWork {
11765 project_id,
11766 work: Some(proto::cancel_language_server_work::Work::Buffers(
11767 proto::cancel_language_server_work::Buffers {
11768 buffer_ids: buffers
11769 .into_iter()
11770 .map(|b| b.read(cx).remote_id().to_proto())
11771 .collect(),
11772 },
11773 )),
11774 });
11775 cx.background_spawn(request).detach_and_log_err(cx);
11776 } else if let Some(local) = self.as_local() {
11777 let servers = buffers
11778 .into_iter()
11779 .flat_map(|buffer| {
11780 buffer.update(cx, |buffer, cx| {
11781 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11782 })
11783 })
11784 .collect::<HashSet<_>>();
11785 for server_id in servers {
11786 self.cancel_language_server_work(server_id, None, cx);
11787 }
11788 }
11789 }
11790
11791 pub(crate) fn cancel_language_server_work(
11792 &mut self,
11793 server_id: LanguageServerId,
11794 token_to_cancel: Option<ProgressToken>,
11795 cx: &mut Context<Self>,
11796 ) {
11797 if let Some(local) = self.as_local() {
11798 let status = self.language_server_statuses.get(&server_id);
11799 let server = local.language_servers.get(&server_id);
11800 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11801 {
11802 for (token, progress) in &status.pending_work {
11803 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11804 && token != token_to_cancel
11805 {
11806 continue;
11807 }
11808 if progress.is_cancellable {
11809 server
11810 .notify::<lsp::notification::WorkDoneProgressCancel>(
11811 WorkDoneProgressCancelParams {
11812 token: token.to_lsp(),
11813 },
11814 )
11815 .ok();
11816 }
11817 }
11818 }
11819 } else if let Some((client, project_id)) = self.upstream_client() {
11820 let request = client.request(proto::CancelLanguageServerWork {
11821 project_id,
11822 work: Some(
11823 proto::cancel_language_server_work::Work::LanguageServerWork(
11824 proto::cancel_language_server_work::LanguageServerWork {
11825 language_server_id: server_id.to_proto(),
11826 token: token_to_cancel.map(|token| token.to_proto()),
11827 },
11828 ),
11829 ),
11830 });
11831 cx.background_spawn(request).detach_and_log_err(cx);
11832 }
11833 }
11834
11835 fn register_supplementary_language_server(
11836 &mut self,
11837 id: LanguageServerId,
11838 name: LanguageServerName,
11839 server: Arc<LanguageServer>,
11840 cx: &mut Context<Self>,
11841 ) {
11842 if let Some(local) = self.as_local_mut() {
11843 local
11844 .supplementary_language_servers
11845 .insert(id, (name.clone(), server));
11846 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11847 }
11848 }
11849
11850 fn unregister_supplementary_language_server(
11851 &mut self,
11852 id: LanguageServerId,
11853 cx: &mut Context<Self>,
11854 ) {
11855 if let Some(local) = self.as_local_mut() {
11856 local.supplementary_language_servers.remove(&id);
11857 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11858 }
11859 }
11860
11861 pub(crate) fn supplementary_language_servers(
11862 &self,
11863 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11864 self.as_local().into_iter().flat_map(|local| {
11865 local
11866 .supplementary_language_servers
11867 .iter()
11868 .map(|(id, (name, _))| (*id, name.clone()))
11869 })
11870 }
11871
11872 pub fn language_server_adapter_for_id(
11873 &self,
11874 id: LanguageServerId,
11875 ) -> Option<Arc<CachedLspAdapter>> {
11876 self.as_local()
11877 .and_then(|local| local.language_servers.get(&id))
11878 .and_then(|language_server_state| match language_server_state {
11879 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11880 _ => None,
11881 })
11882 }
11883
11884 pub(super) fn update_local_worktree_language_servers(
11885 &mut self,
11886 worktree_handle: &Entity<Worktree>,
11887 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11888 cx: &mut Context<Self>,
11889 ) {
11890 if changes.is_empty() {
11891 return;
11892 }
11893
11894 let Some(local) = self.as_local() else { return };
11895
11896 local.prettier_store.update(cx, |prettier_store, cx| {
11897 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11898 });
11899
11900 let worktree_id = worktree_handle.read(cx).id();
11901 let mut language_server_ids = local
11902 .language_server_ids
11903 .iter()
11904 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11905 .collect::<Vec<_>>();
11906 language_server_ids.sort();
11907 language_server_ids.dedup();
11908
11909 // let abs_path = worktree_handle.read(cx).abs_path();
11910 for server_id in &language_server_ids {
11911 if let Some(LanguageServerState::Running { server, .. }) =
11912 local.language_servers.get(server_id)
11913 && let Some(watched_paths) = local
11914 .language_server_watched_paths
11915 .get(server_id)
11916 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11917 {
11918 let params = lsp::DidChangeWatchedFilesParams {
11919 changes: changes
11920 .iter()
11921 .filter_map(|(path, _, change)| {
11922 if !watched_paths.is_match(path.as_std_path()) {
11923 return None;
11924 }
11925 let typ = match change {
11926 PathChange::Loaded => return None,
11927 PathChange::Added => lsp::FileChangeType::CREATED,
11928 PathChange::Removed => lsp::FileChangeType::DELETED,
11929 PathChange::Updated => lsp::FileChangeType::CHANGED,
11930 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11931 };
11932 let uri = lsp::Uri::from_file_path(
11933 worktree_handle.read(cx).absolutize(&path),
11934 )
11935 .ok()?;
11936 Some(lsp::FileEvent { uri, typ })
11937 })
11938 .collect(),
11939 };
11940 if !params.changes.is_empty() {
11941 server
11942 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11943 .ok();
11944 }
11945 }
11946 }
11947 for (path, _, _) in changes {
11948 if let Some(file_name) = path.file_name()
11949 && local.watched_manifest_filenames.contains(file_name)
11950 {
11951 self.request_workspace_config_refresh();
11952 break;
11953 }
11954 }
11955 }
11956
11957 pub fn wait_for_remote_buffer(
11958 &mut self,
11959 id: BufferId,
11960 cx: &mut Context<Self>,
11961 ) -> Task<Result<Entity<Buffer>>> {
11962 self.buffer_store.update(cx, |buffer_store, cx| {
11963 buffer_store.wait_for_remote_buffer(id, cx)
11964 })
11965 }
11966
11967 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11968 let mut result = proto::Symbol {
11969 language_server_name: symbol.language_server_name.0.to_string(),
11970 source_worktree_id: symbol.source_worktree_id.to_proto(),
11971 language_server_id: symbol.source_language_server_id.to_proto(),
11972 name: symbol.name.clone(),
11973 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11974 start: Some(proto::PointUtf16 {
11975 row: symbol.range.start.0.row,
11976 column: symbol.range.start.0.column,
11977 }),
11978 end: Some(proto::PointUtf16 {
11979 row: symbol.range.end.0.row,
11980 column: symbol.range.end.0.column,
11981 }),
11982 worktree_id: Default::default(),
11983 path: Default::default(),
11984 signature: Default::default(),
11985 };
11986 match &symbol.path {
11987 SymbolLocation::InProject(path) => {
11988 result.worktree_id = path.worktree_id.to_proto();
11989 result.path = path.path.to_proto();
11990 }
11991 SymbolLocation::OutsideProject {
11992 abs_path,
11993 signature,
11994 } => {
11995 result.path = abs_path.to_string_lossy().into_owned();
11996 result.signature = signature.to_vec();
11997 }
11998 }
11999 result
12000 }
12001
12002 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
12003 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
12004 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
12005 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
12006
12007 let path = if serialized_symbol.signature.is_empty() {
12008 SymbolLocation::InProject(ProjectPath {
12009 worktree_id,
12010 path: RelPath::from_proto(&serialized_symbol.path)
12011 .context("invalid symbol path")?,
12012 })
12013 } else {
12014 SymbolLocation::OutsideProject {
12015 abs_path: Path::new(&serialized_symbol.path).into(),
12016 signature: serialized_symbol
12017 .signature
12018 .try_into()
12019 .map_err(|_| anyhow!("invalid signature"))?,
12020 }
12021 };
12022
12023 let start = serialized_symbol.start.context("invalid start")?;
12024 let end = serialized_symbol.end.context("invalid end")?;
12025 Ok(CoreSymbol {
12026 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
12027 source_worktree_id,
12028 source_language_server_id: LanguageServerId::from_proto(
12029 serialized_symbol.language_server_id,
12030 ),
12031 path,
12032 name: serialized_symbol.name,
12033 range: Unclipped(PointUtf16::new(start.row, start.column))
12034 ..Unclipped(PointUtf16::new(end.row, end.column)),
12035 kind,
12036 })
12037 }
12038
12039 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12040 let mut serialized_completion = proto::Completion {
12041 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12042 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12043 new_text: completion.new_text.clone(),
12044 ..proto::Completion::default()
12045 };
12046 match &completion.source {
12047 CompletionSource::Lsp {
12048 insert_range,
12049 server_id,
12050 lsp_completion,
12051 lsp_defaults,
12052 resolved,
12053 } => {
12054 let (old_insert_start, old_insert_end) = insert_range
12055 .as_ref()
12056 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12057 .unzip();
12058
12059 serialized_completion.old_insert_start = old_insert_start;
12060 serialized_completion.old_insert_end = old_insert_end;
12061 serialized_completion.source = proto::completion::Source::Lsp as i32;
12062 serialized_completion.server_id = server_id.0 as u64;
12063 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12064 serialized_completion.lsp_defaults = lsp_defaults
12065 .as_deref()
12066 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12067 serialized_completion.resolved = *resolved;
12068 }
12069 CompletionSource::BufferWord {
12070 word_range,
12071 resolved,
12072 } => {
12073 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12074 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12075 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12076 serialized_completion.resolved = *resolved;
12077 }
12078 CompletionSource::Custom => {
12079 serialized_completion.source = proto::completion::Source::Custom as i32;
12080 serialized_completion.resolved = true;
12081 }
12082 CompletionSource::Dap { sort_text } => {
12083 serialized_completion.source = proto::completion::Source::Dap as i32;
12084 serialized_completion.sort_text = Some(sort_text.clone());
12085 }
12086 }
12087
12088 serialized_completion
12089 }
12090
12091 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12092 let old_replace_start = completion
12093 .old_replace_start
12094 .and_then(deserialize_anchor)
12095 .context("invalid old start")?;
12096 let old_replace_end = completion
12097 .old_replace_end
12098 .and_then(deserialize_anchor)
12099 .context("invalid old end")?;
12100 let insert_range = {
12101 match completion.old_insert_start.zip(completion.old_insert_end) {
12102 Some((start, end)) => {
12103 let start = deserialize_anchor(start).context("invalid insert old start")?;
12104 let end = deserialize_anchor(end).context("invalid insert old end")?;
12105 Some(start..end)
12106 }
12107 None => None,
12108 }
12109 };
12110 Ok(CoreCompletion {
12111 replace_range: old_replace_start..old_replace_end,
12112 new_text: completion.new_text,
12113 source: match proto::completion::Source::from_i32(completion.source) {
12114 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12115 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12116 insert_range,
12117 server_id: LanguageServerId::from_proto(completion.server_id),
12118 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12119 lsp_defaults: completion
12120 .lsp_defaults
12121 .as_deref()
12122 .map(serde_json::from_slice)
12123 .transpose()?,
12124 resolved: completion.resolved,
12125 },
12126 Some(proto::completion::Source::BufferWord) => {
12127 let word_range = completion
12128 .buffer_word_start
12129 .and_then(deserialize_anchor)
12130 .context("invalid buffer word start")?
12131 ..completion
12132 .buffer_word_end
12133 .and_then(deserialize_anchor)
12134 .context("invalid buffer word end")?;
12135 CompletionSource::BufferWord {
12136 word_range,
12137 resolved: completion.resolved,
12138 }
12139 }
12140 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12141 sort_text: completion
12142 .sort_text
12143 .context("expected sort text to exist")?,
12144 },
12145 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12146 },
12147 })
12148 }
12149
12150 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12151 let (kind, lsp_action) = match &action.lsp_action {
12152 LspAction::Action(code_action) => (
12153 proto::code_action::Kind::Action as i32,
12154 serde_json::to_vec(code_action).unwrap(),
12155 ),
12156 LspAction::Command(command) => (
12157 proto::code_action::Kind::Command as i32,
12158 serde_json::to_vec(command).unwrap(),
12159 ),
12160 LspAction::CodeLens(code_lens) => (
12161 proto::code_action::Kind::CodeLens as i32,
12162 serde_json::to_vec(code_lens).unwrap(),
12163 ),
12164 };
12165
12166 proto::CodeAction {
12167 server_id: action.server_id.0 as u64,
12168 start: Some(serialize_anchor(&action.range.start)),
12169 end: Some(serialize_anchor(&action.range.end)),
12170 lsp_action,
12171 kind,
12172 resolved: action.resolved,
12173 }
12174 }
12175
12176 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12177 let start = action
12178 .start
12179 .and_then(deserialize_anchor)
12180 .context("invalid start")?;
12181 let end = action
12182 .end
12183 .and_then(deserialize_anchor)
12184 .context("invalid end")?;
12185 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12186 Some(proto::code_action::Kind::Action) => {
12187 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12188 }
12189 Some(proto::code_action::Kind::Command) => {
12190 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12191 }
12192 Some(proto::code_action::Kind::CodeLens) => {
12193 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12194 }
12195 None => anyhow::bail!("Unknown action kind {}", action.kind),
12196 };
12197 Ok(CodeAction {
12198 server_id: LanguageServerId(action.server_id as usize),
12199 range: start..end,
12200 resolved: action.resolved,
12201 lsp_action,
12202 })
12203 }
12204
12205 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12206 match &formatting_result {
12207 Ok(_) => self.last_formatting_failure = None,
12208 Err(error) => {
12209 let error_string = format!("{error:#}");
12210 log::error!("Formatting failed: {error_string}");
12211 self.last_formatting_failure
12212 .replace(error_string.lines().join(" "));
12213 }
12214 }
12215 }
12216
12217 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12218 self.lsp_server_capabilities.remove(&for_server);
12219 for lsp_data in self.lsp_data.values_mut() {
12220 lsp_data.remove_server_data(for_server);
12221 }
12222 if let Some(local) = self.as_local_mut() {
12223 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12224 local
12225 .workspace_pull_diagnostics_result_ids
12226 .remove(&for_server);
12227 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12228 buffer_servers.remove(&for_server);
12229 }
12230 }
12231 }
12232
12233 pub fn result_id_for_buffer_pull(
12234 &self,
12235 server_id: LanguageServerId,
12236 buffer_id: BufferId,
12237 registration_id: &Option<SharedString>,
12238 cx: &App,
12239 ) -> Option<SharedString> {
12240 let abs_path = self
12241 .buffer_store
12242 .read(cx)
12243 .get(buffer_id)
12244 .and_then(|b| File::from_dyn(b.read(cx).file()))
12245 .map(|f| f.abs_path(cx))?;
12246 self.as_local()?
12247 .buffer_pull_diagnostics_result_ids
12248 .get(&server_id)?
12249 .get(registration_id)?
12250 .get(&abs_path)?
12251 .clone()
12252 }
12253
12254 /// Gets all result_ids for a workspace diagnostics pull request.
12255 /// 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.
12256 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12257 pub fn result_ids_for_workspace_refresh(
12258 &self,
12259 server_id: LanguageServerId,
12260 registration_id: &Option<SharedString>,
12261 ) -> HashMap<PathBuf, SharedString> {
12262 let Some(local) = self.as_local() else {
12263 return HashMap::default();
12264 };
12265 local
12266 .workspace_pull_diagnostics_result_ids
12267 .get(&server_id)
12268 .into_iter()
12269 .filter_map(|diagnostics| diagnostics.get(registration_id))
12270 .flatten()
12271 .filter_map(|(abs_path, result_id)| {
12272 let result_id = local
12273 .buffer_pull_diagnostics_result_ids
12274 .get(&server_id)
12275 .and_then(|buffer_ids_result_ids| {
12276 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12277 })
12278 .cloned()
12279 .flatten()
12280 .or_else(|| result_id.clone())?;
12281 Some((abs_path.clone(), result_id))
12282 })
12283 .collect()
12284 }
12285
12286 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12287 if let Some(LanguageServerState::Running {
12288 workspace_diagnostics_refresh_tasks,
12289 ..
12290 }) = self
12291 .as_local_mut()
12292 .and_then(|local| local.language_servers.get_mut(&server_id))
12293 {
12294 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12295 diagnostics.refresh_tx.try_send(()).ok();
12296 }
12297 }
12298 }
12299
12300 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12301 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12302 /// which requires refreshing both workspace and document diagnostics.
12303 pub fn pull_document_diagnostics_for_server(
12304 &mut self,
12305 server_id: LanguageServerId,
12306 source_buffer_id: Option<BufferId>,
12307 cx: &mut Context<Self>,
12308 ) -> Shared<Task<()>> {
12309 let Some(local) = self.as_local_mut() else {
12310 return Task::ready(()).shared();
12311 };
12312 let mut buffers_to_refresh = HashSet::default();
12313 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12314 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12315 buffers_to_refresh.insert(*buffer_id);
12316 }
12317 }
12318
12319 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12320 }
12321
12322 pub fn pull_document_diagnostics_for_buffer_edit(
12323 &mut self,
12324 buffer_id: BufferId,
12325 cx: &mut Context<Self>,
12326 ) {
12327 let Some(local) = self.as_local_mut() else {
12328 return;
12329 };
12330 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12331 else {
12332 return;
12333 };
12334 for server_id in languages_servers {
12335 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12336 }
12337 }
12338
12339 fn apply_workspace_diagnostic_report(
12340 &mut self,
12341 server_id: LanguageServerId,
12342 report: lsp::WorkspaceDiagnosticReportResult,
12343 registration_id: Option<SharedString>,
12344 cx: &mut Context<Self>,
12345 ) {
12346 let mut workspace_diagnostics =
12347 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12348 report,
12349 server_id,
12350 registration_id,
12351 );
12352 workspace_diagnostics.retain(|d| match &d.diagnostics {
12353 LspPullDiagnostics::Response {
12354 server_id,
12355 registration_id,
12356 ..
12357 } => self.diagnostic_registration_exists(*server_id, registration_id),
12358 LspPullDiagnostics::Default => false,
12359 });
12360 let mut unchanged_buffers = HashMap::default();
12361 let workspace_diagnostics_updates = workspace_diagnostics
12362 .into_iter()
12363 .filter_map(
12364 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12365 LspPullDiagnostics::Response {
12366 server_id,
12367 uri,
12368 diagnostics,
12369 registration_id,
12370 } => Some((
12371 server_id,
12372 uri,
12373 diagnostics,
12374 workspace_diagnostics.version,
12375 registration_id,
12376 )),
12377 LspPullDiagnostics::Default => None,
12378 },
12379 )
12380 .fold(
12381 HashMap::default(),
12382 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12383 let (result_id, diagnostics) = match diagnostics {
12384 PulledDiagnostics::Unchanged { result_id } => {
12385 unchanged_buffers
12386 .entry(new_registration_id.clone())
12387 .or_insert_with(HashSet::default)
12388 .insert(uri.clone());
12389 (Some(result_id), Vec::new())
12390 }
12391 PulledDiagnostics::Changed {
12392 result_id,
12393 diagnostics,
12394 } => (result_id, diagnostics),
12395 };
12396 let disk_based_sources = Cow::Owned(
12397 self.language_server_adapter_for_id(server_id)
12398 .as_ref()
12399 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12400 .unwrap_or(&[])
12401 .to_vec(),
12402 );
12403
12404 let Some(abs_path) = uri.to_file_path().ok() else {
12405 return acc;
12406 };
12407 let Some((worktree, relative_path)) =
12408 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12409 else {
12410 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12411 return acc;
12412 };
12413 let worktree_id = worktree.read(cx).id();
12414 let project_path = ProjectPath {
12415 worktree_id,
12416 path: relative_path,
12417 };
12418 if let Some(local_lsp_store) = self.as_local_mut() {
12419 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12420 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12421 }
12422 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12423 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12424 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12425 acc.entry(server_id)
12426 .or_insert_with(HashMap::default)
12427 .entry(new_registration_id.clone())
12428 .or_insert_with(Vec::new)
12429 .push(DocumentDiagnosticsUpdate {
12430 server_id,
12431 diagnostics: lsp::PublishDiagnosticsParams {
12432 uri,
12433 diagnostics,
12434 version,
12435 },
12436 result_id,
12437 disk_based_sources,
12438 registration_id: new_registration_id,
12439 });
12440 }
12441 acc
12442 },
12443 );
12444
12445 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12446 for (registration_id, diagnostic_updates) in diagnostic_updates {
12447 self.merge_lsp_diagnostics(
12448 DiagnosticSourceKind::Pulled,
12449 diagnostic_updates,
12450 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12451 DiagnosticSourceKind::Pulled => {
12452 old_diagnostic.registration_id != registration_id
12453 || unchanged_buffers
12454 .get(&old_diagnostic.registration_id)
12455 .is_some_and(|unchanged_buffers| {
12456 unchanged_buffers.contains(&document_uri)
12457 })
12458 }
12459 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12460 },
12461 cx,
12462 )
12463 .log_err();
12464 }
12465 }
12466 }
12467
12468 fn register_server_capabilities(
12469 &mut self,
12470 server_id: LanguageServerId,
12471 params: lsp::RegistrationParams,
12472 cx: &mut Context<Self>,
12473 ) -> anyhow::Result<()> {
12474 let server = self
12475 .language_server_for_id(server_id)
12476 .with_context(|| format!("no server {server_id} found"))?;
12477 for reg in params.registrations {
12478 match reg.method.as_str() {
12479 "workspace/didChangeWatchedFiles" => {
12480 if let Some(options) = reg.register_options {
12481 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12482 let caps = serde_json::from_value(options)?;
12483 local_lsp_store
12484 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12485 true
12486 } else {
12487 false
12488 };
12489 if notify {
12490 notify_server_capabilities_updated(&server, cx);
12491 }
12492 }
12493 }
12494 "workspace/didChangeConfiguration" => {
12495 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12496 }
12497 "workspace/didChangeWorkspaceFolders" => {
12498 // In this case register options is an empty object, we can ignore it
12499 let caps = lsp::WorkspaceFoldersServerCapabilities {
12500 supported: Some(true),
12501 change_notifications: Some(OneOf::Right(reg.id)),
12502 };
12503 server.update_capabilities(|capabilities| {
12504 capabilities
12505 .workspace
12506 .get_or_insert_default()
12507 .workspace_folders = Some(caps);
12508 });
12509 notify_server_capabilities_updated(&server, cx);
12510 }
12511 "workspace/symbol" => {
12512 let options = parse_register_capabilities(reg)?;
12513 server.update_capabilities(|capabilities| {
12514 capabilities.workspace_symbol_provider = Some(options);
12515 });
12516 notify_server_capabilities_updated(&server, cx);
12517 }
12518 "workspace/fileOperations" => {
12519 if let Some(options) = reg.register_options {
12520 let caps = serde_json::from_value(options)?;
12521 server.update_capabilities(|capabilities| {
12522 capabilities
12523 .workspace
12524 .get_or_insert_default()
12525 .file_operations = Some(caps);
12526 });
12527 notify_server_capabilities_updated(&server, cx);
12528 }
12529 }
12530 "workspace/executeCommand" => {
12531 if let Some(options) = reg.register_options {
12532 let options = serde_json::from_value(options)?;
12533 server.update_capabilities(|capabilities| {
12534 capabilities.execute_command_provider = Some(options);
12535 });
12536 notify_server_capabilities_updated(&server, cx);
12537 }
12538 }
12539 "textDocument/rangeFormatting" => {
12540 let options = parse_register_capabilities(reg)?;
12541 server.update_capabilities(|capabilities| {
12542 capabilities.document_range_formatting_provider = Some(options);
12543 });
12544 notify_server_capabilities_updated(&server, cx);
12545 }
12546 "textDocument/onTypeFormatting" => {
12547 if let Some(options) = reg
12548 .register_options
12549 .map(serde_json::from_value)
12550 .transpose()?
12551 {
12552 server.update_capabilities(|capabilities| {
12553 capabilities.document_on_type_formatting_provider = Some(options);
12554 });
12555 notify_server_capabilities_updated(&server, cx);
12556 }
12557 }
12558 "textDocument/formatting" => {
12559 let options = parse_register_capabilities(reg)?;
12560 server.update_capabilities(|capabilities| {
12561 capabilities.document_formatting_provider = Some(options);
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 "textDocument/rename" => {
12566 let options = parse_register_capabilities(reg)?;
12567 server.update_capabilities(|capabilities| {
12568 capabilities.rename_provider = Some(options);
12569 });
12570 notify_server_capabilities_updated(&server, cx);
12571 }
12572 "textDocument/inlayHint" => {
12573 let options = parse_register_capabilities(reg)?;
12574 server.update_capabilities(|capabilities| {
12575 capabilities.inlay_hint_provider = Some(options);
12576 });
12577 notify_server_capabilities_updated(&server, cx);
12578 }
12579 "textDocument/documentSymbol" => {
12580 let options = parse_register_capabilities(reg)?;
12581 server.update_capabilities(|capabilities| {
12582 capabilities.document_symbol_provider = Some(options);
12583 });
12584 notify_server_capabilities_updated(&server, cx);
12585 }
12586 "textDocument/codeAction" => {
12587 let options = parse_register_capabilities(reg)?;
12588 let provider = match options {
12589 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12590 OneOf::Right(caps) => caps,
12591 };
12592 server.update_capabilities(|capabilities| {
12593 capabilities.code_action_provider = Some(provider);
12594 });
12595 notify_server_capabilities_updated(&server, cx);
12596 }
12597 "textDocument/definition" => {
12598 let options = parse_register_capabilities(reg)?;
12599 server.update_capabilities(|capabilities| {
12600 capabilities.definition_provider = Some(options);
12601 });
12602 notify_server_capabilities_updated(&server, cx);
12603 }
12604 "textDocument/completion" => {
12605 if let Some(caps) = reg
12606 .register_options
12607 .map(serde_json::from_value::<CompletionOptions>)
12608 .transpose()?
12609 {
12610 server.update_capabilities(|capabilities| {
12611 capabilities.completion_provider = Some(caps.clone());
12612 });
12613
12614 if let Some(local) = self.as_local() {
12615 let mut buffers_with_language_server = Vec::new();
12616 for handle in self.buffer_store.read(cx).buffers() {
12617 let buffer_id = handle.read(cx).remote_id();
12618 if local
12619 .buffers_opened_in_servers
12620 .get(&buffer_id)
12621 .filter(|s| s.contains(&server_id))
12622 .is_some()
12623 {
12624 buffers_with_language_server.push(handle);
12625 }
12626 }
12627 let triggers = caps
12628 .trigger_characters
12629 .unwrap_or_default()
12630 .into_iter()
12631 .collect::<BTreeSet<_>>();
12632 for handle in buffers_with_language_server {
12633 let triggers = triggers.clone();
12634 let _ = handle.update(cx, move |buffer, cx| {
12635 buffer.set_completion_triggers(server_id, triggers, cx);
12636 });
12637 }
12638 }
12639 notify_server_capabilities_updated(&server, cx);
12640 }
12641 }
12642 "textDocument/hover" => {
12643 let options = parse_register_capabilities(reg)?;
12644 let provider = match options {
12645 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12646 OneOf::Right(caps) => caps,
12647 };
12648 server.update_capabilities(|capabilities| {
12649 capabilities.hover_provider = Some(provider);
12650 });
12651 notify_server_capabilities_updated(&server, cx);
12652 }
12653 "textDocument/signatureHelp" => {
12654 if let Some(caps) = reg
12655 .register_options
12656 .map(serde_json::from_value)
12657 .transpose()?
12658 {
12659 server.update_capabilities(|capabilities| {
12660 capabilities.signature_help_provider = Some(caps);
12661 });
12662 notify_server_capabilities_updated(&server, cx);
12663 }
12664 }
12665 "textDocument/didChange" => {
12666 if let Some(sync_kind) = reg
12667 .register_options
12668 .and_then(|opts| opts.get("syncKind").cloned())
12669 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12670 .transpose()?
12671 {
12672 server.update_capabilities(|capabilities| {
12673 let mut sync_options =
12674 Self::take_text_document_sync_options(capabilities);
12675 sync_options.change = Some(sync_kind);
12676 capabilities.text_document_sync =
12677 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12678 });
12679 notify_server_capabilities_updated(&server, cx);
12680 }
12681 }
12682 "textDocument/didSave" => {
12683 if let Some(include_text) = reg
12684 .register_options
12685 .map(|opts| {
12686 let transpose = opts
12687 .get("includeText")
12688 .cloned()
12689 .map(serde_json::from_value::<Option<bool>>)
12690 .transpose();
12691 match transpose {
12692 Ok(value) => Ok(value.flatten()),
12693 Err(e) => Err(e),
12694 }
12695 })
12696 .transpose()?
12697 {
12698 server.update_capabilities(|capabilities| {
12699 let mut sync_options =
12700 Self::take_text_document_sync_options(capabilities);
12701 sync_options.save =
12702 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12703 include_text,
12704 }));
12705 capabilities.text_document_sync =
12706 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12707 });
12708 notify_server_capabilities_updated(&server, cx);
12709 }
12710 }
12711 "textDocument/codeLens" => {
12712 if let Some(caps) = reg
12713 .register_options
12714 .map(serde_json::from_value)
12715 .transpose()?
12716 {
12717 server.update_capabilities(|capabilities| {
12718 capabilities.code_lens_provider = Some(caps);
12719 });
12720 notify_server_capabilities_updated(&server, cx);
12721 }
12722 }
12723 "textDocument/diagnostic" => {
12724 if let Some(caps) = reg
12725 .register_options
12726 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12727 .transpose()?
12728 {
12729 let local = self
12730 .as_local_mut()
12731 .context("Expected LSP Store to be local")?;
12732 let state = local
12733 .language_servers
12734 .get_mut(&server_id)
12735 .context("Could not obtain Language Servers state")?;
12736 local
12737 .language_server_dynamic_registrations
12738 .entry(server_id)
12739 .or_default()
12740 .diagnostics
12741 .insert(Some(reg.id.clone()), caps.clone());
12742
12743 let supports_workspace_diagnostics =
12744 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12745 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12746 diagnostic_options.workspace_diagnostics
12747 }
12748 DiagnosticServerCapabilities::RegistrationOptions(
12749 diagnostic_registration_options,
12750 ) => {
12751 diagnostic_registration_options
12752 .diagnostic_options
12753 .workspace_diagnostics
12754 }
12755 };
12756
12757 if supports_workspace_diagnostics(&caps) {
12758 if let LanguageServerState::Running {
12759 workspace_diagnostics_refresh_tasks,
12760 ..
12761 } = state
12762 && let Some(task) = lsp_workspace_diagnostics_refresh(
12763 Some(reg.id.clone()),
12764 caps.clone(),
12765 server.clone(),
12766 cx,
12767 )
12768 {
12769 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12770 }
12771 }
12772
12773 server.update_capabilities(|capabilities| {
12774 capabilities.diagnostic_provider = Some(caps);
12775 });
12776
12777 notify_server_capabilities_updated(&server, cx);
12778
12779 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12780 }
12781 }
12782 "textDocument/documentColor" => {
12783 let options = parse_register_capabilities(reg)?;
12784 let provider = match options {
12785 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12786 OneOf::Right(caps) => caps,
12787 };
12788 server.update_capabilities(|capabilities| {
12789 capabilities.color_provider = Some(provider);
12790 });
12791 notify_server_capabilities_updated(&server, cx);
12792 }
12793 _ => log::warn!("unhandled capability registration: {reg:?}"),
12794 }
12795 }
12796
12797 Ok(())
12798 }
12799
12800 fn unregister_server_capabilities(
12801 &mut self,
12802 server_id: LanguageServerId,
12803 params: lsp::UnregistrationParams,
12804 cx: &mut Context<Self>,
12805 ) -> anyhow::Result<()> {
12806 let server = self
12807 .language_server_for_id(server_id)
12808 .with_context(|| format!("no server {server_id} found"))?;
12809 for unreg in params.unregisterations.iter() {
12810 match unreg.method.as_str() {
12811 "workspace/didChangeWatchedFiles" => {
12812 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12813 local_lsp_store
12814 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12815 true
12816 } else {
12817 false
12818 };
12819 if notify {
12820 notify_server_capabilities_updated(&server, cx);
12821 }
12822 }
12823 "workspace/didChangeConfiguration" => {
12824 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12825 }
12826 "workspace/didChangeWorkspaceFolders" => {
12827 server.update_capabilities(|capabilities| {
12828 capabilities
12829 .workspace
12830 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12831 workspace_folders: None,
12832 file_operations: None,
12833 })
12834 .workspace_folders = None;
12835 });
12836 notify_server_capabilities_updated(&server, cx);
12837 }
12838 "workspace/symbol" => {
12839 server.update_capabilities(|capabilities| {
12840 capabilities.workspace_symbol_provider = None
12841 });
12842 notify_server_capabilities_updated(&server, cx);
12843 }
12844 "workspace/fileOperations" => {
12845 server.update_capabilities(|capabilities| {
12846 capabilities
12847 .workspace
12848 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12849 workspace_folders: None,
12850 file_operations: None,
12851 })
12852 .file_operations = None;
12853 });
12854 notify_server_capabilities_updated(&server, cx);
12855 }
12856 "workspace/executeCommand" => {
12857 server.update_capabilities(|capabilities| {
12858 capabilities.execute_command_provider = None;
12859 });
12860 notify_server_capabilities_updated(&server, cx);
12861 }
12862 "textDocument/rangeFormatting" => {
12863 server.update_capabilities(|capabilities| {
12864 capabilities.document_range_formatting_provider = None
12865 });
12866 notify_server_capabilities_updated(&server, cx);
12867 }
12868 "textDocument/onTypeFormatting" => {
12869 server.update_capabilities(|capabilities| {
12870 capabilities.document_on_type_formatting_provider = None;
12871 });
12872 notify_server_capabilities_updated(&server, cx);
12873 }
12874 "textDocument/formatting" => {
12875 server.update_capabilities(|capabilities| {
12876 capabilities.document_formatting_provider = None;
12877 });
12878 notify_server_capabilities_updated(&server, cx);
12879 }
12880 "textDocument/rename" => {
12881 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12882 notify_server_capabilities_updated(&server, cx);
12883 }
12884 "textDocument/codeAction" => {
12885 server.update_capabilities(|capabilities| {
12886 capabilities.code_action_provider = None;
12887 });
12888 notify_server_capabilities_updated(&server, cx);
12889 }
12890 "textDocument/definition" => {
12891 server.update_capabilities(|capabilities| {
12892 capabilities.definition_provider = None;
12893 });
12894 notify_server_capabilities_updated(&server, cx);
12895 }
12896 "textDocument/completion" => {
12897 server.update_capabilities(|capabilities| {
12898 capabilities.completion_provider = None;
12899 });
12900 notify_server_capabilities_updated(&server, cx);
12901 }
12902 "textDocument/hover" => {
12903 server.update_capabilities(|capabilities| {
12904 capabilities.hover_provider = None;
12905 });
12906 notify_server_capabilities_updated(&server, cx);
12907 }
12908 "textDocument/signatureHelp" => {
12909 server.update_capabilities(|capabilities| {
12910 capabilities.signature_help_provider = None;
12911 });
12912 notify_server_capabilities_updated(&server, cx);
12913 }
12914 "textDocument/didChange" => {
12915 server.update_capabilities(|capabilities| {
12916 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12917 sync_options.change = None;
12918 capabilities.text_document_sync =
12919 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12920 });
12921 notify_server_capabilities_updated(&server, cx);
12922 }
12923 "textDocument/didSave" => {
12924 server.update_capabilities(|capabilities| {
12925 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12926 sync_options.save = None;
12927 capabilities.text_document_sync =
12928 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12929 });
12930 notify_server_capabilities_updated(&server, cx);
12931 }
12932 "textDocument/codeLens" => {
12933 server.update_capabilities(|capabilities| {
12934 capabilities.code_lens_provider = None;
12935 });
12936 notify_server_capabilities_updated(&server, cx);
12937 }
12938 "textDocument/diagnostic" => {
12939 let local = self
12940 .as_local_mut()
12941 .context("Expected LSP Store to be local")?;
12942
12943 let state = local
12944 .language_servers
12945 .get_mut(&server_id)
12946 .context("Could not obtain Language Servers state")?;
12947 let registrations = local
12948 .language_server_dynamic_registrations
12949 .get_mut(&server_id)
12950 .with_context(|| {
12951 format!("Expected dynamic registration to exist for server {server_id}")
12952 })?;
12953 registrations.diagnostics
12954 .remove(&Some(unreg.id.clone()))
12955 .with_context(|| format!(
12956 "Attempted to unregister non-existent diagnostic registration with ID {}",
12957 unreg.id)
12958 )?;
12959 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12960
12961 if let LanguageServerState::Running {
12962 workspace_diagnostics_refresh_tasks,
12963 ..
12964 } = state
12965 {
12966 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12967 }
12968
12969 self.clear_unregistered_diagnostics(
12970 server_id,
12971 SharedString::from(unreg.id.clone()),
12972 cx,
12973 )?;
12974
12975 if removed_last_diagnostic_provider {
12976 server.update_capabilities(|capabilities| {
12977 debug_assert!(capabilities.diagnostic_provider.is_some());
12978 capabilities.diagnostic_provider = None;
12979 });
12980 }
12981
12982 notify_server_capabilities_updated(&server, cx);
12983 }
12984 "textDocument/documentColor" => {
12985 server.update_capabilities(|capabilities| {
12986 capabilities.color_provider = None;
12987 });
12988 notify_server_capabilities_updated(&server, cx);
12989 }
12990 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12991 }
12992 }
12993
12994 Ok(())
12995 }
12996
12997 fn clear_unregistered_diagnostics(
12998 &mut self,
12999 server_id: LanguageServerId,
13000 cleared_registration_id: SharedString,
13001 cx: &mut Context<Self>,
13002 ) -> anyhow::Result<()> {
13003 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
13004
13005 self.buffer_store.update(cx, |buffer_store, cx| {
13006 for buffer_handle in buffer_store.buffers() {
13007 let buffer = buffer_handle.read(cx);
13008 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
13009 let Some(abs_path) = abs_path else {
13010 continue;
13011 };
13012 affected_abs_paths.insert(abs_path);
13013 }
13014 });
13015
13016 let local = self.as_local().context("Expected LSP Store to be local")?;
13017 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13018 let Some(worktree) = self
13019 .worktree_store
13020 .read(cx)
13021 .worktree_for_id(*worktree_id, cx)
13022 else {
13023 continue;
13024 };
13025
13026 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13027 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13028 let has_matching_registration =
13029 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13030 entry.diagnostic.registration_id.as_ref()
13031 == Some(&cleared_registration_id)
13032 });
13033 if has_matching_registration {
13034 let abs_path = worktree.read(cx).absolutize(rel_path);
13035 affected_abs_paths.insert(abs_path);
13036 }
13037 }
13038 }
13039 }
13040
13041 if affected_abs_paths.is_empty() {
13042 return Ok(());
13043 }
13044
13045 // Send a fake diagnostic update which clears the state for the registration ID
13046 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13047 affected_abs_paths
13048 .into_iter()
13049 .map(|abs_path| DocumentDiagnosticsUpdate {
13050 diagnostics: DocumentDiagnostics {
13051 diagnostics: Vec::new(),
13052 document_abs_path: abs_path,
13053 version: None,
13054 },
13055 result_id: None,
13056 registration_id: Some(cleared_registration_id.clone()),
13057 server_id,
13058 disk_based_sources: Cow::Borrowed(&[]),
13059 })
13060 .collect();
13061
13062 let merge_registration_id = cleared_registration_id.clone();
13063 self.merge_diagnostic_entries(
13064 clears,
13065 move |_, diagnostic, _| {
13066 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13067 diagnostic.registration_id != Some(merge_registration_id.clone())
13068 } else {
13069 true
13070 }
13071 },
13072 cx,
13073 )?;
13074
13075 Ok(())
13076 }
13077
13078 async fn deduplicate_range_based_lsp_requests<T>(
13079 lsp_store: &Entity<Self>,
13080 server_id: Option<LanguageServerId>,
13081 lsp_request_id: LspRequestId,
13082 proto_request: &T::ProtoRequest,
13083 range: Range<Anchor>,
13084 cx: &mut AsyncApp,
13085 ) -> Result<()>
13086 where
13087 T: LspCommand,
13088 T::ProtoRequest: proto::LspRequestMessage,
13089 {
13090 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13091 let version = deserialize_version(proto_request.buffer_version());
13092 let buffer = lsp_store.update(cx, |this, cx| {
13093 this.buffer_store.read(cx).get_existing(buffer_id)
13094 })?;
13095 buffer
13096 .update(cx, |buffer, _| buffer.wait_for_version(version))
13097 .await?;
13098 lsp_store.update(cx, |lsp_store, cx| {
13099 let buffer_snapshot = buffer.read(cx).snapshot();
13100 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13101 let chunks_queried_for = lsp_data
13102 .inlay_hints
13103 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13104 .collect::<Vec<_>>();
13105 match chunks_queried_for.as_slice() {
13106 &[chunk] => {
13107 let key = LspKey {
13108 request_type: TypeId::of::<T>(),
13109 server_queried: server_id,
13110 };
13111 let previous_request = lsp_data
13112 .chunk_lsp_requests
13113 .entry(key)
13114 .or_default()
13115 .insert(chunk, lsp_request_id);
13116 if let Some((previous_request, running_requests)) =
13117 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13118 {
13119 running_requests.remove(&previous_request);
13120 }
13121 }
13122 _ambiguous_chunks => {
13123 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13124 // there, a buffer version-based check will be performed and outdated requests discarded.
13125 }
13126 }
13127 anyhow::Ok(())
13128 })?;
13129
13130 Ok(())
13131 }
13132
13133 async fn query_lsp_locally<T>(
13134 lsp_store: Entity<Self>,
13135 for_server_id: Option<LanguageServerId>,
13136 sender_id: proto::PeerId,
13137 lsp_request_id: LspRequestId,
13138 proto_request: T::ProtoRequest,
13139 position: Option<Anchor>,
13140 cx: &mut AsyncApp,
13141 ) -> Result<()>
13142 where
13143 T: LspCommand + Clone,
13144 T::ProtoRequest: proto::LspRequestMessage,
13145 <T::ProtoRequest as proto::RequestMessage>::Response:
13146 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13147 {
13148 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13149 let version = deserialize_version(proto_request.buffer_version());
13150 let buffer = lsp_store.update(cx, |this, cx| {
13151 this.buffer_store.read(cx).get_existing(buffer_id)
13152 })?;
13153 buffer
13154 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13155 .await?;
13156 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13157 let request =
13158 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13159 let key = LspKey {
13160 request_type: TypeId::of::<T>(),
13161 server_queried: for_server_id,
13162 };
13163 lsp_store.update(cx, |lsp_store, cx| {
13164 let request_task = match for_server_id {
13165 Some(server_id) => {
13166 let server_task = lsp_store.request_lsp(
13167 buffer.clone(),
13168 LanguageServerToQuery::Other(server_id),
13169 request.clone(),
13170 cx,
13171 );
13172 cx.background_spawn(async move {
13173 let mut responses = Vec::new();
13174 match server_task.await {
13175 Ok(response) => responses.push((server_id, response)),
13176 // rust-analyzer likes to error with this when its still loading up
13177 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13178 Err(e) => log::error!(
13179 "Error handling response for request {request:?}: {e:#}"
13180 ),
13181 }
13182 responses
13183 })
13184 }
13185 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13186 };
13187 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13188 if T::ProtoRequest::stop_previous_requests() {
13189 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13190 lsp_requests.clear();
13191 }
13192 }
13193 lsp_data.lsp_requests.entry(key).or_default().insert(
13194 lsp_request_id,
13195 cx.spawn(async move |lsp_store, cx| {
13196 let response = request_task.await;
13197 lsp_store
13198 .update(cx, |lsp_store, cx| {
13199 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13200 {
13201 let response = response
13202 .into_iter()
13203 .map(|(server_id, response)| {
13204 (
13205 server_id.to_proto(),
13206 T::response_to_proto(
13207 response,
13208 lsp_store,
13209 sender_id,
13210 &buffer_version,
13211 cx,
13212 )
13213 .into(),
13214 )
13215 })
13216 .collect::<HashMap<_, _>>();
13217 match client.send_lsp_response::<T::ProtoRequest>(
13218 project_id,
13219 lsp_request_id,
13220 response,
13221 ) {
13222 Ok(()) => {}
13223 Err(e) => {
13224 log::error!("Failed to send LSP response: {e:#}",)
13225 }
13226 }
13227 }
13228 })
13229 .ok();
13230 }),
13231 );
13232 });
13233 Ok(())
13234 }
13235
13236 fn take_text_document_sync_options(
13237 capabilities: &mut lsp::ServerCapabilities,
13238 ) -> lsp::TextDocumentSyncOptions {
13239 match capabilities.text_document_sync.take() {
13240 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13241 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13242 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13243 sync_options.change = Some(sync_kind);
13244 sync_options
13245 }
13246 None => lsp::TextDocumentSyncOptions::default(),
13247 }
13248 }
13249
13250 #[cfg(any(test, feature = "test-support"))]
13251 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13252 Some(
13253 self.lsp_data
13254 .get_mut(&buffer_id)?
13255 .code_lens
13256 .take()?
13257 .update
13258 .take()?
13259 .1,
13260 )
13261 }
13262
13263 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13264 self.downstream_client.clone()
13265 }
13266
13267 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13268 self.worktree_store.clone()
13269 }
13270
13271 /// Gets what's stored in the LSP data for the given buffer.
13272 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13273 self.lsp_data.get_mut(&buffer_id)
13274 }
13275
13276 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13277 /// new [`BufferLspData`] will be created to replace the previous state.
13278 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13279 let (buffer_id, buffer_version) =
13280 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13281 let lsp_data = self
13282 .lsp_data
13283 .entry(buffer_id)
13284 .or_insert_with(|| BufferLspData::new(buffer, cx));
13285 if buffer_version.changed_since(&lsp_data.buffer_version) {
13286 *lsp_data = BufferLspData::new(buffer, cx);
13287 }
13288 lsp_data
13289 }
13290}
13291
13292// Registration with registerOptions as null, should fallback to true.
13293// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13294fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13295 reg: lsp::Registration,
13296) -> Result<OneOf<bool, T>> {
13297 Ok(match reg.register_options {
13298 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13299 None => OneOf::Left(true),
13300 })
13301}
13302
13303fn subscribe_to_binary_statuses(
13304 languages: &Arc<LanguageRegistry>,
13305 cx: &mut Context<'_, LspStore>,
13306) -> Task<()> {
13307 let mut server_statuses = languages.language_server_binary_statuses();
13308 cx.spawn(async move |lsp_store, cx| {
13309 while let Some((server_name, binary_status)) = server_statuses.next().await {
13310 if lsp_store
13311 .update(cx, |_, cx| {
13312 let mut message = None;
13313 let binary_status = match binary_status {
13314 BinaryStatus::None => proto::ServerBinaryStatus::None,
13315 BinaryStatus::CheckingForUpdate => {
13316 proto::ServerBinaryStatus::CheckingForUpdate
13317 }
13318 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13319 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13320 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13321 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13322 BinaryStatus::Failed { error } => {
13323 message = Some(error);
13324 proto::ServerBinaryStatus::Failed
13325 }
13326 };
13327 cx.emit(LspStoreEvent::LanguageServerUpdate {
13328 // Binary updates are about the binary that might not have any language server id at that point.
13329 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13330 language_server_id: LanguageServerId(0),
13331 name: Some(server_name),
13332 message: proto::update_language_server::Variant::StatusUpdate(
13333 proto::StatusUpdate {
13334 message,
13335 status: Some(proto::status_update::Status::Binary(
13336 binary_status as i32,
13337 )),
13338 },
13339 ),
13340 });
13341 })
13342 .is_err()
13343 {
13344 break;
13345 }
13346 }
13347 })
13348}
13349
13350fn lsp_workspace_diagnostics_refresh(
13351 registration_id: Option<String>,
13352 options: DiagnosticServerCapabilities,
13353 server: Arc<LanguageServer>,
13354 cx: &mut Context<'_, LspStore>,
13355) -> Option<WorkspaceRefreshTask> {
13356 let identifier = workspace_diagnostic_identifier(&options)?;
13357 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13358
13359 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13360 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13361 refresh_tx.try_send(()).ok();
13362
13363 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13364 let mut attempts = 0;
13365 let max_attempts = 50;
13366 let mut requests = 0;
13367
13368 loop {
13369 let Some(()) = refresh_rx.recv().await else {
13370 return;
13371 };
13372
13373 'request: loop {
13374 requests += 1;
13375 if attempts > max_attempts {
13376 log::error!(
13377 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13378 );
13379 return;
13380 }
13381 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13382 cx.background_executor()
13383 .timer(Duration::from_millis(backoff_millis))
13384 .await;
13385 attempts += 1;
13386
13387 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13388 lsp_store
13389 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13390 .into_iter()
13391 .filter_map(|(abs_path, result_id)| {
13392 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13393 Some(lsp::PreviousResultId {
13394 uri,
13395 value: result_id.to_string(),
13396 })
13397 })
13398 .collect()
13399 }) else {
13400 return;
13401 };
13402
13403 let token = if let Some(registration_id) = ®istration_id {
13404 format!(
13405 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13406 server.server_id(),
13407 )
13408 } else {
13409 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13410 };
13411
13412 progress_rx.try_recv().ok();
13413 let timer =
13414 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13415 let progress = pin!(progress_rx.recv().fuse());
13416 let response_result = server
13417 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13418 lsp::WorkspaceDiagnosticParams {
13419 previous_result_ids,
13420 identifier: identifier.clone(),
13421 work_done_progress_params: Default::default(),
13422 partial_result_params: lsp::PartialResultParams {
13423 partial_result_token: Some(lsp::ProgressToken::String(token)),
13424 },
13425 },
13426 select(timer, progress).then(|either| match either {
13427 Either::Left((message, ..)) => ready(message).left_future(),
13428 Either::Right(..) => pending::<String>().right_future(),
13429 }),
13430 )
13431 .await;
13432
13433 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13434 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13435 match response_result {
13436 ConnectionResult::Timeout => {
13437 log::error!("Timeout during workspace diagnostics pull");
13438 continue 'request;
13439 }
13440 ConnectionResult::ConnectionReset => {
13441 log::error!("Server closed a workspace diagnostics pull request");
13442 continue 'request;
13443 }
13444 ConnectionResult::Result(Err(e)) => {
13445 log::error!("Error during workspace diagnostics pull: {e:#}");
13446 break 'request;
13447 }
13448 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13449 attempts = 0;
13450 if lsp_store
13451 .update(cx, |lsp_store, cx| {
13452 lsp_store.apply_workspace_diagnostic_report(
13453 server.server_id(),
13454 pulled_diagnostics,
13455 registration_id_shared.clone(),
13456 cx,
13457 )
13458 })
13459 .is_err()
13460 {
13461 return;
13462 }
13463 break 'request;
13464 }
13465 }
13466 }
13467 }
13468 });
13469
13470 Some(WorkspaceRefreshTask {
13471 refresh_tx,
13472 progress_tx,
13473 task: workspace_query_language_server,
13474 })
13475}
13476
13477fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13478 match &options {
13479 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13480 diagnostic_options.identifier.clone()
13481 }
13482 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13483 let diagnostic_options = ®istration_options.diagnostic_options;
13484 diagnostic_options.identifier.clone()
13485 }
13486 }
13487}
13488
13489fn workspace_diagnostic_identifier(
13490 options: &DiagnosticServerCapabilities,
13491) -> Option<Option<String>> {
13492 match &options {
13493 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13494 if !diagnostic_options.workspace_diagnostics {
13495 return None;
13496 }
13497 Some(diagnostic_options.identifier.clone())
13498 }
13499 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13500 let diagnostic_options = ®istration_options.diagnostic_options;
13501 if !diagnostic_options.workspace_diagnostics {
13502 return None;
13503 }
13504 Some(diagnostic_options.identifier.clone())
13505 }
13506 }
13507}
13508
13509fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13510 let CompletionSource::BufferWord {
13511 word_range,
13512 resolved,
13513 } = &mut completion.source
13514 else {
13515 return;
13516 };
13517 if *resolved {
13518 return;
13519 }
13520
13521 if completion.new_text
13522 != snapshot
13523 .text_for_range(word_range.clone())
13524 .collect::<String>()
13525 {
13526 return;
13527 }
13528
13529 let mut offset = 0;
13530 for chunk in snapshot.chunks(word_range.clone(), true) {
13531 let end_offset = offset + chunk.text.len();
13532 if let Some(highlight_id) = chunk.syntax_highlight_id {
13533 completion
13534 .label
13535 .runs
13536 .push((offset..end_offset, highlight_id));
13537 }
13538 offset = end_offset;
13539 }
13540 *resolved = true;
13541}
13542
13543impl EventEmitter<LspStoreEvent> for LspStore {}
13544
13545fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13546 hover
13547 .contents
13548 .retain(|hover_block| !hover_block.text.trim().is_empty());
13549 if hover.contents.is_empty() {
13550 None
13551 } else {
13552 Some(hover)
13553 }
13554}
13555
13556async fn populate_labels_for_completions(
13557 new_completions: Vec<CoreCompletion>,
13558 language: Option<Arc<Language>>,
13559 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13560) -> Vec<Completion> {
13561 let lsp_completions = new_completions
13562 .iter()
13563 .filter_map(|new_completion| {
13564 new_completion
13565 .source
13566 .lsp_completion(true)
13567 .map(|lsp_completion| lsp_completion.into_owned())
13568 })
13569 .collect::<Vec<_>>();
13570
13571 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13572 lsp_adapter
13573 .labels_for_completions(&lsp_completions, language)
13574 .await
13575 .log_err()
13576 .unwrap_or_default()
13577 } else {
13578 Vec::new()
13579 }
13580 .into_iter()
13581 .fuse();
13582
13583 let mut completions = Vec::new();
13584 for completion in new_completions {
13585 match completion.source.lsp_completion(true) {
13586 Some(lsp_completion) => {
13587 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13588
13589 let mut label = labels.next().flatten().unwrap_or_else(|| {
13590 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13591 });
13592 ensure_uniform_list_compatible_label(&mut label);
13593 completions.push(Completion {
13594 label,
13595 documentation,
13596 replace_range: completion.replace_range,
13597 new_text: completion.new_text,
13598 insert_text_mode: lsp_completion.insert_text_mode,
13599 source: completion.source,
13600 icon_path: None,
13601 confirm: None,
13602 match_start: None,
13603 snippet_deduplication_key: None,
13604 });
13605 }
13606 None => {
13607 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13608 ensure_uniform_list_compatible_label(&mut label);
13609 completions.push(Completion {
13610 label,
13611 documentation: None,
13612 replace_range: completion.replace_range,
13613 new_text: completion.new_text,
13614 source: completion.source,
13615 insert_text_mode: None,
13616 icon_path: None,
13617 confirm: None,
13618 match_start: None,
13619 snippet_deduplication_key: None,
13620 });
13621 }
13622 }
13623 }
13624 completions
13625}
13626
13627#[derive(Debug)]
13628pub enum LanguageServerToQuery {
13629 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13630 FirstCapable,
13631 /// Query a specific language server.
13632 Other(LanguageServerId),
13633}
13634
13635#[derive(Default)]
13636struct RenamePathsWatchedForServer {
13637 did_rename: Vec<RenameActionPredicate>,
13638 will_rename: Vec<RenameActionPredicate>,
13639}
13640
13641impl RenamePathsWatchedForServer {
13642 fn with_did_rename_patterns(
13643 mut self,
13644 did_rename: Option<&FileOperationRegistrationOptions>,
13645 ) -> Self {
13646 if let Some(did_rename) = did_rename {
13647 self.did_rename = did_rename
13648 .filters
13649 .iter()
13650 .filter_map(|filter| filter.try_into().log_err())
13651 .collect();
13652 }
13653 self
13654 }
13655 fn with_will_rename_patterns(
13656 mut self,
13657 will_rename: Option<&FileOperationRegistrationOptions>,
13658 ) -> Self {
13659 if let Some(will_rename) = will_rename {
13660 self.will_rename = will_rename
13661 .filters
13662 .iter()
13663 .filter_map(|filter| filter.try_into().log_err())
13664 .collect();
13665 }
13666 self
13667 }
13668
13669 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13670 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13671 }
13672 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13673 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13674 }
13675}
13676
13677impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13678 type Error = globset::Error;
13679 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13680 Ok(Self {
13681 kind: ops.pattern.matches.clone(),
13682 glob: GlobBuilder::new(&ops.pattern.glob)
13683 .case_insensitive(
13684 ops.pattern
13685 .options
13686 .as_ref()
13687 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13688 )
13689 .build()?
13690 .compile_matcher(),
13691 })
13692 }
13693}
13694struct RenameActionPredicate {
13695 glob: GlobMatcher,
13696 kind: Option<FileOperationPatternKind>,
13697}
13698
13699impl RenameActionPredicate {
13700 // Returns true if language server should be notified
13701 fn eval(&self, path: &str, is_dir: bool) -> bool {
13702 self.kind.as_ref().is_none_or(|kind| {
13703 let expected_kind = if is_dir {
13704 FileOperationPatternKind::Folder
13705 } else {
13706 FileOperationPatternKind::File
13707 };
13708 kind == &expected_kind
13709 }) && self.glob.is_match(path)
13710 }
13711}
13712
13713#[derive(Default)]
13714struct LanguageServerWatchedPaths {
13715 worktree_paths: HashMap<WorktreeId, GlobSet>,
13716 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13717}
13718
13719#[derive(Default)]
13720struct LanguageServerWatchedPathsBuilder {
13721 worktree_paths: HashMap<WorktreeId, GlobSet>,
13722 abs_paths: HashMap<Arc<Path>, GlobSet>,
13723}
13724
13725impl LanguageServerWatchedPathsBuilder {
13726 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13727 self.worktree_paths.insert(worktree_id, glob_set);
13728 }
13729 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13730 self.abs_paths.insert(path, glob_set);
13731 }
13732 fn build(
13733 self,
13734 fs: Arc<dyn Fs>,
13735 language_server_id: LanguageServerId,
13736 cx: &mut Context<LspStore>,
13737 ) -> LanguageServerWatchedPaths {
13738 let lsp_store = cx.weak_entity();
13739
13740 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13741 let abs_paths = self
13742 .abs_paths
13743 .into_iter()
13744 .map(|(abs_path, globset)| {
13745 let task = cx.spawn({
13746 let abs_path = abs_path.clone();
13747 let fs = fs.clone();
13748
13749 let lsp_store = lsp_store.clone();
13750 async move |_, cx| {
13751 maybe!(async move {
13752 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13753 while let Some(update) = push_updates.0.next().await {
13754 let action = lsp_store
13755 .update(cx, |this, _| {
13756 let Some(local) = this.as_local() else {
13757 return ControlFlow::Break(());
13758 };
13759 let Some(watcher) = local
13760 .language_server_watched_paths
13761 .get(&language_server_id)
13762 else {
13763 return ControlFlow::Break(());
13764 };
13765 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13766 "Watched abs path is not registered with a watcher",
13767 );
13768 let matching_entries = update
13769 .into_iter()
13770 .filter(|event| globs.is_match(&event.path))
13771 .collect::<Vec<_>>();
13772 this.lsp_notify_abs_paths_changed(
13773 language_server_id,
13774 matching_entries,
13775 );
13776 ControlFlow::Continue(())
13777 })
13778 .ok()?;
13779
13780 if action.is_break() {
13781 break;
13782 }
13783 }
13784 Some(())
13785 })
13786 .await;
13787 }
13788 });
13789 (abs_path, (globset, task))
13790 })
13791 .collect();
13792 LanguageServerWatchedPaths {
13793 worktree_paths: self.worktree_paths,
13794 abs_paths,
13795 }
13796 }
13797}
13798
13799struct LspBufferSnapshot {
13800 version: i32,
13801 snapshot: TextBufferSnapshot,
13802}
13803
13804/// A prompt requested by LSP server.
13805#[derive(Clone, Debug)]
13806pub struct LanguageServerPromptRequest {
13807 pub id: usize,
13808 pub level: PromptLevel,
13809 pub message: String,
13810 pub actions: Vec<MessageActionItem>,
13811 pub lsp_name: String,
13812 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13813}
13814
13815impl LanguageServerPromptRequest {
13816 pub fn new(
13817 level: PromptLevel,
13818 message: String,
13819 actions: Vec<MessageActionItem>,
13820 lsp_name: String,
13821 response_channel: smol::channel::Sender<MessageActionItem>,
13822 ) -> Self {
13823 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13824 LanguageServerPromptRequest {
13825 id,
13826 level,
13827 message,
13828 actions,
13829 lsp_name,
13830 response_channel,
13831 }
13832 }
13833 pub async fn respond(self, index: usize) -> Option<()> {
13834 if let Some(response) = self.actions.into_iter().nth(index) {
13835 self.response_channel.send(response).await.ok()
13836 } else {
13837 None
13838 }
13839 }
13840
13841 #[cfg(any(test, feature = "test-support"))]
13842 pub fn test(
13843 level: PromptLevel,
13844 message: String,
13845 actions: Vec<MessageActionItem>,
13846 lsp_name: String,
13847 ) -> Self {
13848 let (tx, _rx) = smol::channel::unbounded();
13849 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13850 }
13851}
13852impl PartialEq for LanguageServerPromptRequest {
13853 fn eq(&self, other: &Self) -> bool {
13854 self.message == other.message && self.actions == other.actions
13855 }
13856}
13857
13858#[derive(Clone, Debug, PartialEq)]
13859pub enum LanguageServerLogType {
13860 Log(MessageType),
13861 Trace { verbose_info: Option<String> },
13862 Rpc { received: bool },
13863}
13864
13865impl LanguageServerLogType {
13866 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13867 match self {
13868 Self::Log(log_type) => {
13869 use proto::log_message::LogLevel;
13870 let level = match *log_type {
13871 MessageType::ERROR => LogLevel::Error,
13872 MessageType::WARNING => LogLevel::Warning,
13873 MessageType::INFO => LogLevel::Info,
13874 MessageType::LOG => LogLevel::Log,
13875 other => {
13876 log::warn!("Unknown lsp log message type: {other:?}");
13877 LogLevel::Log
13878 }
13879 };
13880 proto::language_server_log::LogType::Log(proto::LogMessage {
13881 level: level as i32,
13882 })
13883 }
13884 Self::Trace { verbose_info } => {
13885 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13886 verbose_info: verbose_info.to_owned(),
13887 })
13888 }
13889 Self::Rpc { received } => {
13890 let kind = if *received {
13891 proto::rpc_message::Kind::Received
13892 } else {
13893 proto::rpc_message::Kind::Sent
13894 };
13895 let kind = kind as i32;
13896 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13897 }
13898 }
13899 }
13900
13901 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13902 use proto::log_message::LogLevel;
13903 use proto::rpc_message;
13904 match log_type {
13905 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13906 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13907 LogLevel::Error => MessageType::ERROR,
13908 LogLevel::Warning => MessageType::WARNING,
13909 LogLevel::Info => MessageType::INFO,
13910 LogLevel::Log => MessageType::LOG,
13911 },
13912 ),
13913 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13914 verbose_info: trace_message.verbose_info,
13915 },
13916 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13917 received: match rpc_message::Kind::from_i32(message.kind)
13918 .unwrap_or(rpc_message::Kind::Received)
13919 {
13920 rpc_message::Kind::Received => true,
13921 rpc_message::Kind::Sent => false,
13922 },
13923 },
13924 }
13925 }
13926}
13927
13928pub struct WorkspaceRefreshTask {
13929 refresh_tx: mpsc::Sender<()>,
13930 progress_tx: mpsc::Sender<()>,
13931 #[allow(dead_code)]
13932 task: Task<()>,
13933}
13934
13935pub enum LanguageServerState {
13936 Starting {
13937 startup: Task<Option<Arc<LanguageServer>>>,
13938 /// List of language servers that will be added to the workspace once it's initialization completes.
13939 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13940 },
13941
13942 Running {
13943 adapter: Arc<CachedLspAdapter>,
13944 server: Arc<LanguageServer>,
13945 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13946 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13947 },
13948}
13949
13950impl LanguageServerState {
13951 fn add_workspace_folder(&self, uri: Uri) {
13952 match self {
13953 LanguageServerState::Starting {
13954 pending_workspace_folders,
13955 ..
13956 } => {
13957 pending_workspace_folders.lock().insert(uri);
13958 }
13959 LanguageServerState::Running { server, .. } => {
13960 server.add_workspace_folder(uri);
13961 }
13962 }
13963 }
13964 fn _remove_workspace_folder(&self, uri: Uri) {
13965 match self {
13966 LanguageServerState::Starting {
13967 pending_workspace_folders,
13968 ..
13969 } => {
13970 pending_workspace_folders.lock().remove(&uri);
13971 }
13972 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13973 }
13974 }
13975}
13976
13977impl std::fmt::Debug for LanguageServerState {
13978 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13979 match self {
13980 LanguageServerState::Starting { .. } => {
13981 f.debug_struct("LanguageServerState::Starting").finish()
13982 }
13983 LanguageServerState::Running { .. } => {
13984 f.debug_struct("LanguageServerState::Running").finish()
13985 }
13986 }
13987 }
13988}
13989
13990#[derive(Clone, Debug, Serialize)]
13991pub struct LanguageServerProgress {
13992 pub is_disk_based_diagnostics_progress: bool,
13993 pub is_cancellable: bool,
13994 pub title: Option<String>,
13995 pub message: Option<String>,
13996 pub percentage: Option<usize>,
13997 #[serde(skip_serializing)]
13998 pub last_update_at: Instant,
13999}
14000
14001#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14002pub struct DiagnosticSummary {
14003 pub error_count: usize,
14004 pub warning_count: usize,
14005}
14006
14007impl DiagnosticSummary {
14008 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14009 let mut this = Self {
14010 error_count: 0,
14011 warning_count: 0,
14012 };
14013
14014 for entry in diagnostics {
14015 if entry.diagnostic.is_primary {
14016 match entry.diagnostic.severity {
14017 DiagnosticSeverity::ERROR => this.error_count += 1,
14018 DiagnosticSeverity::WARNING => this.warning_count += 1,
14019 _ => {}
14020 }
14021 }
14022 }
14023
14024 this
14025 }
14026
14027 pub fn is_empty(&self) -> bool {
14028 self.error_count == 0 && self.warning_count == 0
14029 }
14030
14031 pub fn to_proto(
14032 self,
14033 language_server_id: LanguageServerId,
14034 path: &RelPath,
14035 ) -> proto::DiagnosticSummary {
14036 proto::DiagnosticSummary {
14037 path: path.to_proto(),
14038 language_server_id: language_server_id.0 as u64,
14039 error_count: self.error_count as u32,
14040 warning_count: self.warning_count as u32,
14041 }
14042 }
14043}
14044
14045#[derive(Clone, Debug)]
14046pub enum CompletionDocumentation {
14047 /// There is no documentation for this completion.
14048 Undocumented,
14049 /// A single line of documentation.
14050 SingleLine(SharedString),
14051 /// Multiple lines of plain text documentation.
14052 MultiLinePlainText(SharedString),
14053 /// Markdown documentation.
14054 MultiLineMarkdown(SharedString),
14055 /// Both single line and multiple lines of plain text documentation.
14056 SingleLineAndMultiLinePlainText {
14057 single_line: SharedString,
14058 plain_text: Option<SharedString>,
14059 },
14060}
14061
14062impl CompletionDocumentation {
14063 #[cfg(any(test, feature = "test-support"))]
14064 pub fn text(&self) -> SharedString {
14065 match self {
14066 CompletionDocumentation::Undocumented => "".into(),
14067 CompletionDocumentation::SingleLine(s) => s.clone(),
14068 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14069 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14070 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14071 single_line.clone()
14072 }
14073 }
14074 }
14075}
14076
14077impl From<lsp::Documentation> for CompletionDocumentation {
14078 fn from(docs: lsp::Documentation) -> Self {
14079 match docs {
14080 lsp::Documentation::String(text) => {
14081 if text.lines().count() <= 1 {
14082 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14083 } else {
14084 CompletionDocumentation::MultiLinePlainText(text.into())
14085 }
14086 }
14087
14088 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14089 lsp::MarkupKind::PlainText => {
14090 if value.lines().count() <= 1 {
14091 CompletionDocumentation::SingleLine(value.into())
14092 } else {
14093 CompletionDocumentation::MultiLinePlainText(value.into())
14094 }
14095 }
14096
14097 lsp::MarkupKind::Markdown => {
14098 CompletionDocumentation::MultiLineMarkdown(value.into())
14099 }
14100 },
14101 }
14102 }
14103}
14104
14105pub enum ResolvedHint {
14106 Resolved(InlayHint),
14107 Resolving(Shared<Task<()>>),
14108}
14109
14110pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14111 glob.components()
14112 .take_while(|component| match component {
14113 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14114 _ => true,
14115 })
14116 .collect()
14117}
14118
14119pub struct SshLspAdapter {
14120 name: LanguageServerName,
14121 binary: LanguageServerBinary,
14122 initialization_options: Option<String>,
14123 code_action_kinds: Option<Vec<CodeActionKind>>,
14124}
14125
14126impl SshLspAdapter {
14127 pub fn new(
14128 name: LanguageServerName,
14129 binary: LanguageServerBinary,
14130 initialization_options: Option<String>,
14131 code_action_kinds: Option<String>,
14132 ) -> Self {
14133 Self {
14134 name,
14135 binary,
14136 initialization_options,
14137 code_action_kinds: code_action_kinds
14138 .as_ref()
14139 .and_then(|c| serde_json::from_str(c).ok()),
14140 }
14141 }
14142}
14143
14144impl LspInstaller for SshLspAdapter {
14145 type BinaryVersion = ();
14146 async fn check_if_user_installed(
14147 &self,
14148 _: &dyn LspAdapterDelegate,
14149 _: Option<Toolchain>,
14150 _: &AsyncApp,
14151 ) -> Option<LanguageServerBinary> {
14152 Some(self.binary.clone())
14153 }
14154
14155 async fn cached_server_binary(
14156 &self,
14157 _: PathBuf,
14158 _: &dyn LspAdapterDelegate,
14159 ) -> Option<LanguageServerBinary> {
14160 None
14161 }
14162
14163 async fn fetch_latest_server_version(
14164 &self,
14165 _: &dyn LspAdapterDelegate,
14166 _: bool,
14167 _: &mut AsyncApp,
14168 ) -> Result<()> {
14169 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14170 }
14171
14172 async fn fetch_server_binary(
14173 &self,
14174 _: (),
14175 _: PathBuf,
14176 _: &dyn LspAdapterDelegate,
14177 ) -> Result<LanguageServerBinary> {
14178 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14179 }
14180}
14181
14182#[async_trait(?Send)]
14183impl LspAdapter for SshLspAdapter {
14184 fn name(&self) -> LanguageServerName {
14185 self.name.clone()
14186 }
14187
14188 async fn initialization_options(
14189 self: Arc<Self>,
14190 _: &Arc<dyn LspAdapterDelegate>,
14191 ) -> Result<Option<serde_json::Value>> {
14192 let Some(options) = &self.initialization_options else {
14193 return Ok(None);
14194 };
14195 let result = serde_json::from_str(options)?;
14196 Ok(result)
14197 }
14198
14199 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14200 self.code_action_kinds.clone()
14201 }
14202}
14203
14204pub fn language_server_settings<'a>(
14205 delegate: &'a dyn LspAdapterDelegate,
14206 language: &LanguageServerName,
14207 cx: &'a App,
14208) -> Option<&'a LspSettings> {
14209 language_server_settings_for(
14210 SettingsLocation {
14211 worktree_id: delegate.worktree_id(),
14212 path: RelPath::empty(),
14213 },
14214 language,
14215 cx,
14216 )
14217}
14218
14219pub fn language_server_settings_for<'a>(
14220 location: SettingsLocation<'a>,
14221 language: &LanguageServerName,
14222 cx: &'a App,
14223) -> Option<&'a LspSettings> {
14224 ProjectSettings::get(Some(location), cx).lsp.get(language)
14225}
14226
14227pub struct LocalLspAdapterDelegate {
14228 lsp_store: WeakEntity<LspStore>,
14229 worktree: worktree::Snapshot,
14230 fs: Arc<dyn Fs>,
14231 http_client: Arc<dyn HttpClient>,
14232 language_registry: Arc<LanguageRegistry>,
14233 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14234}
14235
14236impl LocalLspAdapterDelegate {
14237 pub fn new(
14238 language_registry: Arc<LanguageRegistry>,
14239 environment: &Entity<ProjectEnvironment>,
14240 lsp_store: WeakEntity<LspStore>,
14241 worktree: &Entity<Worktree>,
14242 http_client: Arc<dyn HttpClient>,
14243 fs: Arc<dyn Fs>,
14244 cx: &mut App,
14245 ) -> Arc<Self> {
14246 let load_shell_env_task =
14247 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14248
14249 Arc::new(Self {
14250 lsp_store,
14251 worktree: worktree.read(cx).snapshot(),
14252 fs,
14253 http_client,
14254 language_registry,
14255 load_shell_env_task,
14256 })
14257 }
14258
14259 pub fn from_local_lsp(
14260 local: &LocalLspStore,
14261 worktree: &Entity<Worktree>,
14262 cx: &mut App,
14263 ) -> Arc<Self> {
14264 Self::new(
14265 local.languages.clone(),
14266 &local.environment,
14267 local.weak.clone(),
14268 worktree,
14269 local.http_client.clone(),
14270 local.fs.clone(),
14271 cx,
14272 )
14273 }
14274}
14275
14276#[async_trait]
14277impl LspAdapterDelegate for LocalLspAdapterDelegate {
14278 fn show_notification(&self, message: &str, cx: &mut App) {
14279 self.lsp_store
14280 .update(cx, |_, cx| {
14281 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14282 })
14283 .ok();
14284 }
14285
14286 fn http_client(&self) -> Arc<dyn HttpClient> {
14287 self.http_client.clone()
14288 }
14289
14290 fn worktree_id(&self) -> WorktreeId {
14291 self.worktree.id()
14292 }
14293
14294 fn worktree_root_path(&self) -> &Path {
14295 self.worktree.abs_path().as_ref()
14296 }
14297
14298 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14299 self.worktree.resolve_executable_path(path)
14300 }
14301
14302 async fn shell_env(&self) -> HashMap<String, String> {
14303 let task = self.load_shell_env_task.clone();
14304 task.await.unwrap_or_default()
14305 }
14306
14307 async fn npm_package_installed_version(
14308 &self,
14309 package_name: &str,
14310 ) -> Result<Option<(PathBuf, Version)>> {
14311 let local_package_directory = self.worktree_root_path();
14312 let node_modules_directory = local_package_directory.join("node_modules");
14313
14314 if let Some(version) =
14315 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14316 {
14317 return Ok(Some((node_modules_directory, version)));
14318 }
14319 let Some(npm) = self.which("npm".as_ref()).await else {
14320 log::warn!(
14321 "Failed to find npm executable for {:?}",
14322 local_package_directory
14323 );
14324 return Ok(None);
14325 };
14326
14327 let env = self.shell_env().await;
14328 let output = util::command::new_smol_command(&npm)
14329 .args(["root", "-g"])
14330 .envs(env)
14331 .current_dir(local_package_directory)
14332 .output()
14333 .await?;
14334 let global_node_modules =
14335 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14336
14337 if let Some(version) =
14338 read_package_installed_version(global_node_modules.clone(), package_name).await?
14339 {
14340 return Ok(Some((global_node_modules, version)));
14341 }
14342 return Ok(None);
14343 }
14344
14345 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14346 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14347 if self.fs.is_file(&worktree_abs_path).await {
14348 worktree_abs_path.pop();
14349 }
14350
14351 let env = self.shell_env().await;
14352
14353 let shell_path = env.get("PATH").cloned();
14354
14355 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14356 }
14357
14358 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14359 let mut working_dir = self.worktree_root_path().to_path_buf();
14360 if self.fs.is_file(&working_dir).await {
14361 working_dir.pop();
14362 }
14363 let output = util::command::new_smol_command(&command.path)
14364 .args(command.arguments)
14365 .envs(command.env.clone().unwrap_or_default())
14366 .current_dir(working_dir)
14367 .output()
14368 .await?;
14369
14370 anyhow::ensure!(
14371 output.status.success(),
14372 "{}, stdout: {:?}, stderr: {:?}",
14373 output.status,
14374 String::from_utf8_lossy(&output.stdout),
14375 String::from_utf8_lossy(&output.stderr)
14376 );
14377 Ok(())
14378 }
14379
14380 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14381 self.language_registry
14382 .update_lsp_binary_status(server_name, status);
14383 }
14384
14385 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14386 self.language_registry
14387 .all_lsp_adapters()
14388 .into_iter()
14389 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14390 .collect()
14391 }
14392
14393 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14394 let dir = self.language_registry.language_server_download_dir(name)?;
14395
14396 if !dir.exists() {
14397 smol::fs::create_dir_all(&dir)
14398 .await
14399 .context("failed to create container directory")
14400 .log_err()?;
14401 }
14402
14403 Some(dir)
14404 }
14405
14406 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14407 let entry = self
14408 .worktree
14409 .entry_for_path(path)
14410 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14411 let abs_path = self.worktree.absolutize(&entry.path);
14412 self.fs.load(&abs_path).await
14413 }
14414}
14415
14416async fn populate_labels_for_symbols(
14417 symbols: Vec<CoreSymbol>,
14418 language_registry: &Arc<LanguageRegistry>,
14419 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14420 output: &mut Vec<Symbol>,
14421) {
14422 #[allow(clippy::mutable_key_type)]
14423 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14424
14425 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14426 for symbol in symbols {
14427 let Some(file_name) = symbol.path.file_name() else {
14428 continue;
14429 };
14430 let language = language_registry
14431 .load_language_for_file_path(Path::new(file_name))
14432 .await
14433 .ok()
14434 .or_else(|| {
14435 unknown_paths.insert(file_name.into());
14436 None
14437 });
14438 symbols_by_language
14439 .entry(language)
14440 .or_default()
14441 .push(symbol);
14442 }
14443
14444 for unknown_path in unknown_paths {
14445 log::info!("no language found for symbol in file {unknown_path:?}");
14446 }
14447
14448 let mut label_params = Vec::new();
14449 for (language, mut symbols) in symbols_by_language {
14450 label_params.clear();
14451 label_params.extend(
14452 symbols
14453 .iter_mut()
14454 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14455 );
14456
14457 let mut labels = Vec::new();
14458 if let Some(language) = language {
14459 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14460 language_registry
14461 .lsp_adapters(&language.name())
14462 .first()
14463 .cloned()
14464 });
14465 if let Some(lsp_adapter) = lsp_adapter {
14466 labels = lsp_adapter
14467 .labels_for_symbols(&label_params, &language)
14468 .await
14469 .log_err()
14470 .unwrap_or_default();
14471 }
14472 }
14473
14474 for ((symbol, (name, _)), label) in symbols
14475 .into_iter()
14476 .zip(label_params.drain(..))
14477 .zip(labels.into_iter().chain(iter::repeat(None)))
14478 {
14479 output.push(Symbol {
14480 language_server_name: symbol.language_server_name,
14481 source_worktree_id: symbol.source_worktree_id,
14482 source_language_server_id: symbol.source_language_server_id,
14483 path: symbol.path,
14484 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14485 name,
14486 kind: symbol.kind,
14487 range: symbol.range,
14488 });
14489 }
14490 }
14491}
14492
14493fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14494 match server.capabilities().text_document_sync.as_ref()? {
14495 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14496 // Server wants didSave but didn't specify includeText.
14497 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14498 // Server doesn't want didSave at all.
14499 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14500 // Server provided SaveOptions.
14501 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14502 Some(save_options.include_text.unwrap_or(false))
14503 }
14504 },
14505 // We do not have any save info. Kind affects didChange only.
14506 lsp::TextDocumentSyncCapability::Kind(_) => None,
14507 }
14508}
14509
14510/// Completion items are displayed in a `UniformList`.
14511/// Usually, those items are single-line strings, but in LSP responses,
14512/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14513/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14514/// 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,
14515/// breaking the completions menu presentation.
14516///
14517/// 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.
14518pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14519 let mut new_text = String::with_capacity(label.text.len());
14520 let mut offset_map = vec![0; label.text.len() + 1];
14521 let mut last_char_was_space = false;
14522 let mut new_idx = 0;
14523 let chars = label.text.char_indices().fuse();
14524 let mut newlines_removed = false;
14525
14526 for (idx, c) in chars {
14527 offset_map[idx] = new_idx;
14528
14529 match c {
14530 '\n' if last_char_was_space => {
14531 newlines_removed = true;
14532 }
14533 '\t' | ' ' if last_char_was_space => {}
14534 '\n' if !last_char_was_space => {
14535 new_text.push(' ');
14536 new_idx += 1;
14537 last_char_was_space = true;
14538 newlines_removed = true;
14539 }
14540 ' ' | '\t' => {
14541 new_text.push(' ');
14542 new_idx += 1;
14543 last_char_was_space = true;
14544 }
14545 _ => {
14546 new_text.push(c);
14547 new_idx += c.len_utf8();
14548 last_char_was_space = false;
14549 }
14550 }
14551 }
14552 offset_map[label.text.len()] = new_idx;
14553
14554 // Only modify the label if newlines were removed.
14555 if !newlines_removed {
14556 return;
14557 }
14558
14559 let last_index = new_idx;
14560 let mut run_ranges_errors = Vec::new();
14561 label.runs.retain_mut(|(range, _)| {
14562 match offset_map.get(range.start) {
14563 Some(&start) => range.start = start,
14564 None => {
14565 run_ranges_errors.push(range.clone());
14566 return false;
14567 }
14568 }
14569
14570 match offset_map.get(range.end) {
14571 Some(&end) => range.end = end,
14572 None => {
14573 run_ranges_errors.push(range.clone());
14574 range.end = last_index;
14575 }
14576 }
14577 true
14578 });
14579 if !run_ranges_errors.is_empty() {
14580 log::error!(
14581 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14582 label.text
14583 );
14584 }
14585
14586 let mut wrong_filter_range = None;
14587 if label.filter_range == (0..label.text.len()) {
14588 label.filter_range = 0..new_text.len();
14589 } else {
14590 let mut original_filter_range = Some(label.filter_range.clone());
14591 match offset_map.get(label.filter_range.start) {
14592 Some(&start) => label.filter_range.start = start,
14593 None => {
14594 wrong_filter_range = original_filter_range.take();
14595 label.filter_range.start = last_index;
14596 }
14597 }
14598
14599 match offset_map.get(label.filter_range.end) {
14600 Some(&end) => label.filter_range.end = end,
14601 None => {
14602 wrong_filter_range = original_filter_range.take();
14603 label.filter_range.end = last_index;
14604 }
14605 }
14606 }
14607 if let Some(wrong_filter_range) = wrong_filter_range {
14608 log::error!(
14609 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14610 label.text
14611 );
14612 }
14613
14614 label.text = new_text;
14615}