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;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 CodeLabelExt, Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff,
75 File as _, Language, LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate,
76 LspInstaller, ManifestDelegate, ManifestName, ModelineSettings, OffsetUtf16, Patch, PointUtf16,
77 TextBufferSnapshot, ToOffset, ToOffsetUtf16, ToPointUtf16, Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 },
81 modeline, point_to_lsp,
82 proto::{
83 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
84 serialize_anchor_range, serialize_version,
85 },
86 range_from_lsp, range_to_lsp,
87 row_chunk::RowChunk,
88};
89use lsp::{
90 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
91 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
92 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
93 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
94 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
95 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
96 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
97 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
98};
99use node_runtime::read_package_installed_version;
100use parking_lot::Mutex;
101use postage::{mpsc, sink::Sink, stream::Stream, watch};
102use rand::prelude::*;
103use rpc::{
104 AnyProtoClient, ErrorCode, ErrorExt as _,
105 proto::{LspRequestId, LspRequestMessage as _},
106};
107use semver::Version;
108use serde::Serialize;
109use serde_json::Value;
110use settings::{Settings, SettingsLocation, SettingsStore};
111use sha2::{Digest, Sha256};
112use snippet::Snippet;
113use std::{
114 any::TypeId,
115 borrow::Cow,
116 cell::RefCell,
117 cmp::{Ordering, Reverse},
118 collections::{VecDeque, hash_map},
119 convert::TryInto,
120 ffi::OsStr,
121 future::ready,
122 iter, mem,
123 ops::{ControlFlow, Range},
124 path::{self, Path, PathBuf},
125 pin::pin,
126 rc::Rc,
127 sync::{
128 Arc,
129 atomic::{self, AtomicUsize},
130 },
131 time::{Duration, Instant},
132 vec,
133};
134use sum_tree::Dimensions;
135use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
136
137use util::{
138 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
139 paths::{PathStyle, SanitizedPath, UrlExt},
140 post_inc,
141 redact::redact_command,
142 rel_path::RelPath,
143};
144
145pub use document_colors::DocumentColors;
146pub use folding_ranges::LspFoldingRange;
147pub use fs::*;
148pub use language::Location;
149pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
150#[cfg(any(test, feature = "test-support"))]
151pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
152#[cfg(any(test, feature = "test-support"))]
153pub use prettier::RANGE_FORMAT_SUFFIX as TEST_PRETTIER_RANGE_FORMAT_SUFFIX;
154pub use semantic_tokens::{
155 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
156};
157
158pub use worktree::{
159 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
160 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
161};
162
163const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
164pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
165const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
166const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
167static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
168
169#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
170pub enum ProgressToken {
171 Number(i32),
172 String(SharedString),
173}
174
175impl std::fmt::Display for ProgressToken {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 Self::Number(number) => write!(f, "{number}"),
179 Self::String(string) => write!(f, "{string}"),
180 }
181 }
182}
183
184impl ProgressToken {
185 fn from_lsp(value: lsp::NumberOrString) -> Self {
186 match value {
187 lsp::NumberOrString::Number(number) => Self::Number(number),
188 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
189 }
190 }
191
192 fn to_lsp(&self) -> lsp::NumberOrString {
193 match self {
194 Self::Number(number) => lsp::NumberOrString::Number(*number),
195 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
196 }
197 }
198
199 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
200 Some(match value.value? {
201 proto::progress_token::Value::Number(number) => Self::Number(number),
202 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
203 })
204 }
205
206 fn to_proto(&self) -> proto::ProgressToken {
207 proto::ProgressToken {
208 value: Some(match self {
209 Self::Number(number) => proto::progress_token::Value::Number(*number),
210 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
211 }),
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum FormatTrigger {
218 Save,
219 Manual,
220}
221
222pub enum LspFormatTarget {
223 Buffers,
224 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
229
230struct OpenLspBuffer(Entity<Buffer>);
231
232impl FormatTrigger {
233 fn from_proto(value: i32) -> FormatTrigger {
234 match value {
235 0 => FormatTrigger::Save,
236 1 => FormatTrigger::Manual,
237 _ => FormatTrigger::Save,
238 }
239 }
240}
241
242#[derive(Clone)]
243struct UnifiedLanguageServer {
244 id: LanguageServerId,
245 project_roots: HashSet<Arc<RelPath>>,
246}
247
248/// Settings that affect language server identity.
249///
250/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
251/// updated via `workspace/didChangeConfiguration` without restarting the server.
252#[derive(Clone, Debug, Hash, PartialEq, Eq)]
253struct LanguageServerSeedSettings {
254 binary: Option<BinarySettings>,
255 initialization_options: Option<serde_json::Value>,
256}
257
258#[derive(Clone, Debug, Hash, PartialEq, Eq)]
259struct LanguageServerSeed {
260 worktree_id: WorktreeId,
261 name: LanguageServerName,
262 toolchain: Option<Toolchain>,
263 settings: LanguageServerSeedSettings,
264}
265
266#[derive(Debug)]
267pub struct DocumentDiagnosticsUpdate<'a, D> {
268 pub diagnostics: D,
269 pub result_id: Option<SharedString>,
270 pub registration_id: Option<SharedString>,
271 pub server_id: LanguageServerId,
272 pub disk_based_sources: Cow<'a, [String]>,
273}
274
275pub struct DocumentDiagnostics {
276 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
277 document_abs_path: PathBuf,
278 version: Option<i32>,
279}
280
281#[derive(Default, Debug)]
282struct DynamicRegistrations {
283 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
284 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
285}
286
287pub struct LocalLspStore {
288 weak: WeakEntity<LspStore>,
289 pub worktree_store: Entity<WorktreeStore>,
290 toolchain_store: Entity<LocalToolchainStore>,
291 http_client: Arc<dyn HttpClient>,
292 environment: Entity<ProjectEnvironment>,
293 fs: Arc<dyn Fs>,
294 languages: Arc<LanguageRegistry>,
295 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
296 yarn: Entity<YarnPathStore>,
297 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
298 buffers_being_formatted: HashSet<BufferId>,
299 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
300 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
301 watched_manifest_filenames: HashSet<ManifestName>,
302 language_server_paths_watched_for_rename:
303 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
304 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
305 supplementary_language_servers:
306 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
307 prettier_store: Entity<PrettierStore>,
308 next_diagnostic_group_id: usize,
309 diagnostics: HashMap<
310 WorktreeId,
311 HashMap<
312 Arc<RelPath>,
313 Vec<(
314 LanguageServerId,
315 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
316 )>,
317 >,
318 >,
319 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
320 _subscription: gpui::Subscription,
321 lsp_tree: LanguageServerTree,
322 registered_buffers: HashMap<BufferId, usize>,
323 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
324 buffer_pull_diagnostics_result_ids: HashMap<
325 LanguageServerId,
326 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
327 >,
328 workspace_pull_diagnostics_result_ids: HashMap<
329 LanguageServerId,
330 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
331 >,
332 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
333
334 buffers_to_refresh_hash_set: HashSet<BufferId>,
335 buffers_to_refresh_queue: VecDeque<BufferId>,
336 _background_diagnostics_worker: Shared<Task<()>>,
337}
338
339impl LocalLspStore {
340 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
341 pub fn running_language_server_for_id(
342 &self,
343 id: LanguageServerId,
344 ) -> Option<&Arc<LanguageServer>> {
345 let language_server_state = self.language_servers.get(&id)?;
346
347 match language_server_state {
348 LanguageServerState::Running { server, .. } => Some(server),
349 LanguageServerState::Starting { .. } => None,
350 }
351 }
352
353 fn get_or_insert_language_server(
354 &mut self,
355 worktree_handle: &Entity<Worktree>,
356 delegate: Arc<LocalLspAdapterDelegate>,
357 disposition: &Arc<LaunchDisposition>,
358 language_name: &LanguageName,
359 cx: &mut App,
360 ) -> LanguageServerId {
361 let key = LanguageServerSeed {
362 worktree_id: worktree_handle.read(cx).id(),
363 name: disposition.server_name.clone(),
364 settings: LanguageServerSeedSettings {
365 binary: disposition.settings.binary.clone(),
366 initialization_options: disposition.settings.initialization_options.clone(),
367 },
368 toolchain: disposition.toolchain.clone(),
369 };
370 if let Some(state) = self.language_server_ids.get_mut(&key) {
371 state.project_roots.insert(disposition.path.path.clone());
372 state.id
373 } else {
374 let adapter = self
375 .languages
376 .lsp_adapters(language_name)
377 .into_iter()
378 .find(|adapter| adapter.name() == disposition.server_name)
379 .expect("To find LSP adapter");
380 let new_language_server_id = self.start_language_server(
381 worktree_handle,
382 delegate,
383 adapter,
384 disposition.settings.clone(),
385 key.clone(),
386 language_name.clone(),
387 cx,
388 );
389 if let Some(state) = self.language_server_ids.get_mut(&key) {
390 state.project_roots.insert(disposition.path.path.clone());
391 } else {
392 debug_assert!(
393 false,
394 "Expected `start_language_server` to ensure that `key` exists in a map"
395 );
396 }
397 new_language_server_id
398 }
399 }
400
401 fn start_language_server(
402 &mut self,
403 worktree_handle: &Entity<Worktree>,
404 delegate: Arc<LocalLspAdapterDelegate>,
405 adapter: Arc<CachedLspAdapter>,
406 settings: Arc<LspSettings>,
407 key: LanguageServerSeed,
408 language_name: LanguageName,
409 cx: &mut App,
410 ) -> LanguageServerId {
411 let worktree = worktree_handle.read(cx);
412
413 let worktree_id = worktree.id();
414 let worktree_abs_path = worktree.abs_path();
415 let toolchain = key.toolchain.clone();
416 let override_options = settings.initialization_options.clone();
417
418 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
419
420 let server_id = self.languages.next_language_server_id();
421 log::trace!(
422 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
423 adapter.name.0
424 );
425
426 let wait_until_worktree_trust =
427 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
428 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
429 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
430 });
431 if can_trust {
432 self.restricted_worktrees_tasks.remove(&worktree_id);
433 None
434 } else {
435 match self.restricted_worktrees_tasks.entry(worktree_id) {
436 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
437 hash_map::Entry::Vacant(v) => {
438 let (mut tx, rx) = watch::channel::<bool>();
439 let lsp_store = self.weak.clone();
440 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
441 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
442 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
443 tx.blocking_send(true).ok();
444 lsp_store
445 .update(cx, |lsp_store, _| {
446 if let Some(local_lsp_store) =
447 lsp_store.as_local_mut()
448 {
449 local_lsp_store
450 .restricted_worktrees_tasks
451 .remove(&worktree_id);
452 }
453 })
454 .ok();
455 }
456 }
457 });
458 v.insert((subscription, rx.clone()));
459 Some(rx)
460 }
461 }
462 }
463 });
464 let update_binary_status = wait_until_worktree_trust.is_none();
465
466 let binary = self.get_language_server_binary(
467 worktree_abs_path.clone(),
468 adapter.clone(),
469 settings,
470 toolchain.clone(),
471 delegate.clone(),
472 true,
473 wait_until_worktree_trust,
474 cx,
475 );
476 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
477
478 let pending_server = cx.spawn({
479 let adapter = adapter.clone();
480 let server_name = adapter.name.clone();
481 let stderr_capture = stderr_capture.clone();
482 #[cfg(any(test, feature = "test-support"))]
483 let lsp_store = self.weak.clone();
484 let pending_workspace_folders = pending_workspace_folders.clone();
485 async move |cx| {
486 let binary = binary.await?;
487 #[cfg(any(test, feature = "test-support"))]
488 if let Some(server) = lsp_store
489 .update(&mut cx.clone(), |this, cx| {
490 this.languages.create_fake_language_server(
491 server_id,
492 &server_name,
493 binary.clone(),
494 &mut cx.to_async(),
495 )
496 })
497 .ok()
498 .flatten()
499 {
500 return Ok(server);
501 }
502
503 let code_action_kinds = adapter.code_action_kinds();
504 lsp::LanguageServer::new(
505 stderr_capture,
506 server_id,
507 server_name,
508 binary,
509 &worktree_abs_path,
510 code_action_kinds,
511 Some(pending_workspace_folders),
512 cx,
513 )
514 }
515 });
516
517 let startup = {
518 let server_name = adapter.name.0.clone();
519 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
520 let key = key.clone();
521 let adapter = adapter.clone();
522 let lsp_store = self.weak.clone();
523 let pending_workspace_folders = pending_workspace_folders.clone();
524 let pull_diagnostics = ProjectSettings::get_global(cx)
525 .diagnostics
526 .lsp_pull_diagnostics
527 .enabled;
528 let settings_location = SettingsLocation {
529 worktree_id,
530 path: RelPath::empty(),
531 };
532 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
533 .language(Some(settings_location), Some(&language_name), cx)
534 .semantic_tokens
535 .use_tree_sitter();
536 cx.spawn(async move |cx| {
537 let result = async {
538 let language_server = pending_server.await?;
539
540 let workspace_config = Self::workspace_configuration_for_adapter(
541 adapter.adapter.clone(),
542 &delegate,
543 toolchain,
544 None,
545 cx,
546 )
547 .await?;
548
549 let mut initialization_options = Self::initialization_options_for_adapter(
550 adapter.adapter.clone(),
551 &delegate,
552 cx,
553 )
554 .await?;
555
556 match (&mut initialization_options, override_options) {
557 (Some(initialization_options), Some(override_options)) => {
558 merge_json_value_into(override_options, initialization_options);
559 }
560 (None, override_options) => initialization_options = override_options,
561 _ => {}
562 }
563
564 let initialization_params = cx.update(|cx| {
565 let mut params = language_server.default_initialize_params(
566 pull_diagnostics,
567 augments_syntax_tokens,
568 cx,
569 );
570 params.initialization_options = initialization_options;
571 adapter.adapter.prepare_initialize_params(params, cx)
572 })?;
573
574 Self::setup_lsp_messages(
575 lsp_store.clone(),
576 &language_server,
577 delegate.clone(),
578 adapter.clone(),
579 );
580
581 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
582 settings: workspace_config,
583 };
584 let language_server = cx
585 .update(|cx| {
586 let request_timeout = ProjectSettings::get_global(cx)
587 .global_lsp_settings
588 .get_request_timeout();
589
590 language_server.initialize(
591 initialization_params,
592 Arc::new(did_change_configuration_params.clone()),
593 request_timeout,
594 cx,
595 )
596 })
597 .await
598 .inspect_err(|_| {
599 if let Some(lsp_store) = lsp_store.upgrade() {
600 lsp_store.update(cx, |lsp_store, cx| {
601 lsp_store.cleanup_lsp_data(server_id);
602 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
603 });
604 }
605 })?;
606
607 language_server.notify::<lsp::notification::DidChangeConfiguration>(
608 did_change_configuration_params,
609 )?;
610
611 anyhow::Ok(language_server)
612 }
613 .await;
614
615 match result {
616 Ok(server) => {
617 lsp_store
618 .update(cx, |lsp_store, cx| {
619 lsp_store.insert_newly_running_language_server(
620 adapter,
621 server.clone(),
622 server_id,
623 key,
624 pending_workspace_folders,
625 cx,
626 );
627 })
628 .ok();
629 stderr_capture.lock().take();
630 Some(server)
631 }
632
633 Err(err) => {
634 let log = stderr_capture.lock().take().unwrap_or_default();
635 delegate.update_status(
636 adapter.name(),
637 BinaryStatus::Failed {
638 error: if log.is_empty() {
639 format!("{err:#}")
640 } else {
641 format!("{err:#}\n-- stderr --\n{log}")
642 },
643 },
644 );
645 log::error!(
646 "Failed to start language server {server_name:?}: {}",
647 redact_command(&format!("{err:?}"))
648 );
649 if !log.is_empty() {
650 log::error!("server stderr: {}", redact_command(&log));
651 }
652 None
653 }
654 }
655 })
656 };
657 let state = LanguageServerState::Starting {
658 startup,
659 pending_workspace_folders,
660 };
661
662 if update_binary_status {
663 self.languages
664 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
665 }
666
667 self.language_servers.insert(server_id, state);
668 self.language_server_ids
669 .entry(key)
670 .or_insert(UnifiedLanguageServer {
671 id: server_id,
672 project_roots: Default::default(),
673 });
674 server_id
675 }
676
677 fn get_language_server_binary(
678 &self,
679 worktree_abs_path: Arc<Path>,
680 adapter: Arc<CachedLspAdapter>,
681 settings: Arc<LspSettings>,
682 toolchain: Option<Toolchain>,
683 delegate: Arc<dyn LspAdapterDelegate>,
684 allow_binary_download: bool,
685 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
686 cx: &mut App,
687 ) -> Task<Result<LanguageServerBinary>> {
688 if let Some(settings) = &settings.binary
689 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
690 {
691 let settings = settings.clone();
692 let languages = self.languages.clone();
693 return cx.background_spawn(async move {
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 languages
712 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
713 }
714 let mut env = delegate.shell_env().await;
715 env.extend(settings.env.unwrap_or_default());
716
717 Ok(LanguageServerBinary {
718 path: delegate.resolve_relative_path(path),
719 env: Some(env),
720 arguments: settings
721 .arguments
722 .unwrap_or_default()
723 .iter()
724 .map(Into::into)
725 .collect(),
726 })
727 });
728 }
729 let lsp_binary_options = LanguageServerBinaryOptions {
730 allow_path_lookup: !settings
731 .binary
732 .as_ref()
733 .and_then(|b| b.ignore_system_version)
734 .unwrap_or_default(),
735 allow_binary_download,
736 pre_release: settings
737 .fetch
738 .as_ref()
739 .and_then(|f| f.pre_release)
740 .unwrap_or(false),
741 };
742
743 cx.spawn(async move |cx| {
744 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
745 let already_trusted = *wait_until_worktree_trust.borrow();
746 if !already_trusted {
747 log::info!(
748 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
749 adapter.name(),
750 );
751 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
752 if worktree_trusted {
753 break;
754 }
755 }
756 log::info!(
757 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
758 adapter.name(),
759 );
760 }
761 }
762
763 let (existing_binary, maybe_download_binary) = adapter
764 .clone()
765 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
766 .await
767 .await;
768
769 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
770
771 let mut binary = match (existing_binary, maybe_download_binary) {
772 (binary, None) => binary?,
773 (Err(_), Some(downloader)) => downloader.await?,
774 (Ok(existing_binary), Some(downloader)) => {
775 let mut download_timeout = cx
776 .background_executor()
777 .timer(SERVER_DOWNLOAD_TIMEOUT)
778 .fuse();
779 let mut downloader = downloader.fuse();
780 futures::select! {
781 _ = download_timeout => {
782 // Return existing binary and kick the existing work to the background.
783 cx.spawn(async move |_| downloader.await).detach();
784 Ok(existing_binary)
785 },
786 downloaded_or_existing_binary = downloader => {
787 // If download fails, this results in the existing binary.
788 downloaded_or_existing_binary
789 }
790 }?
791 }
792 };
793 let mut shell_env = delegate.shell_env().await;
794
795 shell_env.extend(binary.env.unwrap_or_default());
796
797 if let Some(settings) = settings.binary.as_ref() {
798 if let Some(arguments) = &settings.arguments {
799 binary.arguments = arguments.iter().map(Into::into).collect();
800 }
801 if let Some(env) = &settings.env {
802 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
803 }
804 }
805
806 binary.env = Some(shell_env);
807 Ok(binary)
808 })
809 }
810
811 fn setup_lsp_messages(
812 lsp_store: WeakEntity<LspStore>,
813 language_server: &LanguageServer,
814 delegate: Arc<dyn LspAdapterDelegate>,
815 adapter: Arc<CachedLspAdapter>,
816 ) {
817 let name = language_server.name();
818 let server_id = language_server.server_id();
819 language_server
820 .on_notification::<lsp::notification::PublishDiagnostics, _>({
821 let adapter = adapter.clone();
822 let this = lsp_store.clone();
823 move |mut params, cx| {
824 let adapter = adapter.clone();
825 if let Some(this) = this.upgrade() {
826 this.update(cx, |this, cx| {
827 adapter.process_diagnostics(&mut params, server_id);
828
829 this.merge_lsp_diagnostics(
830 DiagnosticSourceKind::Pushed,
831 vec![DocumentDiagnosticsUpdate {
832 server_id,
833 diagnostics: params,
834 result_id: None,
835 disk_based_sources: Cow::Borrowed(
836 &adapter.disk_based_diagnostic_sources,
837 ),
838 registration_id: None,
839 }],
840 |_, diagnostic, _cx| match diagnostic.source_kind {
841 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
842 adapter.retain_old_diagnostic(diagnostic)
843 }
844 DiagnosticSourceKind::Pulled => true,
845 },
846 cx,
847 )
848 .log_err();
849 });
850 }
851 }
852 })
853 .detach();
854 language_server
855 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
856 let adapter = adapter.adapter.clone();
857 let delegate = delegate.clone();
858 let this = lsp_store.clone();
859 move |params, cx| {
860 let adapter = adapter.clone();
861 let delegate = delegate.clone();
862 let this = this.clone();
863 let mut cx = cx.clone();
864 async move {
865 let toolchain_for_id = this
866 .update(&mut cx, |this, _| {
867 this.as_local()?.language_server_ids.iter().find_map(
868 |(seed, value)| {
869 (value.id == server_id).then(|| seed.toolchain.clone())
870 },
871 )
872 })?
873 .context("Expected the LSP store to be in a local mode")?;
874
875 let mut scope_uri_to_workspace_config = BTreeMap::new();
876 for item in ¶ms.items {
877 let scope_uri = item.scope_uri.clone();
878 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
879 scope_uri_to_workspace_config.entry(scope_uri.clone())
880 else {
881 // We've already queried workspace configuration of this URI.
882 continue;
883 };
884 let workspace_config = Self::workspace_configuration_for_adapter(
885 adapter.clone(),
886 &delegate,
887 toolchain_for_id.clone(),
888 scope_uri,
889 &mut cx,
890 )
891 .await?;
892 new_scope_uri.insert(workspace_config);
893 }
894
895 Ok(params
896 .items
897 .into_iter()
898 .filter_map(|item| {
899 let workspace_config =
900 scope_uri_to_workspace_config.get(&item.scope_uri)?;
901 if let Some(section) = &item.section {
902 Some(
903 workspace_config
904 .get(section)
905 .cloned()
906 .unwrap_or(serde_json::Value::Null),
907 )
908 } else {
909 Some(workspace_config.clone())
910 }
911 })
912 .collect())
913 }
914 }
915 })
916 .detach();
917
918 language_server
919 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
920 let this = lsp_store.clone();
921 move |_, cx| {
922 let this = this.clone();
923 let cx = cx.clone();
924 async move {
925 let Some(server) =
926 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
927 else {
928 return Ok(None);
929 };
930 let root = server.workspace_folders();
931 Ok(Some(
932 root.into_iter()
933 .map(|uri| WorkspaceFolder {
934 uri,
935 name: Default::default(),
936 })
937 .collect(),
938 ))
939 }
940 }
941 })
942 .detach();
943 // Even though we don't have handling for these requests, respond to them to
944 // avoid stalling any language server like `gopls` which waits for a response
945 // to these requests when initializing.
946 language_server
947 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
948 let this = lsp_store.clone();
949 move |params, cx| {
950 let this = this.clone();
951 let mut cx = cx.clone();
952 async move {
953 this.update(&mut cx, |this, _| {
954 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
955 {
956 status
957 .progress_tokens
958 .insert(ProgressToken::from_lsp(params.token));
959 }
960 })?;
961
962 Ok(())
963 }
964 }
965 })
966 .detach();
967
968 language_server
969 .on_request::<lsp::request::RegisterCapability, _, _>({
970 let lsp_store = lsp_store.clone();
971 move |params, cx| {
972 let lsp_store = lsp_store.clone();
973 let mut cx = cx.clone();
974 async move {
975 lsp_store
976 .update(&mut cx, |lsp_store, cx| {
977 if lsp_store.as_local().is_some() {
978 match lsp_store
979 .register_server_capabilities(server_id, params, cx)
980 {
981 Ok(()) => {}
982 Err(e) => {
983 log::error!(
984 "Failed to register server capabilities: {e:#}"
985 );
986 }
987 };
988 }
989 })
990 .ok();
991 Ok(())
992 }
993 }
994 })
995 .detach();
996
997 language_server
998 .on_request::<lsp::request::UnregisterCapability, _, _>({
999 let lsp_store = lsp_store.clone();
1000 move |params, cx| {
1001 let lsp_store = lsp_store.clone();
1002 let mut cx = cx.clone();
1003 async move {
1004 lsp_store
1005 .update(&mut cx, |lsp_store, cx| {
1006 if lsp_store.as_local().is_some() {
1007 match lsp_store
1008 .unregister_server_capabilities(server_id, params, cx)
1009 {
1010 Ok(()) => {}
1011 Err(e) => {
1012 log::error!(
1013 "Failed to unregister server capabilities: {e:#}"
1014 );
1015 }
1016 }
1017 }
1018 })
1019 .ok();
1020 Ok(())
1021 }
1022 }
1023 })
1024 .detach();
1025
1026 language_server
1027 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1028 let this = lsp_store.clone();
1029 move |params, cx| {
1030 let mut cx = cx.clone();
1031 let this = this.clone();
1032 async move {
1033 LocalLspStore::on_lsp_workspace_edit(
1034 this.clone(),
1035 params,
1036 server_id,
1037 &mut cx,
1038 )
1039 .await
1040 }
1041 }
1042 })
1043 .detach();
1044
1045 language_server
1046 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1047 let lsp_store = lsp_store.clone();
1048 let request_id = Arc::new(AtomicUsize::new(0));
1049 move |(), cx| {
1050 let lsp_store = lsp_store.clone();
1051 let request_id = request_id.clone();
1052 let mut cx = cx.clone();
1053 async move {
1054 lsp_store
1055 .update(&mut cx, |lsp_store, cx| {
1056 let request_id =
1057 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1058 cx.emit(LspStoreEvent::RefreshInlayHints {
1059 server_id,
1060 request_id,
1061 });
1062 lsp_store
1063 .downstream_client
1064 .as_ref()
1065 .map(|(client, project_id)| {
1066 client.send(proto::RefreshInlayHints {
1067 project_id: *project_id,
1068 server_id: server_id.to_proto(),
1069 request_id: request_id.map(|id| id as u64),
1070 })
1071 })
1072 })?
1073 .transpose()?;
1074 Ok(())
1075 }
1076 }
1077 })
1078 .detach();
1079
1080 language_server
1081 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1082 let this = lsp_store.clone();
1083 move |(), cx| {
1084 let this = this.clone();
1085 let mut cx = cx.clone();
1086 async move {
1087 this.update(&mut cx, |this, cx| {
1088 cx.emit(LspStoreEvent::RefreshCodeLens);
1089 this.downstream_client.as_ref().map(|(client, project_id)| {
1090 client.send(proto::RefreshCodeLens {
1091 project_id: *project_id,
1092 })
1093 })
1094 })?
1095 .transpose()?;
1096 Ok(())
1097 }
1098 }
1099 })
1100 .detach();
1101
1102 language_server
1103 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1104 let lsp_store = lsp_store.clone();
1105 let request_id = Arc::new(AtomicUsize::new(0));
1106 move |(), cx| {
1107 let lsp_store = lsp_store.clone();
1108 let request_id = request_id.clone();
1109 let mut cx = cx.clone();
1110 async move {
1111 lsp_store
1112 .update(&mut cx, |lsp_store, cx| {
1113 let request_id =
1114 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1115 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1116 server_id,
1117 request_id,
1118 });
1119 lsp_store
1120 .downstream_client
1121 .as_ref()
1122 .map(|(client, project_id)| {
1123 client.send(proto::RefreshSemanticTokens {
1124 project_id: *project_id,
1125 server_id: server_id.to_proto(),
1126 request_id: request_id.map(|id| id as u64),
1127 })
1128 })
1129 })?
1130 .transpose()?;
1131 Ok(())
1132 }
1133 }
1134 })
1135 .detach();
1136
1137 language_server
1138 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1139 let this = lsp_store.clone();
1140 move |(), cx| {
1141 let this = this.clone();
1142 let mut cx = cx.clone();
1143 async move {
1144 this.update(&mut cx, |lsp_store, cx| {
1145 lsp_store.pull_workspace_diagnostics(server_id);
1146 lsp_store
1147 .downstream_client
1148 .as_ref()
1149 .map(|(client, project_id)| {
1150 client.send(proto::PullWorkspaceDiagnostics {
1151 project_id: *project_id,
1152 server_id: server_id.to_proto(),
1153 })
1154 })
1155 .transpose()?;
1156 anyhow::Ok(
1157 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1158 )
1159 })??
1160 .await;
1161 Ok(())
1162 }
1163 }
1164 })
1165 .detach();
1166
1167 language_server
1168 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1169 let this = lsp_store.clone();
1170 let name = name.to_string();
1171 let adapter = adapter.clone();
1172 move |params, cx| {
1173 let this = this.clone();
1174 let name = name.to_string();
1175 let adapter = adapter.clone();
1176 let mut cx = cx.clone();
1177 async move {
1178 let actions = params.actions.unwrap_or_default();
1179 let message = params.message.clone();
1180 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1181 let level = match params.typ {
1182 lsp::MessageType::ERROR => PromptLevel::Critical,
1183 lsp::MessageType::WARNING => PromptLevel::Warning,
1184 _ => PromptLevel::Info,
1185 };
1186 let request = LanguageServerPromptRequest::new(
1187 level,
1188 params.message,
1189 actions,
1190 name.clone(),
1191 tx,
1192 );
1193
1194 let did_update = this
1195 .update(&mut cx, |_, cx| {
1196 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1197 })
1198 .is_ok();
1199 if did_update {
1200 let response = rx.recv().await.ok();
1201 if let Some(ref selected_action) = response {
1202 let context = language::PromptResponseContext {
1203 message,
1204 selected_action: selected_action.clone(),
1205 };
1206 adapter.process_prompt_response(&context, &mut cx)
1207 }
1208
1209 Ok(response)
1210 } else {
1211 Ok(None)
1212 }
1213 }
1214 }
1215 })
1216 .detach();
1217 language_server
1218 .on_notification::<lsp::notification::ShowMessage, _>({
1219 let this = lsp_store.clone();
1220 let name = name.to_string();
1221 move |params, cx| {
1222 let this = this.clone();
1223 let name = name.to_string();
1224 let mut cx = cx.clone();
1225
1226 let (tx, _) = smol::channel::bounded(1);
1227 let level = match params.typ {
1228 lsp::MessageType::ERROR => PromptLevel::Critical,
1229 lsp::MessageType::WARNING => PromptLevel::Warning,
1230 _ => PromptLevel::Info,
1231 };
1232 let request =
1233 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1234
1235 let _ = this.update(&mut cx, |_, cx| {
1236 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1237 });
1238 }
1239 })
1240 .detach();
1241
1242 let disk_based_diagnostics_progress_token =
1243 adapter.disk_based_diagnostics_progress_token.clone();
1244
1245 language_server
1246 .on_notification::<lsp::notification::Progress, _>({
1247 let this = lsp_store.clone();
1248 move |params, cx| {
1249 if let Some(this) = this.upgrade() {
1250 this.update(cx, |this, cx| {
1251 this.on_lsp_progress(
1252 params,
1253 server_id,
1254 disk_based_diagnostics_progress_token.clone(),
1255 cx,
1256 );
1257 });
1258 }
1259 }
1260 })
1261 .detach();
1262
1263 language_server
1264 .on_notification::<lsp::notification::LogMessage, _>({
1265 let this = lsp_store.clone();
1266 move |params, cx| {
1267 if let Some(this) = this.upgrade() {
1268 this.update(cx, |_, cx| {
1269 cx.emit(LspStoreEvent::LanguageServerLog(
1270 server_id,
1271 LanguageServerLogType::Log(params.typ),
1272 params.message,
1273 ));
1274 });
1275 }
1276 }
1277 })
1278 .detach();
1279
1280 language_server
1281 .on_notification::<lsp::notification::LogTrace, _>({
1282 let this = lsp_store.clone();
1283 move |params, cx| {
1284 let mut cx = cx.clone();
1285 if let Some(this) = this.upgrade() {
1286 this.update(&mut cx, |_, cx| {
1287 cx.emit(LspStoreEvent::LanguageServerLog(
1288 server_id,
1289 LanguageServerLogType::Trace {
1290 verbose_info: params.verbose,
1291 },
1292 params.message,
1293 ));
1294 });
1295 }
1296 }
1297 })
1298 .detach();
1299
1300 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1301 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1302 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1303 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1304 }
1305
1306 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1307 let shutdown_futures = self
1308 .language_servers
1309 .drain()
1310 .map(|(_, server_state)| Self::shutdown_server(server_state))
1311 .collect::<Vec<_>>();
1312
1313 async move {
1314 join_all(shutdown_futures).await;
1315 }
1316 }
1317
1318 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1319 match server_state {
1320 LanguageServerState::Running { server, .. } => {
1321 if let Some(shutdown) = server.shutdown() {
1322 shutdown.await;
1323 }
1324 }
1325 LanguageServerState::Starting { startup, .. } => {
1326 if let Some(server) = startup.await
1327 && let Some(shutdown) = server.shutdown()
1328 {
1329 shutdown.await;
1330 }
1331 }
1332 }
1333 Ok(())
1334 }
1335
1336 fn language_servers_for_worktree(
1337 &self,
1338 worktree_id: WorktreeId,
1339 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1340 self.language_server_ids
1341 .iter()
1342 .filter_map(move |(seed, state)| {
1343 if seed.worktree_id != worktree_id {
1344 return None;
1345 }
1346
1347 if let Some(LanguageServerState::Running { server, .. }) =
1348 self.language_servers.get(&state.id)
1349 {
1350 Some(server)
1351 } else {
1352 None
1353 }
1354 })
1355 }
1356
1357 fn language_server_ids_for_project_path(
1358 &self,
1359 project_path: ProjectPath,
1360 language: &Language,
1361 cx: &mut App,
1362 ) -> Vec<LanguageServerId> {
1363 let Some(worktree) = self
1364 .worktree_store
1365 .read(cx)
1366 .worktree_for_id(project_path.worktree_id, cx)
1367 else {
1368 return Vec::new();
1369 };
1370 let delegate: Arc<dyn ManifestDelegate> =
1371 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1372
1373 self.lsp_tree
1374 .get(
1375 project_path,
1376 language.name(),
1377 language.manifest(),
1378 &delegate,
1379 cx,
1380 )
1381 .collect::<Vec<_>>()
1382 }
1383
1384 fn language_server_ids_for_buffer(
1385 &self,
1386 buffer: &Buffer,
1387 cx: &mut App,
1388 ) -> Vec<LanguageServerId> {
1389 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1390 let worktree_id = file.worktree_id(cx);
1391
1392 let path: Arc<RelPath> = file
1393 .path()
1394 .parent()
1395 .map(Arc::from)
1396 .unwrap_or_else(|| file.path().clone());
1397 let worktree_path = ProjectPath { worktree_id, path };
1398 self.language_server_ids_for_project_path(worktree_path, language, cx)
1399 } else {
1400 Vec::new()
1401 }
1402 }
1403
1404 fn language_servers_for_buffer<'a>(
1405 &'a self,
1406 buffer: &'a Buffer,
1407 cx: &'a mut App,
1408 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1409 self.language_server_ids_for_buffer(buffer, cx)
1410 .into_iter()
1411 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1412 LanguageServerState::Running {
1413 adapter, server, ..
1414 } => Some((adapter, server)),
1415 _ => None,
1416 })
1417 }
1418
1419 async fn execute_code_action_kind_locally(
1420 lsp_store: WeakEntity<LspStore>,
1421 mut buffers: Vec<Entity<Buffer>>,
1422 kind: CodeActionKind,
1423 push_to_history: bool,
1424 cx: &mut AsyncApp,
1425 ) -> anyhow::Result<ProjectTransaction> {
1426 // Do not allow multiple concurrent code actions requests for the
1427 // same buffer.
1428 lsp_store.update(cx, |this, cx| {
1429 let this = this.as_local_mut().unwrap();
1430 buffers.retain(|buffer| {
1431 this.buffers_being_formatted
1432 .insert(buffer.read(cx).remote_id())
1433 });
1434 })?;
1435 let _cleanup = defer({
1436 let this = lsp_store.clone();
1437 let mut cx = cx.clone();
1438 let buffers = &buffers;
1439 move || {
1440 this.update(&mut cx, |this, cx| {
1441 let this = this.as_local_mut().unwrap();
1442 for buffer in buffers {
1443 this.buffers_being_formatted
1444 .remove(&buffer.read(cx).remote_id());
1445 }
1446 })
1447 .ok();
1448 }
1449 });
1450 let mut project_transaction = ProjectTransaction::default();
1451
1452 for buffer in &buffers {
1453 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1454 buffer.update(cx, |buffer, cx| {
1455 lsp_store
1456 .as_local()
1457 .unwrap()
1458 .language_servers_for_buffer(buffer, cx)
1459 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1460 .collect::<Vec<_>>()
1461 })
1462 })?;
1463 for (_, language_server) in adapters_and_servers.iter() {
1464 let actions = Self::get_server_code_actions_from_action_kinds(
1465 &lsp_store,
1466 language_server.server_id(),
1467 vec![kind.clone()],
1468 buffer,
1469 cx,
1470 )
1471 .await?;
1472 Self::execute_code_actions_on_server(
1473 &lsp_store,
1474 language_server,
1475 actions,
1476 push_to_history,
1477 &mut project_transaction,
1478 cx,
1479 )
1480 .await?;
1481 }
1482 }
1483 Ok(project_transaction)
1484 }
1485
1486 async fn format_locally(
1487 lsp_store: WeakEntity<LspStore>,
1488 mut buffers: Vec<FormattableBuffer>,
1489 push_to_history: bool,
1490 trigger: FormatTrigger,
1491 logger: zlog::Logger,
1492 cx: &mut AsyncApp,
1493 ) -> anyhow::Result<ProjectTransaction> {
1494 // Do not allow multiple concurrent formatting requests for the
1495 // same buffer.
1496 lsp_store.update(cx, |this, cx| {
1497 let this = this.as_local_mut().unwrap();
1498 buffers.retain(|buffer| {
1499 this.buffers_being_formatted
1500 .insert(buffer.handle.read(cx).remote_id())
1501 });
1502 })?;
1503
1504 let _cleanup = defer({
1505 let this = lsp_store.clone();
1506 let mut cx = cx.clone();
1507 let buffers = &buffers;
1508 move || {
1509 this.update(&mut cx, |this, cx| {
1510 let this = this.as_local_mut().unwrap();
1511 for buffer in buffers {
1512 this.buffers_being_formatted
1513 .remove(&buffer.handle.read(cx).remote_id());
1514 }
1515 })
1516 .ok();
1517 }
1518 });
1519
1520 let mut project_transaction = ProjectTransaction::default();
1521
1522 for buffer in &buffers {
1523 zlog::debug!(
1524 logger =>
1525 "formatting buffer '{:?}'",
1526 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1527 );
1528 // Create an empty transaction to hold all of the formatting edits.
1529 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1530 // ensure no transactions created while formatting are
1531 // grouped with the previous transaction in the history
1532 // based on the transaction group interval
1533 buffer.finalize_last_transaction();
1534 buffer
1535 .start_transaction()
1536 .context("transaction already open")?;
1537 buffer.end_transaction(cx);
1538 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1539 buffer.finalize_last_transaction();
1540 anyhow::Ok(transaction_id)
1541 })?;
1542
1543 let result = Self::format_buffer_locally(
1544 lsp_store.clone(),
1545 buffer,
1546 formatting_transaction_id,
1547 trigger,
1548 logger,
1549 cx,
1550 )
1551 .await;
1552
1553 buffer.handle.update(cx, |buffer, cx| {
1554 let Some(formatting_transaction) =
1555 buffer.get_transaction(formatting_transaction_id).cloned()
1556 else {
1557 zlog::warn!(logger => "no formatting transaction");
1558 return;
1559 };
1560 if formatting_transaction.edit_ids.is_empty() {
1561 zlog::debug!(logger => "no changes made while formatting");
1562 buffer.forget_transaction(formatting_transaction_id);
1563 return;
1564 }
1565 if !push_to_history {
1566 zlog::trace!(logger => "forgetting format transaction");
1567 buffer.forget_transaction(formatting_transaction.id);
1568 }
1569 project_transaction
1570 .0
1571 .insert(cx.entity(), formatting_transaction);
1572 });
1573
1574 result?;
1575 }
1576
1577 Ok(project_transaction)
1578 }
1579
1580 async fn format_buffer_locally(
1581 lsp_store: WeakEntity<LspStore>,
1582 buffer: &FormattableBuffer,
1583 formatting_transaction_id: clock::Lamport,
1584 trigger: FormatTrigger,
1585 logger: zlog::Logger,
1586 cx: &mut AsyncApp,
1587 ) -> Result<()> {
1588 let (adapters_and_servers, settings, request_timeout) =
1589 lsp_store.update(cx, |lsp_store, cx| {
1590 buffer.handle.update(cx, |buffer, cx| {
1591 let adapters_and_servers = lsp_store
1592 .as_local()
1593 .unwrap()
1594 .language_servers_for_buffer(buffer, cx)
1595 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1596 .collect::<Vec<_>>();
1597 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1598 let request_timeout = ProjectSettings::get_global(cx)
1599 .global_lsp_settings
1600 .get_request_timeout();
1601 (adapters_and_servers, settings, request_timeout)
1602 })
1603 })?;
1604
1605 // handle whitespace formatting
1606 if settings.remove_trailing_whitespace_on_save {
1607 zlog::trace!(logger => "removing trailing whitespace");
1608 let diff = buffer
1609 .handle
1610 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1611 .await;
1612 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1613 buffer.apply_diff(diff, cx);
1614 })?;
1615 }
1616
1617 if settings.ensure_final_newline_on_save {
1618 zlog::trace!(logger => "ensuring final newline");
1619 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1620 buffer.ensure_final_newline(cx);
1621 })?;
1622 }
1623
1624 // Formatter for `code_actions_on_format` that runs before
1625 // the rest of the formatters
1626 let mut code_actions_on_format_formatters = None;
1627 let should_run_code_actions_on_format = !matches!(
1628 (trigger, &settings.format_on_save),
1629 (FormatTrigger::Save, &FormatOnSave::Off)
1630 );
1631 if should_run_code_actions_on_format {
1632 let have_code_actions_to_run_on_format = settings
1633 .code_actions_on_format
1634 .values()
1635 .any(|enabled| *enabled);
1636 if have_code_actions_to_run_on_format {
1637 zlog::trace!(logger => "going to run code actions on format");
1638 code_actions_on_format_formatters = Some(
1639 settings
1640 .code_actions_on_format
1641 .iter()
1642 .filter_map(|(action, enabled)| enabled.then_some(action))
1643 .cloned()
1644 .map(Formatter::CodeAction)
1645 .collect::<Vec<_>>(),
1646 );
1647 }
1648 }
1649
1650 let formatters = match (trigger, &settings.format_on_save) {
1651 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1652 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1653 settings.formatter.as_ref()
1654 }
1655 };
1656
1657 let formatters = code_actions_on_format_formatters
1658 .iter()
1659 .flatten()
1660 .chain(formatters);
1661
1662 for formatter in formatters {
1663 let formatter = if formatter == &Formatter::Auto {
1664 if settings.prettier.allowed {
1665 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1666 &Formatter::Prettier
1667 } else {
1668 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1669 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1670 }
1671 } else {
1672 formatter
1673 };
1674 if let Err(err) = Self::apply_formatter(
1675 formatter,
1676 &lsp_store,
1677 buffer,
1678 formatting_transaction_id,
1679 &adapters_and_servers,
1680 &settings,
1681 request_timeout,
1682 logger,
1683 cx,
1684 )
1685 .await
1686 {
1687 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1688 }
1689 }
1690
1691 Ok(())
1692 }
1693
1694 async fn apply_formatter(
1695 formatter: &Formatter,
1696 lsp_store: &WeakEntity<LspStore>,
1697 buffer: &FormattableBuffer,
1698 formatting_transaction_id: clock::Lamport,
1699 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1700 settings: &LanguageSettings,
1701 request_timeout: Duration,
1702 logger: zlog::Logger,
1703 cx: &mut AsyncApp,
1704 ) -> anyhow::Result<()> {
1705 match formatter {
1706 Formatter::None => {
1707 zlog::trace!(logger => "skipping formatter 'none'");
1708 return Ok(());
1709 }
1710 Formatter::Auto => {
1711 debug_panic!("Auto resolved above");
1712 return Ok(());
1713 }
1714 Formatter::Prettier => {
1715 let logger = zlog::scoped!(logger => "prettier");
1716 zlog::trace!(logger => "formatting");
1717 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1718
1719 // When selection ranges are provided (via FormatSelections), we pass the
1720 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1721 // After diffing, we filter the resulting edits to only keep those that
1722 // overlap with the original byte-level selection ranges.
1723 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1724 Some(ranges) if !ranges.is_empty() => {
1725 let (utf16_range, byte_ranges) =
1726 buffer.handle.read_with(cx, |buffer, _cx| {
1727 let snapshot = buffer.snapshot();
1728 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1729 let mut max_end_utf16 = OffsetUtf16(0);
1730 let mut byte_ranges = Vec::with_capacity(ranges.len());
1731 for range in ranges {
1732 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1733 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1734 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1735 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1736
1737 let start_byte = range.start.to_offset(&snapshot);
1738 let end_byte = range.end.to_offset(&snapshot);
1739 byte_ranges.push(start_byte..end_byte);
1740 }
1741 (min_start_utf16..max_end_utf16, byte_ranges)
1742 });
1743 (Some(utf16_range), Some(byte_ranges))
1744 }
1745 _ => (None, None),
1746 };
1747
1748 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1749 lsp_store.prettier_store().unwrap().downgrade()
1750 })?;
1751 let diff = prettier_store::format_with_prettier(
1752 &prettier,
1753 &buffer.handle,
1754 range_utf16,
1755 cx,
1756 )
1757 .await
1758 .transpose()?;
1759 let Some(mut diff) = diff else {
1760 zlog::trace!(logger => "No changes");
1761 return Ok(());
1762 };
1763
1764 if let Some(byte_ranges) = byte_ranges {
1765 diff.edits.retain(|(edit_range, _)| {
1766 byte_ranges.iter().any(|selection_range| {
1767 edit_range.start < selection_range.end
1768 && edit_range.end > selection_range.start
1769 })
1770 });
1771 if diff.edits.is_empty() {
1772 zlog::trace!(logger => "No changes within selection");
1773 return Ok(());
1774 }
1775 }
1776
1777 extend_formatting_transaction(
1778 buffer,
1779 formatting_transaction_id,
1780 cx,
1781 |buffer, cx| {
1782 buffer.apply_diff(diff, cx);
1783 },
1784 )?;
1785 }
1786 Formatter::External { command, arguments } => {
1787 let logger = zlog::scoped!(logger => "command");
1788
1789 if buffer.ranges.is_some() {
1790 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1791 return Ok(());
1792 }
1793
1794 zlog::trace!(logger => "formatting");
1795 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1796
1797 let diff =
1798 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1799 .await
1800 .with_context(|| {
1801 format!("Failed to format buffer via external command: {}", command)
1802 })?;
1803 let Some(diff) = diff else {
1804 zlog::trace!(logger => "No changes");
1805 return Ok(());
1806 };
1807
1808 extend_formatting_transaction(
1809 buffer,
1810 formatting_transaction_id,
1811 cx,
1812 |buffer, cx| {
1813 buffer.apply_diff(diff, cx);
1814 },
1815 )?;
1816 }
1817 Formatter::LanguageServer(specifier) => {
1818 let logger = zlog::scoped!(logger => "language-server");
1819 zlog::trace!(logger => "formatting");
1820 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1821
1822 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1823 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1824 return Ok(());
1825 };
1826
1827 let language_server = match specifier {
1828 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1829 adapters_and_servers.iter().find_map(|(adapter, server)| {
1830 if adapter.name.0.as_ref() == name {
1831 Some(server.clone())
1832 } else {
1833 None
1834 }
1835 })
1836 }
1837 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1838 .iter()
1839 .find(|(_, server)| Self::server_supports_formatting(server))
1840 .map(|(_, server)| server.clone()),
1841 };
1842
1843 let Some(language_server) = language_server else {
1844 log::debug!(
1845 "No language server found to format buffer '{:?}'. Skipping",
1846 buffer_path_abs.as_path().to_string_lossy()
1847 );
1848 return Ok(());
1849 };
1850
1851 zlog::trace!(
1852 logger =>
1853 "Formatting buffer '{:?}' using language server '{:?}'",
1854 buffer_path_abs.as_path().to_string_lossy(),
1855 language_server.name()
1856 );
1857
1858 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1859 zlog::trace!(logger => "formatting ranges");
1860 Self::format_ranges_via_lsp(
1861 &lsp_store,
1862 &buffer.handle,
1863 ranges,
1864 buffer_path_abs,
1865 &language_server,
1866 &settings,
1867 cx,
1868 )
1869 .await
1870 .context("Failed to format ranges via language server")?
1871 } else {
1872 zlog::trace!(logger => "formatting full");
1873 Self::format_via_lsp(
1874 &lsp_store,
1875 &buffer.handle,
1876 buffer_path_abs,
1877 &language_server,
1878 &settings,
1879 cx,
1880 )
1881 .await
1882 .context("failed to format via language server")?
1883 };
1884
1885 if edits.is_empty() {
1886 zlog::trace!(logger => "No changes");
1887 return Ok(());
1888 }
1889 extend_formatting_transaction(
1890 buffer,
1891 formatting_transaction_id,
1892 cx,
1893 |buffer, cx| {
1894 buffer.edit(edits, None, cx);
1895 },
1896 )?;
1897 }
1898 Formatter::CodeAction(code_action_name) => {
1899 let logger = zlog::scoped!(logger => "code-actions");
1900 zlog::trace!(logger => "formatting");
1901 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1902
1903 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1904 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1905 return Ok(());
1906 };
1907
1908 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1909 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1910
1911 let mut actions_and_servers = Vec::new();
1912
1913 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1914 let actions_result = Self::get_server_code_actions_from_action_kinds(
1915 &lsp_store,
1916 language_server.server_id(),
1917 vec![code_action_kind.clone()],
1918 &buffer.handle,
1919 cx,
1920 )
1921 .await
1922 .with_context(|| {
1923 format!(
1924 "Failed to resolve code action {:?} with language server {}",
1925 code_action_kind,
1926 language_server.name()
1927 )
1928 });
1929 let Ok(actions) = actions_result else {
1930 // note: it may be better to set result to the error and break formatters here
1931 // but for now we try to execute the actions that we can resolve and skip the rest
1932 zlog::error!(
1933 logger =>
1934 "Failed to resolve code action {:?} with language server {}",
1935 code_action_kind,
1936 language_server.name()
1937 );
1938 continue;
1939 };
1940 for action in actions {
1941 actions_and_servers.push((action, index));
1942 }
1943 }
1944
1945 if actions_and_servers.is_empty() {
1946 zlog::warn!(logger => "No code actions were resolved, continuing");
1947 return Ok(());
1948 }
1949
1950 'actions: for (mut action, server_index) in actions_and_servers {
1951 let server = &adapters_and_servers[server_index].1;
1952
1953 let describe_code_action = |action: &CodeAction| {
1954 format!(
1955 "code action '{}' with title \"{}\" on server {}",
1956 action
1957 .lsp_action
1958 .action_kind()
1959 .unwrap_or("unknown".into())
1960 .as_str(),
1961 action.lsp_action.title(),
1962 server.name(),
1963 )
1964 };
1965
1966 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1967
1968 if let Err(err) =
1969 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1970 {
1971 zlog::error!(
1972 logger =>
1973 "Failed to resolve {}. Error: {}",
1974 describe_code_action(&action),
1975 err
1976 );
1977 continue;
1978 }
1979
1980 if let Some(edit) = action.lsp_action.edit().cloned() {
1981 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1982 // but filters out and logs warnings for code actions that require unreasonably
1983 // difficult handling on our part, such as:
1984 // - applying edits that call commands
1985 // which can result in arbitrary workspace edits being sent from the server that
1986 // have no way of being tied back to the command that initiated them (i.e. we
1987 // can't know which edits are part of the format request, or if the server is done sending
1988 // actions in response to the command)
1989 // - actions that create/delete/modify/rename files other than the one we are formatting
1990 // as we then would need to handle such changes correctly in the local history as well
1991 // as the remote history through the ProjectTransaction
1992 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1993 // Supporting these actions is not impossible, but not supported as of yet.
1994 if edit.changes.is_none() && edit.document_changes.is_none() {
1995 zlog::trace!(
1996 logger =>
1997 "No changes for code action. Skipping {}",
1998 describe_code_action(&action),
1999 );
2000 continue;
2001 }
2002
2003 let mut operations = Vec::new();
2004 if let Some(document_changes) = edit.document_changes {
2005 match document_changes {
2006 lsp::DocumentChanges::Edits(edits) => operations.extend(
2007 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2008 ),
2009 lsp::DocumentChanges::Operations(ops) => operations = ops,
2010 }
2011 } else if let Some(changes) = edit.changes {
2012 operations.extend(changes.into_iter().map(|(uri, edits)| {
2013 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2014 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2015 uri,
2016 version: None,
2017 },
2018 edits: edits.into_iter().map(Edit::Plain).collect(),
2019 })
2020 }));
2021 }
2022
2023 let mut edits = Vec::with_capacity(operations.len());
2024
2025 if operations.is_empty() {
2026 zlog::trace!(
2027 logger =>
2028 "No changes for code action. Skipping {}",
2029 describe_code_action(&action),
2030 );
2031 continue;
2032 }
2033 for operation in operations {
2034 let op = match operation {
2035 lsp::DocumentChangeOperation::Edit(op) => op,
2036 lsp::DocumentChangeOperation::Op(_) => {
2037 zlog::warn!(
2038 logger =>
2039 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2040 describe_code_action(&action),
2041 );
2042 continue 'actions;
2043 }
2044 };
2045 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2046 zlog::warn!(
2047 logger =>
2048 "Failed to convert URI '{:?}' to file path. Skipping {}",
2049 &op.text_document.uri,
2050 describe_code_action(&action),
2051 );
2052 continue 'actions;
2053 };
2054 if &file_path != buffer_path_abs {
2055 zlog::warn!(
2056 logger =>
2057 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2058 file_path,
2059 buffer_path_abs,
2060 describe_code_action(&action),
2061 );
2062 continue 'actions;
2063 }
2064
2065 let mut lsp_edits = Vec::new();
2066 for edit in op.edits {
2067 match edit {
2068 Edit::Plain(edit) => {
2069 if !lsp_edits.contains(&edit) {
2070 lsp_edits.push(edit);
2071 }
2072 }
2073 Edit::Annotated(edit) => {
2074 if !lsp_edits.contains(&edit.text_edit) {
2075 lsp_edits.push(edit.text_edit);
2076 }
2077 }
2078 Edit::Snippet(_) => {
2079 zlog::warn!(
2080 logger =>
2081 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2082 describe_code_action(&action),
2083 );
2084 continue 'actions;
2085 }
2086 }
2087 }
2088 let edits_result = lsp_store
2089 .update(cx, |lsp_store, cx| {
2090 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2091 &buffer.handle,
2092 lsp_edits,
2093 server.server_id(),
2094 op.text_document.version,
2095 cx,
2096 )
2097 })?
2098 .await;
2099 let Ok(resolved_edits) = edits_result else {
2100 zlog::warn!(
2101 logger =>
2102 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2103 buffer_path_abs.as_path(),
2104 describe_code_action(&action),
2105 );
2106 continue 'actions;
2107 };
2108 edits.extend(resolved_edits);
2109 }
2110
2111 if edits.is_empty() {
2112 zlog::warn!(logger => "No edits resolved from LSP");
2113 continue;
2114 }
2115
2116 extend_formatting_transaction(
2117 buffer,
2118 formatting_transaction_id,
2119 cx,
2120 |buffer, cx| {
2121 zlog::info!(
2122 "Applying edits {edits:?}. Content: {:?}",
2123 buffer.text()
2124 );
2125 buffer.edit(edits, None, cx);
2126 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2127 },
2128 )?;
2129 }
2130
2131 let Some(command) = action.lsp_action.command() else {
2132 continue;
2133 };
2134
2135 zlog::warn!(
2136 logger =>
2137 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2138 &command.command,
2139 );
2140
2141 let server_capabilities = server.capabilities();
2142 let available_commands = server_capabilities
2143 .execute_command_provider
2144 .as_ref()
2145 .map(|options| options.commands.as_slice())
2146 .unwrap_or_default();
2147 if !available_commands.contains(&command.command) {
2148 zlog::warn!(
2149 logger =>
2150 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2151 command.command,
2152 server.name(),
2153 );
2154 continue;
2155 }
2156
2157 extend_formatting_transaction(
2158 buffer,
2159 formatting_transaction_id,
2160 cx,
2161 |_, _| {},
2162 )?;
2163 zlog::info!(logger => "Executing command {}", &command.command);
2164
2165 lsp_store.update(cx, |this, _| {
2166 this.as_local_mut()
2167 .unwrap()
2168 .last_workspace_edits_by_language_server
2169 .remove(&server.server_id());
2170 })?;
2171
2172 let execute_command_result = server
2173 .request::<lsp::request::ExecuteCommand>(
2174 lsp::ExecuteCommandParams {
2175 command: command.command.clone(),
2176 arguments: command.arguments.clone().unwrap_or_default(),
2177 ..Default::default()
2178 },
2179 request_timeout,
2180 )
2181 .await
2182 .into_response();
2183
2184 if execute_command_result.is_err() {
2185 zlog::error!(
2186 logger =>
2187 "Failed to execute command '{}' as part of {}",
2188 &command.command,
2189 describe_code_action(&action),
2190 );
2191 continue 'actions;
2192 }
2193
2194 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2195 this.as_local_mut()
2196 .unwrap()
2197 .last_workspace_edits_by_language_server
2198 .remove(&server.server_id())
2199 .unwrap_or_default()
2200 })?;
2201
2202 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2203 {
2204 zlog::trace!(
2205 logger =>
2206 "Successfully captured {} edits that resulted from command {}",
2207 transaction.edit_ids.len(),
2208 &command.command,
2209 );
2210 let transaction_id_project_transaction = transaction.id;
2211 buffer.handle.update(cx, |buffer, _| {
2212 // it may have been removed from history if push_to_history was
2213 // false in deserialize_workspace_edit. If so push it so we
2214 // can merge it with the format transaction
2215 // and pop the combined transaction off the history stack
2216 // later if push_to_history is false
2217 if buffer.get_transaction(transaction.id).is_none() {
2218 buffer.push_transaction(transaction, Instant::now());
2219 }
2220 buffer.merge_transactions(
2221 transaction_id_project_transaction,
2222 formatting_transaction_id,
2223 );
2224 });
2225 }
2226
2227 if project_transaction_command.0.is_empty() {
2228 continue;
2229 }
2230
2231 let mut extra_buffers = String::new();
2232 for buffer in project_transaction_command.0.keys() {
2233 buffer.read_with(cx, |b, cx| {
2234 let Some(path) = b.project_path(cx) else {
2235 return;
2236 };
2237
2238 if !extra_buffers.is_empty() {
2239 extra_buffers.push_str(", ");
2240 }
2241 extra_buffers.push_str(path.path.as_unix_str());
2242 });
2243 }
2244 zlog::warn!(
2245 logger =>
2246 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2247 &command.command,
2248 extra_buffers,
2249 );
2250 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2251 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2252 // add it so it's included, and merge it into the format transaction when its created later
2253 }
2254 }
2255 }
2256
2257 Ok(())
2258 }
2259
2260 pub async fn format_ranges_via_lsp(
2261 this: &WeakEntity<LspStore>,
2262 buffer_handle: &Entity<Buffer>,
2263 ranges: &[Range<Anchor>],
2264 abs_path: &Path,
2265 language_server: &Arc<LanguageServer>,
2266 settings: &LanguageSettings,
2267 cx: &mut AsyncApp,
2268 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2269 let capabilities = &language_server.capabilities();
2270 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2271 if range_formatting_provider == Some(&OneOf::Left(false)) {
2272 anyhow::bail!(
2273 "{} language server does not support range formatting",
2274 language_server.name()
2275 );
2276 }
2277
2278 let uri = file_path_to_lsp_url(abs_path)?;
2279 let text_document = lsp::TextDocumentIdentifier::new(uri);
2280
2281 let request_timeout = cx.update(|app| {
2282 ProjectSettings::get_global(app)
2283 .global_lsp_settings
2284 .get_request_timeout()
2285 });
2286 let lsp_edits = {
2287 let mut lsp_ranges = Vec::new();
2288 this.update(cx, |_this, cx| {
2289 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2290 // not have been sent to the language server. This seems like a fairly systemic
2291 // issue, though, the resolution probably is not specific to formatting.
2292 //
2293 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2294 // LSP.
2295 let snapshot = buffer_handle.read(cx).snapshot();
2296 for range in ranges {
2297 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2298 }
2299 anyhow::Ok(())
2300 })??;
2301
2302 let mut edits = None;
2303 for range in lsp_ranges {
2304 if let Some(mut edit) = language_server
2305 .request::<lsp::request::RangeFormatting>(
2306 lsp::DocumentRangeFormattingParams {
2307 text_document: text_document.clone(),
2308 range,
2309 options: lsp_command::lsp_formatting_options(settings),
2310 work_done_progress_params: Default::default(),
2311 },
2312 request_timeout,
2313 )
2314 .await
2315 .into_response()?
2316 {
2317 edits.get_or_insert_with(Vec::new).append(&mut edit);
2318 }
2319 }
2320 edits
2321 };
2322
2323 if let Some(lsp_edits) = lsp_edits {
2324 this.update(cx, |this, cx| {
2325 this.as_local_mut().unwrap().edits_from_lsp(
2326 buffer_handle,
2327 lsp_edits,
2328 language_server.server_id(),
2329 None,
2330 cx,
2331 )
2332 })?
2333 .await
2334 } else {
2335 Ok(Vec::with_capacity(0))
2336 }
2337 }
2338
2339 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2340 let capabilities = server.capabilities();
2341 let formatting = capabilities.document_formatting_provider.as_ref();
2342 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2343 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2344 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2345 }
2346
2347 async fn format_via_lsp(
2348 this: &WeakEntity<LspStore>,
2349 buffer: &Entity<Buffer>,
2350 abs_path: &Path,
2351 language_server: &Arc<LanguageServer>,
2352 settings: &LanguageSettings,
2353 cx: &mut AsyncApp,
2354 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2355 let logger = zlog::scoped!("lsp_format");
2356 zlog::debug!(logger => "Formatting via LSP");
2357
2358 let uri = file_path_to_lsp_url(abs_path)?;
2359 let text_document = lsp::TextDocumentIdentifier::new(uri);
2360 let capabilities = &language_server.capabilities();
2361
2362 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2363 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2364
2365 let request_timeout = cx.update(|app| {
2366 ProjectSettings::get_global(app)
2367 .global_lsp_settings
2368 .get_request_timeout()
2369 });
2370
2371 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2372 let _timer = zlog::time!(logger => "format-full");
2373 language_server
2374 .request::<lsp::request::Formatting>(
2375 lsp::DocumentFormattingParams {
2376 text_document,
2377 options: lsp_command::lsp_formatting_options(settings),
2378 work_done_progress_params: Default::default(),
2379 },
2380 request_timeout,
2381 )
2382 .await
2383 .into_response()?
2384 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2385 let _timer = zlog::time!(logger => "format-range");
2386 let buffer_start = lsp::Position::new(0, 0);
2387 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2388 language_server
2389 .request::<lsp::request::RangeFormatting>(
2390 lsp::DocumentRangeFormattingParams {
2391 text_document: text_document.clone(),
2392 range: lsp::Range::new(buffer_start, buffer_end),
2393 options: lsp_command::lsp_formatting_options(settings),
2394 work_done_progress_params: Default::default(),
2395 },
2396 request_timeout,
2397 )
2398 .await
2399 .into_response()?
2400 } else {
2401 None
2402 };
2403
2404 if let Some(lsp_edits) = lsp_edits {
2405 this.update(cx, |this, cx| {
2406 this.as_local_mut().unwrap().edits_from_lsp(
2407 buffer,
2408 lsp_edits,
2409 language_server.server_id(),
2410 None,
2411 cx,
2412 )
2413 })?
2414 .await
2415 } else {
2416 Ok(Vec::with_capacity(0))
2417 }
2418 }
2419
2420 async fn format_via_external_command(
2421 buffer: &FormattableBuffer,
2422 command: &str,
2423 arguments: Option<&[String]>,
2424 cx: &mut AsyncApp,
2425 ) -> Result<Option<Diff>> {
2426 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2427 let file = File::from_dyn(buffer.file())?;
2428 let worktree = file.worktree.read(cx);
2429 let mut worktree_path = worktree.abs_path().to_path_buf();
2430 if worktree.root_entry()?.is_file() {
2431 worktree_path.pop();
2432 }
2433 Some(worktree_path)
2434 });
2435
2436 use util::command::Stdio;
2437 let mut child = util::command::new_command(command);
2438
2439 if let Some(buffer_env) = buffer.env.as_ref() {
2440 child.envs(buffer_env);
2441 }
2442
2443 if let Some(working_dir_path) = working_dir_path {
2444 child.current_dir(working_dir_path);
2445 }
2446
2447 if let Some(arguments) = arguments {
2448 child.args(arguments.iter().map(|arg| {
2449 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2450 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2451 } else {
2452 arg.replace("{buffer_path}", "Untitled")
2453 }
2454 }));
2455 }
2456
2457 let mut child = child
2458 .stdin(Stdio::piped())
2459 .stdout(Stdio::piped())
2460 .stderr(Stdio::piped())
2461 .spawn()?;
2462
2463 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2464 let text = buffer
2465 .handle
2466 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2467 for chunk in text.chunks() {
2468 stdin.write_all(chunk.as_bytes()).await?;
2469 }
2470 stdin.flush().await?;
2471
2472 let output = child.output().await?;
2473 anyhow::ensure!(
2474 output.status.success(),
2475 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2476 output.status.code(),
2477 String::from_utf8_lossy(&output.stdout),
2478 String::from_utf8_lossy(&output.stderr),
2479 );
2480
2481 let stdout = String::from_utf8(output.stdout)?;
2482 Ok(Some(
2483 buffer
2484 .handle
2485 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2486 .await,
2487 ))
2488 }
2489
2490 async fn try_resolve_code_action(
2491 lang_server: &LanguageServer,
2492 action: &mut CodeAction,
2493 request_timeout: Duration,
2494 ) -> anyhow::Result<()> {
2495 match &mut action.lsp_action {
2496 LspAction::Action(lsp_action) => {
2497 if !action.resolved
2498 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2499 && lsp_action.data.is_some()
2500 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2501 {
2502 **lsp_action = lang_server
2503 .request::<lsp::request::CodeActionResolveRequest>(
2504 *lsp_action.clone(),
2505 request_timeout,
2506 )
2507 .await
2508 .into_response()?;
2509 }
2510 }
2511 LspAction::CodeLens(lens) => {
2512 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2513 *lens = lang_server
2514 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2515 .await
2516 .into_response()?;
2517 }
2518 }
2519 LspAction::Command(_) => {}
2520 }
2521
2522 action.resolved = true;
2523 anyhow::Ok(())
2524 }
2525
2526 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2527 let buffer = buffer_handle.read(cx);
2528
2529 let file = buffer.file().cloned();
2530
2531 let Some(file) = File::from_dyn(file.as_ref()) else {
2532 return;
2533 };
2534 if !file.is_local() {
2535 return;
2536 }
2537 let path = ProjectPath::from_file(file, cx);
2538 let worktree_id = file.worktree_id(cx);
2539 let language = buffer.language().cloned();
2540
2541 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2542 for (server_id, diagnostics) in
2543 diagnostics.get(file.path()).cloned().unwrap_or_default()
2544 {
2545 self.update_buffer_diagnostics(
2546 buffer_handle,
2547 server_id,
2548 None,
2549 None,
2550 None,
2551 Vec::new(),
2552 diagnostics,
2553 cx,
2554 )
2555 .log_err();
2556 }
2557 }
2558 let Some(language) = language else {
2559 return;
2560 };
2561 let Some(snapshot) = self
2562 .worktree_store
2563 .read(cx)
2564 .worktree_for_id(worktree_id, cx)
2565 .map(|worktree| worktree.read(cx).snapshot())
2566 else {
2567 return;
2568 };
2569 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2570
2571 for server_id in
2572 self.lsp_tree
2573 .get(path, language.name(), language.manifest(), &delegate, cx)
2574 {
2575 let server = self
2576 .language_servers
2577 .get(&server_id)
2578 .and_then(|server_state| {
2579 if let LanguageServerState::Running { server, .. } = server_state {
2580 Some(server.clone())
2581 } else {
2582 None
2583 }
2584 });
2585 let server = match server {
2586 Some(server) => server,
2587 None => continue,
2588 };
2589
2590 buffer_handle.update(cx, |buffer, cx| {
2591 buffer.set_completion_triggers(
2592 server.server_id(),
2593 server
2594 .capabilities()
2595 .completion_provider
2596 .as_ref()
2597 .and_then(|provider| {
2598 provider
2599 .trigger_characters
2600 .as_ref()
2601 .map(|characters| characters.iter().cloned().collect())
2602 })
2603 .unwrap_or_default(),
2604 cx,
2605 );
2606 });
2607 }
2608 }
2609
2610 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2611 buffer.update(cx, |buffer, cx| {
2612 let Some(language) = buffer.language() else {
2613 return;
2614 };
2615 let path = ProjectPath {
2616 worktree_id: old_file.worktree_id(cx),
2617 path: old_file.path.clone(),
2618 };
2619 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2620 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2621 buffer.set_completion_triggers(server_id, Default::default(), cx);
2622 }
2623 });
2624 }
2625
2626 fn update_buffer_diagnostics(
2627 &mut self,
2628 buffer: &Entity<Buffer>,
2629 server_id: LanguageServerId,
2630 registration_id: Option<Option<SharedString>>,
2631 result_id: Option<SharedString>,
2632 version: Option<i32>,
2633 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2634 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2635 cx: &mut Context<LspStore>,
2636 ) -> Result<()> {
2637 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2638 Ordering::Equal
2639 .then_with(|| b.is_primary.cmp(&a.is_primary))
2640 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2641 .then_with(|| a.severity.cmp(&b.severity))
2642 .then_with(|| a.message.cmp(&b.message))
2643 }
2644
2645 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2646 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2647 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2648
2649 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2650 Ordering::Equal
2651 .then_with(|| a.range.start.cmp(&b.range.start))
2652 .then_with(|| b.range.end.cmp(&a.range.end))
2653 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2654 });
2655
2656 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2657
2658 let edits_since_save = std::cell::LazyCell::new(|| {
2659 let saved_version = buffer.read(cx).saved_version();
2660 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2661 });
2662
2663 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2664
2665 for (new_diagnostic, entry) in diagnostics {
2666 let start;
2667 let end;
2668 if new_diagnostic && entry.diagnostic.is_disk_based {
2669 // Some diagnostics are based on files on disk instead of buffers'
2670 // current contents. Adjust these diagnostics' ranges to reflect
2671 // any unsaved edits.
2672 // Do not alter the reused ones though, as their coordinates were stored as anchors
2673 // and were properly adjusted on reuse.
2674 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2675 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2676 } else {
2677 start = entry.range.start;
2678 end = entry.range.end;
2679 }
2680
2681 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2682 ..snapshot.clip_point_utf16(end, Bias::Right);
2683
2684 // Expand empty ranges by one codepoint
2685 if range.start == range.end {
2686 // This will be go to the next boundary when being clipped
2687 range.end.column += 1;
2688 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2689 if range.start == range.end && range.end.column > 0 {
2690 range.start.column -= 1;
2691 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2692 }
2693 }
2694
2695 sanitized_diagnostics.push(DiagnosticEntry {
2696 range,
2697 diagnostic: entry.diagnostic,
2698 });
2699 }
2700 drop(edits_since_save);
2701
2702 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2703 buffer.update(cx, |buffer, cx| {
2704 if let Some(registration_id) = registration_id {
2705 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2706 self.buffer_pull_diagnostics_result_ids
2707 .entry(server_id)
2708 .or_default()
2709 .entry(registration_id)
2710 .or_default()
2711 .insert(abs_path, result_id);
2712 }
2713 }
2714
2715 buffer.update_diagnostics(server_id, set, cx)
2716 });
2717
2718 Ok(())
2719 }
2720
2721 fn register_language_server_for_invisible_worktree(
2722 &mut self,
2723 worktree: &Entity<Worktree>,
2724 language_server_id: LanguageServerId,
2725 cx: &mut App,
2726 ) {
2727 let worktree = worktree.read(cx);
2728 let worktree_id = worktree.id();
2729 debug_assert!(!worktree.is_visible());
2730 let Some(mut origin_seed) = self
2731 .language_server_ids
2732 .iter()
2733 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2734 else {
2735 return;
2736 };
2737 origin_seed.worktree_id = worktree_id;
2738 self.language_server_ids
2739 .entry(origin_seed)
2740 .or_insert_with(|| UnifiedLanguageServer {
2741 id: language_server_id,
2742 project_roots: Default::default(),
2743 });
2744 }
2745
2746 fn register_buffer_with_language_servers(
2747 &mut self,
2748 buffer_handle: &Entity<Buffer>,
2749 only_register_servers: HashSet<LanguageServerSelector>,
2750 cx: &mut Context<LspStore>,
2751 ) {
2752 let buffer = buffer_handle.read(cx);
2753 let buffer_id = buffer.remote_id();
2754
2755 let Some(file) = File::from_dyn(buffer.file()) else {
2756 return;
2757 };
2758 if !file.is_local() {
2759 return;
2760 }
2761
2762 let abs_path = file.abs_path(cx);
2763 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2764 return;
2765 };
2766 let initial_snapshot = buffer.text_snapshot();
2767 let worktree_id = file.worktree_id(cx);
2768
2769 let Some(language) = buffer.language().cloned() else {
2770 return;
2771 };
2772 let path: Arc<RelPath> = file
2773 .path()
2774 .parent()
2775 .map(Arc::from)
2776 .unwrap_or_else(|| file.path().clone());
2777 let Some(worktree) = self
2778 .worktree_store
2779 .read(cx)
2780 .worktree_for_id(worktree_id, cx)
2781 else {
2782 return;
2783 };
2784 let language_name = language.name();
2785 let (reused, delegate, servers) = self
2786 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2787 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2788 .unwrap_or_else(|| {
2789 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2790 let delegate: Arc<dyn ManifestDelegate> =
2791 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2792
2793 let servers = self
2794 .lsp_tree
2795 .walk(
2796 ProjectPath { worktree_id, path },
2797 language.name(),
2798 language.manifest(),
2799 &delegate,
2800 cx,
2801 )
2802 .collect::<Vec<_>>();
2803 (false, lsp_delegate, servers)
2804 });
2805 let servers_and_adapters = servers
2806 .into_iter()
2807 .filter_map(|server_node| {
2808 if reused && server_node.server_id().is_none() {
2809 return None;
2810 }
2811 if !only_register_servers.is_empty() {
2812 if let Some(server_id) = server_node.server_id()
2813 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2814 {
2815 return None;
2816 }
2817 if let Some(name) = server_node.name()
2818 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2819 {
2820 return None;
2821 }
2822 }
2823
2824 let server_id = server_node.server_id_or_init(|disposition| {
2825 let path = &disposition.path;
2826
2827 {
2828 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2829
2830 let server_id = self.get_or_insert_language_server(
2831 &worktree,
2832 delegate.clone(),
2833 disposition,
2834 &language_name,
2835 cx,
2836 );
2837
2838 if let Some(state) = self.language_servers.get(&server_id)
2839 && let Ok(uri) = uri
2840 {
2841 state.add_workspace_folder(uri);
2842 };
2843 server_id
2844 }
2845 })?;
2846 let server_state = self.language_servers.get(&server_id)?;
2847 if let LanguageServerState::Running {
2848 server, adapter, ..
2849 } = server_state
2850 {
2851 Some((server.clone(), adapter.clone()))
2852 } else {
2853 None
2854 }
2855 })
2856 .collect::<Vec<_>>();
2857 for (server, adapter) in servers_and_adapters {
2858 buffer_handle.update(cx, |buffer, cx| {
2859 buffer.set_completion_triggers(
2860 server.server_id(),
2861 server
2862 .capabilities()
2863 .completion_provider
2864 .as_ref()
2865 .and_then(|provider| {
2866 provider
2867 .trigger_characters
2868 .as_ref()
2869 .map(|characters| characters.iter().cloned().collect())
2870 })
2871 .unwrap_or_default(),
2872 cx,
2873 );
2874 });
2875
2876 let snapshot = LspBufferSnapshot {
2877 version: 0,
2878 snapshot: initial_snapshot.clone(),
2879 };
2880
2881 let mut registered = false;
2882 self.buffer_snapshots
2883 .entry(buffer_id)
2884 .or_default()
2885 .entry(server.server_id())
2886 .or_insert_with(|| {
2887 registered = true;
2888 server.register_buffer(
2889 uri.clone(),
2890 adapter.language_id(&language.name()),
2891 0,
2892 initial_snapshot.text(),
2893 );
2894
2895 vec![snapshot]
2896 });
2897
2898 self.buffers_opened_in_servers
2899 .entry(buffer_id)
2900 .or_default()
2901 .insert(server.server_id());
2902 if registered {
2903 cx.emit(LspStoreEvent::LanguageServerUpdate {
2904 language_server_id: server.server_id(),
2905 name: None,
2906 message: proto::update_language_server::Variant::RegisteredForBuffer(
2907 proto::RegisteredForBuffer {
2908 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2909 buffer_id: buffer_id.to_proto(),
2910 },
2911 ),
2912 });
2913 }
2914 }
2915 }
2916
2917 fn reuse_existing_language_server<'lang_name>(
2918 &self,
2919 server_tree: &LanguageServerTree,
2920 worktree: &Entity<Worktree>,
2921 language_name: &'lang_name LanguageName,
2922 cx: &mut App,
2923 ) -> Option<(
2924 Arc<LocalLspAdapterDelegate>,
2925 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2926 )> {
2927 if worktree.read(cx).is_visible() {
2928 return None;
2929 }
2930
2931 let worktree_store = self.worktree_store.read(cx);
2932 let servers = server_tree
2933 .instances
2934 .iter()
2935 .filter(|(worktree_id, _)| {
2936 worktree_store
2937 .worktree_for_id(**worktree_id, cx)
2938 .is_some_and(|worktree| worktree.read(cx).is_visible())
2939 })
2940 .flat_map(|(worktree_id, servers)| {
2941 servers
2942 .roots
2943 .iter()
2944 .flat_map(|(_, language_servers)| language_servers)
2945 .map(move |(_, (server_node, server_languages))| {
2946 (worktree_id, server_node, server_languages)
2947 })
2948 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2949 .map(|(worktree_id, server_node, _)| {
2950 (
2951 *worktree_id,
2952 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2953 )
2954 })
2955 })
2956 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2957 acc.entry(worktree_id)
2958 .or_insert_with(Vec::new)
2959 .push(server_node);
2960 acc
2961 })
2962 .into_values()
2963 .max_by_key(|servers| servers.len())?;
2964
2965 let worktree_id = worktree.read(cx).id();
2966 let apply = move |tree: &mut LanguageServerTree| {
2967 for server_node in &servers {
2968 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2969 }
2970 servers
2971 };
2972
2973 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2974 Some((delegate, apply))
2975 }
2976
2977 pub(crate) fn unregister_old_buffer_from_language_servers(
2978 &mut self,
2979 buffer: &Entity<Buffer>,
2980 old_file: &File,
2981 cx: &mut App,
2982 ) {
2983 let old_path = match old_file.as_local() {
2984 Some(local) => local.abs_path(cx),
2985 None => return,
2986 };
2987
2988 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2989 debug_panic!("{old_path:?} is not parseable as an URI");
2990 return;
2991 };
2992 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2993 }
2994
2995 pub(crate) fn unregister_buffer_from_language_servers(
2996 &mut self,
2997 buffer: &Entity<Buffer>,
2998 file_url: &lsp::Uri,
2999 cx: &mut App,
3000 ) {
3001 buffer.update(cx, |buffer, cx| {
3002 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3003
3004 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3005 if snapshots
3006 .as_mut()
3007 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3008 {
3009 language_server.unregister_buffer(file_url.clone());
3010 }
3011 }
3012 });
3013 }
3014
3015 fn buffer_snapshot_for_lsp_version(
3016 &mut self,
3017 buffer: &Entity<Buffer>,
3018 server_id: LanguageServerId,
3019 version: Option<i32>,
3020 cx: &App,
3021 ) -> Result<TextBufferSnapshot> {
3022 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3023
3024 if let Some(version) = version {
3025 let buffer_id = buffer.read(cx).remote_id();
3026 let snapshots = if let Some(snapshots) = self
3027 .buffer_snapshots
3028 .get_mut(&buffer_id)
3029 .and_then(|m| m.get_mut(&server_id))
3030 {
3031 snapshots
3032 } else if version == 0 {
3033 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3034 // We detect this case and treat it as if the version was `None`.
3035 return Ok(buffer.read(cx).text_snapshot());
3036 } else {
3037 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3038 };
3039
3040 let found_snapshot = snapshots
3041 .binary_search_by_key(&version, |e| e.version)
3042 .map(|ix| snapshots[ix].snapshot.clone())
3043 .map_err(|_| {
3044 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3045 })?;
3046
3047 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3048 Ok(found_snapshot)
3049 } else {
3050 Ok((buffer.read(cx)).text_snapshot())
3051 }
3052 }
3053
3054 async fn get_server_code_actions_from_action_kinds(
3055 lsp_store: &WeakEntity<LspStore>,
3056 language_server_id: LanguageServerId,
3057 code_action_kinds: Vec<lsp::CodeActionKind>,
3058 buffer: &Entity<Buffer>,
3059 cx: &mut AsyncApp,
3060 ) -> Result<Vec<CodeAction>> {
3061 let actions = lsp_store
3062 .update(cx, move |this, cx| {
3063 let request = GetCodeActions {
3064 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3065 kinds: Some(code_action_kinds),
3066 };
3067 let server = LanguageServerToQuery::Other(language_server_id);
3068 this.request_lsp(buffer.clone(), server, request, cx)
3069 })?
3070 .await?;
3071 Ok(actions)
3072 }
3073
3074 pub async fn execute_code_actions_on_server(
3075 lsp_store: &WeakEntity<LspStore>,
3076 language_server: &Arc<LanguageServer>,
3077 actions: Vec<CodeAction>,
3078 push_to_history: bool,
3079 project_transaction: &mut ProjectTransaction,
3080 cx: &mut AsyncApp,
3081 ) -> anyhow::Result<()> {
3082 let request_timeout = cx.update(|app| {
3083 ProjectSettings::get_global(app)
3084 .global_lsp_settings
3085 .get_request_timeout()
3086 });
3087
3088 for mut action in actions {
3089 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3090 .await
3091 .context("resolving a formatting code action")?;
3092
3093 if let Some(edit) = action.lsp_action.edit() {
3094 if edit.changes.is_none() && edit.document_changes.is_none() {
3095 continue;
3096 }
3097
3098 let new = Self::deserialize_workspace_edit(
3099 lsp_store.upgrade().context("project dropped")?,
3100 edit.clone(),
3101 push_to_history,
3102 language_server.clone(),
3103 cx,
3104 )
3105 .await?;
3106 project_transaction.0.extend(new.0);
3107 }
3108
3109 let Some(command) = action.lsp_action.command() else {
3110 continue;
3111 };
3112
3113 let server_capabilities = language_server.capabilities();
3114 let available_commands = server_capabilities
3115 .execute_command_provider
3116 .as_ref()
3117 .map(|options| options.commands.as_slice())
3118 .unwrap_or_default();
3119 if !available_commands.contains(&command.command) {
3120 log::warn!(
3121 "Cannot execute a command {} not listed in the language server capabilities",
3122 command.command
3123 );
3124 continue;
3125 }
3126
3127 lsp_store.update(cx, |lsp_store, _| {
3128 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3129 mode.last_workspace_edits_by_language_server
3130 .remove(&language_server.server_id());
3131 }
3132 })?;
3133
3134 language_server
3135 .request::<lsp::request::ExecuteCommand>(
3136 lsp::ExecuteCommandParams {
3137 command: command.command.clone(),
3138 arguments: command.arguments.clone().unwrap_or_default(),
3139 ..Default::default()
3140 },
3141 request_timeout,
3142 )
3143 .await
3144 .into_response()
3145 .context("execute command")?;
3146
3147 lsp_store.update(cx, |this, _| {
3148 if let LspStoreMode::Local(mode) = &mut this.mode {
3149 project_transaction.0.extend(
3150 mode.last_workspace_edits_by_language_server
3151 .remove(&language_server.server_id())
3152 .unwrap_or_default()
3153 .0,
3154 )
3155 }
3156 })?;
3157 }
3158 Ok(())
3159 }
3160
3161 pub async fn deserialize_text_edits(
3162 this: Entity<LspStore>,
3163 buffer_to_edit: Entity<Buffer>,
3164 edits: Vec<lsp::TextEdit>,
3165 push_to_history: bool,
3166 _: Arc<CachedLspAdapter>,
3167 language_server: Arc<LanguageServer>,
3168 cx: &mut AsyncApp,
3169 ) -> Result<Option<Transaction>> {
3170 let edits = this
3171 .update(cx, |this, cx| {
3172 this.as_local_mut().unwrap().edits_from_lsp(
3173 &buffer_to_edit,
3174 edits,
3175 language_server.server_id(),
3176 None,
3177 cx,
3178 )
3179 })
3180 .await?;
3181
3182 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3183 buffer.finalize_last_transaction();
3184 buffer.start_transaction();
3185 for (range, text) in edits {
3186 buffer.edit([(range, text)], None, cx);
3187 }
3188
3189 if buffer.end_transaction(cx).is_some() {
3190 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3191 if !push_to_history {
3192 buffer.forget_transaction(transaction.id);
3193 }
3194 Some(transaction)
3195 } else {
3196 None
3197 }
3198 });
3199
3200 Ok(transaction)
3201 }
3202
3203 #[allow(clippy::type_complexity)]
3204 pub fn edits_from_lsp(
3205 &mut self,
3206 buffer: &Entity<Buffer>,
3207 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3208 server_id: LanguageServerId,
3209 version: Option<i32>,
3210 cx: &mut Context<LspStore>,
3211 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3212 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3213 cx.background_spawn(async move {
3214 let snapshot = snapshot?;
3215 let mut lsp_edits = lsp_edits
3216 .into_iter()
3217 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3218 .collect::<Vec<_>>();
3219
3220 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3221
3222 let mut lsp_edits = lsp_edits.into_iter().peekable();
3223 let mut edits = Vec::new();
3224 while let Some((range, mut new_text)) = lsp_edits.next() {
3225 // Clip invalid ranges provided by the language server.
3226 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3227 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3228
3229 // Combine any LSP edits that are adjacent.
3230 //
3231 // Also, combine LSP edits that are separated from each other by only
3232 // a newline. This is important because for some code actions,
3233 // Rust-analyzer rewrites the entire buffer via a series of edits that
3234 // are separated by unchanged newline characters.
3235 //
3236 // In order for the diffing logic below to work properly, any edits that
3237 // cancel each other out must be combined into one.
3238 while let Some((next_range, next_text)) = lsp_edits.peek() {
3239 if next_range.start.0 > range.end {
3240 if next_range.start.0.row > range.end.row + 1
3241 || next_range.start.0.column > 0
3242 || snapshot.clip_point_utf16(
3243 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3244 Bias::Left,
3245 ) > range.end
3246 {
3247 break;
3248 }
3249 new_text.push('\n');
3250 }
3251 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3252 new_text.push_str(next_text);
3253 lsp_edits.next();
3254 }
3255
3256 // For multiline edits, perform a diff of the old and new text so that
3257 // we can identify the changes more precisely, preserving the locations
3258 // of any anchors positioned in the unchanged regions.
3259 if range.end.row > range.start.row {
3260 let offset = range.start.to_offset(&snapshot);
3261 let old_text = snapshot.text_for_range(range).collect::<String>();
3262 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3263 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3264 (
3265 snapshot.anchor_after(offset + range.start)
3266 ..snapshot.anchor_before(offset + range.end),
3267 replacement,
3268 )
3269 }));
3270 } else if range.end == range.start {
3271 let anchor = snapshot.anchor_after(range.start);
3272 edits.push((anchor..anchor, new_text.into()));
3273 } else {
3274 let edit_start = snapshot.anchor_after(range.start);
3275 let edit_end = snapshot.anchor_before(range.end);
3276 edits.push((edit_start..edit_end, new_text.into()));
3277 }
3278 }
3279
3280 Ok(edits)
3281 })
3282 }
3283
3284 pub(crate) async fn deserialize_workspace_edit(
3285 this: Entity<LspStore>,
3286 edit: lsp::WorkspaceEdit,
3287 push_to_history: bool,
3288 language_server: Arc<LanguageServer>,
3289 cx: &mut AsyncApp,
3290 ) -> Result<ProjectTransaction> {
3291 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3292
3293 let mut operations = Vec::new();
3294 if let Some(document_changes) = edit.document_changes {
3295 match document_changes {
3296 lsp::DocumentChanges::Edits(edits) => {
3297 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3298 }
3299 lsp::DocumentChanges::Operations(ops) => operations = ops,
3300 }
3301 } else if let Some(changes) = edit.changes {
3302 operations.extend(changes.into_iter().map(|(uri, edits)| {
3303 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3304 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3305 uri,
3306 version: None,
3307 },
3308 edits: edits.into_iter().map(Edit::Plain).collect(),
3309 })
3310 }));
3311 }
3312
3313 let mut project_transaction = ProjectTransaction::default();
3314 for operation in operations {
3315 match operation {
3316 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3317 let abs_path = op
3318 .uri
3319 .to_file_path()
3320 .map_err(|()| anyhow!("can't convert URI to path"))?;
3321
3322 if let Some(parent_path) = abs_path.parent() {
3323 fs.create_dir(parent_path).await?;
3324 }
3325 if abs_path.ends_with("/") {
3326 fs.create_dir(&abs_path).await?;
3327 } else {
3328 fs.create_file(
3329 &abs_path,
3330 op.options
3331 .map(|options| fs::CreateOptions {
3332 overwrite: options.overwrite.unwrap_or(false),
3333 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3334 })
3335 .unwrap_or_default(),
3336 )
3337 .await?;
3338 }
3339 }
3340
3341 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3342 let source_abs_path = op
3343 .old_uri
3344 .to_file_path()
3345 .map_err(|()| anyhow!("can't convert URI to path"))?;
3346 let target_abs_path = op
3347 .new_uri
3348 .to_file_path()
3349 .map_err(|()| anyhow!("can't convert URI to path"))?;
3350
3351 let options = fs::RenameOptions {
3352 overwrite: op
3353 .options
3354 .as_ref()
3355 .and_then(|options| options.overwrite)
3356 .unwrap_or(false),
3357 ignore_if_exists: op
3358 .options
3359 .as_ref()
3360 .and_then(|options| options.ignore_if_exists)
3361 .unwrap_or(false),
3362 create_parents: true,
3363 };
3364
3365 fs.rename(&source_abs_path, &target_abs_path, options)
3366 .await?;
3367 }
3368
3369 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3370 let abs_path = op
3371 .uri
3372 .to_file_path()
3373 .map_err(|()| anyhow!("can't convert URI to path"))?;
3374 let options = op
3375 .options
3376 .map(|options| fs::RemoveOptions {
3377 recursive: options.recursive.unwrap_or(false),
3378 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3379 })
3380 .unwrap_or_default();
3381 if abs_path.ends_with("/") {
3382 fs.remove_dir(&abs_path, options).await?;
3383 } else {
3384 fs.remove_file(&abs_path, options).await?;
3385 }
3386 }
3387
3388 lsp::DocumentChangeOperation::Edit(op) => {
3389 let buffer_to_edit = this
3390 .update(cx, |this, cx| {
3391 this.open_local_buffer_via_lsp(
3392 op.text_document.uri.clone(),
3393 language_server.server_id(),
3394 cx,
3395 )
3396 })
3397 .await?;
3398
3399 let edits = this
3400 .update(cx, |this, cx| {
3401 let path = buffer_to_edit.read(cx).project_path(cx);
3402 let active_entry = this.active_entry;
3403 let is_active_entry = path.is_some_and(|project_path| {
3404 this.worktree_store
3405 .read(cx)
3406 .entry_for_path(&project_path, cx)
3407 .is_some_and(|entry| Some(entry.id) == active_entry)
3408 });
3409 let local = this.as_local_mut().unwrap();
3410
3411 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3412 for edit in op.edits {
3413 match edit {
3414 Edit::Plain(edit) => {
3415 if !edits.contains(&edit) {
3416 edits.push(edit)
3417 }
3418 }
3419 Edit::Annotated(edit) => {
3420 if !edits.contains(&edit.text_edit) {
3421 edits.push(edit.text_edit)
3422 }
3423 }
3424 Edit::Snippet(edit) => {
3425 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3426 else {
3427 continue;
3428 };
3429
3430 if is_active_entry {
3431 snippet_edits.push((edit.range, snippet));
3432 } else {
3433 // Since this buffer is not focused, apply a normal edit.
3434 let new_edit = TextEdit {
3435 range: edit.range,
3436 new_text: snippet.text,
3437 };
3438 if !edits.contains(&new_edit) {
3439 edits.push(new_edit);
3440 }
3441 }
3442 }
3443 }
3444 }
3445 if !snippet_edits.is_empty() {
3446 let buffer_id = buffer_to_edit.read(cx).remote_id();
3447 let version = if let Some(buffer_version) = op.text_document.version
3448 {
3449 local
3450 .buffer_snapshot_for_lsp_version(
3451 &buffer_to_edit,
3452 language_server.server_id(),
3453 Some(buffer_version),
3454 cx,
3455 )
3456 .ok()
3457 .map(|snapshot| snapshot.version)
3458 } else {
3459 Some(buffer_to_edit.read(cx).saved_version().clone())
3460 };
3461
3462 let most_recent_edit =
3463 version.and_then(|version| version.most_recent());
3464 // Check if the edit that triggered that edit has been made by this participant.
3465
3466 if let Some(most_recent_edit) = most_recent_edit {
3467 cx.emit(LspStoreEvent::SnippetEdit {
3468 buffer_id,
3469 edits: snippet_edits,
3470 most_recent_edit,
3471 });
3472 }
3473 }
3474
3475 local.edits_from_lsp(
3476 &buffer_to_edit,
3477 edits,
3478 language_server.server_id(),
3479 op.text_document.version,
3480 cx,
3481 )
3482 })
3483 .await?;
3484
3485 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3486 buffer.finalize_last_transaction();
3487 buffer.start_transaction();
3488 for (range, text) in edits {
3489 buffer.edit([(range, text)], None, cx);
3490 }
3491
3492 buffer.end_transaction(cx).and_then(|transaction_id| {
3493 if push_to_history {
3494 buffer.finalize_last_transaction();
3495 buffer.get_transaction(transaction_id).cloned()
3496 } else {
3497 buffer.forget_transaction(transaction_id)
3498 }
3499 })
3500 });
3501 if let Some(transaction) = transaction {
3502 project_transaction.0.insert(buffer_to_edit, transaction);
3503 }
3504 }
3505 }
3506 }
3507
3508 Ok(project_transaction)
3509 }
3510
3511 async fn on_lsp_workspace_edit(
3512 this: WeakEntity<LspStore>,
3513 params: lsp::ApplyWorkspaceEditParams,
3514 server_id: LanguageServerId,
3515 cx: &mut AsyncApp,
3516 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3517 let this = this.upgrade().context("project project closed")?;
3518 let language_server = this
3519 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3520 .context("language server not found")?;
3521 let transaction = Self::deserialize_workspace_edit(
3522 this.clone(),
3523 params.edit,
3524 true,
3525 language_server.clone(),
3526 cx,
3527 )
3528 .await
3529 .log_err();
3530 this.update(cx, |this, cx| {
3531 if let Some(transaction) = transaction {
3532 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3533
3534 this.as_local_mut()
3535 .unwrap()
3536 .last_workspace_edits_by_language_server
3537 .insert(server_id, transaction);
3538 }
3539 });
3540 Ok(lsp::ApplyWorkspaceEditResponse {
3541 applied: true,
3542 failed_change: None,
3543 failure_reason: None,
3544 })
3545 }
3546
3547 fn remove_worktree(
3548 &mut self,
3549 id_to_remove: WorktreeId,
3550 cx: &mut Context<LspStore>,
3551 ) -> Vec<LanguageServerId> {
3552 self.restricted_worktrees_tasks.remove(&id_to_remove);
3553 self.diagnostics.remove(&id_to_remove);
3554 self.prettier_store.update(cx, |prettier_store, cx| {
3555 prettier_store.remove_worktree(id_to_remove, cx);
3556 });
3557
3558 let mut servers_to_remove = BTreeSet::default();
3559 let mut servers_to_preserve = HashSet::default();
3560 for (seed, state) in &self.language_server_ids {
3561 if seed.worktree_id == id_to_remove {
3562 servers_to_remove.insert(state.id);
3563 } else {
3564 servers_to_preserve.insert(state.id);
3565 }
3566 }
3567 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3568 self.language_server_ids
3569 .retain(|_, state| !servers_to_remove.contains(&state.id));
3570 for server_id_to_remove in &servers_to_remove {
3571 self.language_server_watched_paths
3572 .remove(server_id_to_remove);
3573 self.language_server_paths_watched_for_rename
3574 .remove(server_id_to_remove);
3575 self.last_workspace_edits_by_language_server
3576 .remove(server_id_to_remove);
3577 self.language_servers.remove(server_id_to_remove);
3578 self.buffer_pull_diagnostics_result_ids
3579 .remove(server_id_to_remove);
3580 self.workspace_pull_diagnostics_result_ids
3581 .remove(server_id_to_remove);
3582 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3583 buffer_servers.remove(server_id_to_remove);
3584 }
3585 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3586 }
3587 servers_to_remove.into_iter().collect()
3588 }
3589
3590 fn rebuild_watched_paths_inner<'a>(
3591 &'a self,
3592 language_server_id: LanguageServerId,
3593 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3594 cx: &mut Context<LspStore>,
3595 ) -> LanguageServerWatchedPathsBuilder {
3596 let worktrees = self
3597 .worktree_store
3598 .read(cx)
3599 .worktrees()
3600 .filter_map(|worktree| {
3601 self.language_servers_for_worktree(worktree.read(cx).id())
3602 .find(|server| server.server_id() == language_server_id)
3603 .map(|_| worktree)
3604 })
3605 .collect::<Vec<_>>();
3606
3607 let mut worktree_globs = HashMap::default();
3608 let mut abs_globs = HashMap::default();
3609 log::trace!(
3610 "Processing new watcher paths for language server with id {}",
3611 language_server_id
3612 );
3613
3614 for watcher in watchers {
3615 if let Some((worktree, literal_prefix, pattern)) =
3616 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3617 {
3618 worktree.update(cx, |worktree, _| {
3619 if let Some((tree, glob)) =
3620 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3621 {
3622 tree.add_path_prefix_to_scan(literal_prefix);
3623 worktree_globs
3624 .entry(tree.id())
3625 .or_insert_with(GlobSetBuilder::new)
3626 .add(glob);
3627 }
3628 });
3629 } else {
3630 let (path, pattern) = match &watcher.glob_pattern {
3631 lsp::GlobPattern::String(s) => {
3632 let watcher_path = SanitizedPath::new(s);
3633 let path = glob_literal_prefix(watcher_path.as_path());
3634 let pattern = watcher_path
3635 .as_path()
3636 .strip_prefix(&path)
3637 .map(|p| p.to_string_lossy().into_owned())
3638 .unwrap_or_else(|e| {
3639 debug_panic!(
3640 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3641 s,
3642 path.display(),
3643 e
3644 );
3645 watcher_path.as_path().to_string_lossy().into_owned()
3646 });
3647 (path, pattern)
3648 }
3649 lsp::GlobPattern::Relative(rp) => {
3650 let Ok(mut base_uri) = match &rp.base_uri {
3651 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3652 lsp::OneOf::Right(base_uri) => base_uri,
3653 }
3654 .to_file_path() else {
3655 continue;
3656 };
3657
3658 let path = glob_literal_prefix(Path::new(&rp.pattern));
3659 let pattern = Path::new(&rp.pattern)
3660 .strip_prefix(&path)
3661 .map(|p| p.to_string_lossy().into_owned())
3662 .unwrap_or_else(|e| {
3663 debug_panic!(
3664 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3665 rp.pattern,
3666 path.display(),
3667 e
3668 );
3669 rp.pattern.clone()
3670 });
3671 base_uri.push(path);
3672 (base_uri, pattern)
3673 }
3674 };
3675
3676 if let Some(glob) = Glob::new(&pattern).log_err() {
3677 if !path
3678 .components()
3679 .any(|c| matches!(c, path::Component::Normal(_)))
3680 {
3681 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3682 // rather than adding a new watcher for `/`.
3683 for worktree in &worktrees {
3684 worktree_globs
3685 .entry(worktree.read(cx).id())
3686 .or_insert_with(GlobSetBuilder::new)
3687 .add(glob.clone());
3688 }
3689 } else {
3690 abs_globs
3691 .entry(path.into())
3692 .or_insert_with(GlobSetBuilder::new)
3693 .add(glob);
3694 }
3695 }
3696 }
3697 }
3698
3699 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3700 for (worktree_id, builder) in worktree_globs {
3701 if let Ok(globset) = builder.build() {
3702 watch_builder.watch_worktree(worktree_id, globset);
3703 }
3704 }
3705 for (abs_path, builder) in abs_globs {
3706 if let Ok(globset) = builder.build() {
3707 watch_builder.watch_abs_path(abs_path, globset);
3708 }
3709 }
3710 watch_builder
3711 }
3712
3713 fn worktree_and_path_for_file_watcher(
3714 worktrees: &[Entity<Worktree>],
3715 watcher: &FileSystemWatcher,
3716 cx: &App,
3717 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3718 worktrees.iter().find_map(|worktree| {
3719 let tree = worktree.read(cx);
3720 let worktree_root_path = tree.abs_path();
3721 let path_style = tree.path_style();
3722 match &watcher.glob_pattern {
3723 lsp::GlobPattern::String(s) => {
3724 let watcher_path = SanitizedPath::new(s);
3725 let relative = watcher_path
3726 .as_path()
3727 .strip_prefix(&worktree_root_path)
3728 .ok()?;
3729 let literal_prefix = glob_literal_prefix(relative);
3730 Some((
3731 worktree.clone(),
3732 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3733 relative.to_string_lossy().into_owned(),
3734 ))
3735 }
3736 lsp::GlobPattern::Relative(rp) => {
3737 let base_uri = match &rp.base_uri {
3738 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3739 lsp::OneOf::Right(base_uri) => base_uri,
3740 }
3741 .to_file_path()
3742 .ok()?;
3743 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3744 let mut literal_prefix = relative.to_owned();
3745 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3746 Some((
3747 worktree.clone(),
3748 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3749 rp.pattern.clone(),
3750 ))
3751 }
3752 }
3753 })
3754 }
3755
3756 fn rebuild_watched_paths(
3757 &mut self,
3758 language_server_id: LanguageServerId,
3759 cx: &mut Context<LspStore>,
3760 ) {
3761 let Some(registrations) = self
3762 .language_server_dynamic_registrations
3763 .get(&language_server_id)
3764 else {
3765 return;
3766 };
3767
3768 let watch_builder = self.rebuild_watched_paths_inner(
3769 language_server_id,
3770 registrations.did_change_watched_files.values().flatten(),
3771 cx,
3772 );
3773 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3774 self.language_server_watched_paths
3775 .insert(language_server_id, watcher);
3776
3777 cx.notify();
3778 }
3779
3780 fn on_lsp_did_change_watched_files(
3781 &mut self,
3782 language_server_id: LanguageServerId,
3783 registration_id: &str,
3784 params: DidChangeWatchedFilesRegistrationOptions,
3785 cx: &mut Context<LspStore>,
3786 ) {
3787 let registrations = self
3788 .language_server_dynamic_registrations
3789 .entry(language_server_id)
3790 .or_default();
3791
3792 registrations
3793 .did_change_watched_files
3794 .insert(registration_id.to_string(), params.watchers);
3795
3796 self.rebuild_watched_paths(language_server_id, cx);
3797 }
3798
3799 fn on_lsp_unregister_did_change_watched_files(
3800 &mut self,
3801 language_server_id: LanguageServerId,
3802 registration_id: &str,
3803 cx: &mut Context<LspStore>,
3804 ) {
3805 let registrations = self
3806 .language_server_dynamic_registrations
3807 .entry(language_server_id)
3808 .or_default();
3809
3810 if registrations
3811 .did_change_watched_files
3812 .remove(registration_id)
3813 .is_some()
3814 {
3815 log::info!(
3816 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3817 language_server_id,
3818 registration_id
3819 );
3820 } else {
3821 log::warn!(
3822 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3823 language_server_id,
3824 registration_id
3825 );
3826 }
3827
3828 self.rebuild_watched_paths(language_server_id, cx);
3829 }
3830
3831 async fn initialization_options_for_adapter(
3832 adapter: Arc<dyn LspAdapter>,
3833 delegate: &Arc<dyn LspAdapterDelegate>,
3834 cx: &mut AsyncApp,
3835 ) -> Result<Option<serde_json::Value>> {
3836 let Some(mut initialization_config) =
3837 adapter.clone().initialization_options(delegate, cx).await?
3838 else {
3839 return Ok(None);
3840 };
3841
3842 for other_adapter in delegate.registered_lsp_adapters() {
3843 if other_adapter.name() == adapter.name() {
3844 continue;
3845 }
3846 if let Ok(Some(target_config)) = other_adapter
3847 .clone()
3848 .additional_initialization_options(adapter.name(), delegate)
3849 .await
3850 {
3851 merge_json_value_into(target_config.clone(), &mut initialization_config);
3852 }
3853 }
3854
3855 Ok(Some(initialization_config))
3856 }
3857
3858 async fn workspace_configuration_for_adapter(
3859 adapter: Arc<dyn LspAdapter>,
3860 delegate: &Arc<dyn LspAdapterDelegate>,
3861 toolchain: Option<Toolchain>,
3862 requested_uri: Option<Uri>,
3863 cx: &mut AsyncApp,
3864 ) -> Result<serde_json::Value> {
3865 let mut workspace_config = adapter
3866 .clone()
3867 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3868 .await?;
3869
3870 for other_adapter in delegate.registered_lsp_adapters() {
3871 if other_adapter.name() == adapter.name() {
3872 continue;
3873 }
3874 if let Ok(Some(target_config)) = other_adapter
3875 .clone()
3876 .additional_workspace_configuration(adapter.name(), delegate, cx)
3877 .await
3878 {
3879 merge_json_value_into(target_config.clone(), &mut workspace_config);
3880 }
3881 }
3882
3883 Ok(workspace_config)
3884 }
3885
3886 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3887 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3888 Some(server.clone())
3889 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3890 Some(Arc::clone(server))
3891 } else {
3892 None
3893 }
3894 }
3895}
3896
3897fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3898 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3899 cx.emit(LspStoreEvent::LanguageServerUpdate {
3900 language_server_id: server.server_id(),
3901 name: Some(server.name()),
3902 message: proto::update_language_server::Variant::MetadataUpdated(
3903 proto::ServerMetadataUpdated {
3904 capabilities: Some(capabilities),
3905 binary: Some(proto::LanguageServerBinaryInfo {
3906 path: server.binary().path.to_string_lossy().into_owned(),
3907 arguments: server
3908 .binary()
3909 .arguments
3910 .iter()
3911 .map(|arg| arg.to_string_lossy().into_owned())
3912 .collect(),
3913 }),
3914 configuration: serde_json::to_string(server.configuration()).ok(),
3915 workspace_folders: server
3916 .workspace_folders()
3917 .iter()
3918 .map(|uri| uri.to_string())
3919 .collect(),
3920 },
3921 ),
3922 });
3923 }
3924}
3925
3926#[derive(Debug)]
3927pub struct FormattableBuffer {
3928 handle: Entity<Buffer>,
3929 abs_path: Option<PathBuf>,
3930 env: Option<HashMap<String, String>>,
3931 ranges: Option<Vec<Range<Anchor>>>,
3932}
3933
3934pub struct RemoteLspStore {
3935 upstream_client: Option<AnyProtoClient>,
3936 upstream_project_id: u64,
3937}
3938
3939pub(crate) enum LspStoreMode {
3940 Local(LocalLspStore), // ssh host and collab host
3941 Remote(RemoteLspStore), // collab guest
3942}
3943
3944impl LspStoreMode {
3945 fn is_local(&self) -> bool {
3946 matches!(self, LspStoreMode::Local(_))
3947 }
3948}
3949
3950pub struct LspStore {
3951 mode: LspStoreMode,
3952 last_formatting_failure: Option<String>,
3953 downstream_client: Option<(AnyProtoClient, u64)>,
3954 nonce: u128,
3955 buffer_store: Entity<BufferStore>,
3956 worktree_store: Entity<WorktreeStore>,
3957 pub languages: Arc<LanguageRegistry>,
3958 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3959 active_entry: Option<ProjectEntryId>,
3960 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3961 _maintain_buffer_languages: Task<()>,
3962 diagnostic_summaries:
3963 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3964 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3965 semantic_token_config: SemanticTokenConfig,
3966 lsp_data: HashMap<BufferId, BufferLspData>,
3967 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3968 next_hint_id: Arc<AtomicUsize>,
3969}
3970
3971#[derive(Debug)]
3972pub struct BufferLspData {
3973 buffer_version: Global,
3974 document_colors: Option<DocumentColorData>,
3975 code_lens: Option<CodeLensData>,
3976 semantic_tokens: Option<SemanticTokensData>,
3977 folding_ranges: Option<FoldingRangeData>,
3978 document_symbols: Option<DocumentSymbolsData>,
3979 inlay_hints: BufferInlayHints,
3980 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3981 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3982}
3983
3984#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3985struct LspKey {
3986 request_type: TypeId,
3987 server_queried: Option<LanguageServerId>,
3988}
3989
3990impl BufferLspData {
3991 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3992 Self {
3993 buffer_version: buffer.read(cx).version(),
3994 document_colors: None,
3995 code_lens: None,
3996 semantic_tokens: None,
3997 folding_ranges: None,
3998 document_symbols: None,
3999 inlay_hints: BufferInlayHints::new(buffer, cx),
4000 lsp_requests: HashMap::default(),
4001 chunk_lsp_requests: HashMap::default(),
4002 }
4003 }
4004
4005 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4006 if let Some(document_colors) = &mut self.document_colors {
4007 document_colors.remove_server_data(for_server);
4008 }
4009
4010 if let Some(code_lens) = &mut self.code_lens {
4011 code_lens.remove_server_data(for_server);
4012 }
4013
4014 self.inlay_hints.remove_server_data(for_server);
4015
4016 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4017 semantic_tokens.remove_server_data(for_server);
4018 }
4019
4020 if let Some(folding_ranges) = &mut self.folding_ranges {
4021 folding_ranges.ranges.remove(&for_server);
4022 }
4023
4024 if let Some(document_symbols) = &mut self.document_symbols {
4025 document_symbols.remove_server_data(for_server);
4026 }
4027 }
4028
4029 #[cfg(any(test, feature = "test-support"))]
4030 pub fn inlay_hints(&self) -> &BufferInlayHints {
4031 &self.inlay_hints
4032 }
4033}
4034
4035#[derive(Debug)]
4036pub enum LspStoreEvent {
4037 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4038 LanguageServerRemoved(LanguageServerId),
4039 LanguageServerUpdate {
4040 language_server_id: LanguageServerId,
4041 name: Option<LanguageServerName>,
4042 message: proto::update_language_server::Variant,
4043 },
4044 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4045 LanguageServerPrompt(LanguageServerPromptRequest),
4046 LanguageDetected {
4047 buffer: Entity<Buffer>,
4048 new_language: Option<Arc<Language>>,
4049 },
4050 Notification(String),
4051 RefreshInlayHints {
4052 server_id: LanguageServerId,
4053 request_id: Option<usize>,
4054 },
4055 RefreshSemanticTokens {
4056 server_id: LanguageServerId,
4057 request_id: Option<usize>,
4058 },
4059 RefreshCodeLens,
4060 DiagnosticsUpdated {
4061 server_id: LanguageServerId,
4062 paths: Vec<ProjectPath>,
4063 },
4064 DiskBasedDiagnosticsStarted {
4065 language_server_id: LanguageServerId,
4066 },
4067 DiskBasedDiagnosticsFinished {
4068 language_server_id: LanguageServerId,
4069 },
4070 SnippetEdit {
4071 buffer_id: BufferId,
4072 edits: Vec<(lsp::Range, Snippet)>,
4073 most_recent_edit: clock::Lamport,
4074 },
4075 WorkspaceEditApplied(ProjectTransaction),
4076}
4077
4078#[derive(Clone, Debug, Serialize)]
4079pub struct LanguageServerStatus {
4080 pub name: LanguageServerName,
4081 pub server_version: Option<SharedString>,
4082 pub server_readable_version: Option<SharedString>,
4083 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4084 pub has_pending_diagnostic_updates: bool,
4085 pub progress_tokens: HashSet<ProgressToken>,
4086 pub worktree: Option<WorktreeId>,
4087 pub binary: Option<LanguageServerBinary>,
4088 pub configuration: Option<Value>,
4089 pub workspace_folders: BTreeSet<Uri>,
4090 pub process_id: Option<u32>,
4091}
4092
4093#[derive(Clone, Debug)]
4094struct CoreSymbol {
4095 pub language_server_name: LanguageServerName,
4096 pub source_worktree_id: WorktreeId,
4097 pub source_language_server_id: LanguageServerId,
4098 pub path: SymbolLocation,
4099 pub name: String,
4100 pub kind: lsp::SymbolKind,
4101 pub range: Range<Unclipped<PointUtf16>>,
4102 pub container_name: Option<String>,
4103}
4104
4105#[derive(Clone, Debug, PartialEq, Eq)]
4106pub enum SymbolLocation {
4107 InProject(ProjectPath),
4108 OutsideProject {
4109 abs_path: Arc<Path>,
4110 signature: [u8; 32],
4111 },
4112}
4113
4114impl SymbolLocation {
4115 fn file_name(&self) -> Option<&str> {
4116 match self {
4117 Self::InProject(path) => path.path.file_name(),
4118 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4119 }
4120 }
4121}
4122
4123impl LspStore {
4124 pub fn init(client: &AnyProtoClient) {
4125 client.add_entity_request_handler(Self::handle_lsp_query);
4126 client.add_entity_message_handler(Self::handle_lsp_query_response);
4127 client.add_entity_request_handler(Self::handle_restart_language_servers);
4128 client.add_entity_request_handler(Self::handle_stop_language_servers);
4129 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4130 client.add_entity_message_handler(Self::handle_start_language_server);
4131 client.add_entity_message_handler(Self::handle_update_language_server);
4132 client.add_entity_message_handler(Self::handle_language_server_log);
4133 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4134 client.add_entity_request_handler(Self::handle_format_buffers);
4135 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4136 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4137 client.add_entity_request_handler(Self::handle_apply_code_action);
4138 client.add_entity_request_handler(Self::handle_get_project_symbols);
4139 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4140 client.add_entity_request_handler(Self::handle_get_color_presentation);
4141 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4142 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4143 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4144 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4145 client.add_entity_request_handler(Self::handle_on_type_formatting);
4146 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4147 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4148 client.add_entity_request_handler(Self::handle_rename_project_entry);
4149 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4150 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4151 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4152 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4153 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4154 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4155 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4156
4157 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4158 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4159 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4160 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4161 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4162 client.add_entity_request_handler(
4163 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4164 );
4165 client.add_entity_request_handler(
4166 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4167 );
4168 client.add_entity_request_handler(
4169 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4170 );
4171 }
4172
4173 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4174 match &self.mode {
4175 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4176 _ => None,
4177 }
4178 }
4179
4180 pub fn as_local(&self) -> Option<&LocalLspStore> {
4181 match &self.mode {
4182 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4183 _ => None,
4184 }
4185 }
4186
4187 pub fn is_buffer_being_formatted(&self, buffer_id: BufferId) -> bool {
4188 self.as_local()
4189 .is_some_and(|local| local.buffers_being_formatted.contains(&buffer_id))
4190 }
4191
4192 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4193 match &mut self.mode {
4194 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4195 _ => None,
4196 }
4197 }
4198
4199 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4200 match &self.mode {
4201 LspStoreMode::Remote(RemoteLspStore {
4202 upstream_client: Some(upstream_client),
4203 upstream_project_id,
4204 ..
4205 }) => Some((upstream_client.clone(), *upstream_project_id)),
4206
4207 LspStoreMode::Remote(RemoteLspStore {
4208 upstream_client: None,
4209 ..
4210 }) => None,
4211 LspStoreMode::Local(_) => None,
4212 }
4213 }
4214
4215 pub fn new_local(
4216 buffer_store: Entity<BufferStore>,
4217 worktree_store: Entity<WorktreeStore>,
4218 prettier_store: Entity<PrettierStore>,
4219 toolchain_store: Entity<LocalToolchainStore>,
4220 environment: Entity<ProjectEnvironment>,
4221 manifest_tree: Entity<ManifestTree>,
4222 languages: Arc<LanguageRegistry>,
4223 http_client: Arc<dyn HttpClient>,
4224 fs: Arc<dyn Fs>,
4225 cx: &mut Context<Self>,
4226 ) -> Self {
4227 let yarn = YarnPathStore::new(fs.clone(), cx);
4228 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4229 .detach();
4230 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4231 .detach();
4232 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4233 .detach();
4234 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4235 .detach();
4236 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4237 .detach();
4238 subscribe_to_binary_statuses(&languages, cx).detach();
4239
4240 let _maintain_workspace_config = {
4241 let (sender, receiver) = watch::channel();
4242 (Self::maintain_workspace_config(receiver, cx), sender)
4243 };
4244
4245 Self {
4246 mode: LspStoreMode::Local(LocalLspStore {
4247 weak: cx.weak_entity(),
4248 worktree_store: worktree_store.clone(),
4249
4250 supplementary_language_servers: Default::default(),
4251 languages: languages.clone(),
4252 language_server_ids: Default::default(),
4253 language_servers: Default::default(),
4254 last_workspace_edits_by_language_server: Default::default(),
4255 language_server_watched_paths: Default::default(),
4256 language_server_paths_watched_for_rename: Default::default(),
4257 language_server_dynamic_registrations: Default::default(),
4258 buffers_being_formatted: Default::default(),
4259 buffers_to_refresh_hash_set: HashSet::default(),
4260 buffers_to_refresh_queue: VecDeque::new(),
4261 _background_diagnostics_worker: Task::ready(()).shared(),
4262 buffer_snapshots: Default::default(),
4263 prettier_store,
4264 environment,
4265 http_client,
4266 fs,
4267 yarn,
4268 next_diagnostic_group_id: Default::default(),
4269 diagnostics: Default::default(),
4270 _subscription: cx.on_app_quit(|this, _| {
4271 this.as_local_mut()
4272 .unwrap()
4273 .shutdown_language_servers_on_quit()
4274 }),
4275 lsp_tree: LanguageServerTree::new(
4276 manifest_tree,
4277 languages.clone(),
4278 toolchain_store.clone(),
4279 ),
4280 toolchain_store,
4281 registered_buffers: HashMap::default(),
4282 buffers_opened_in_servers: HashMap::default(),
4283 buffer_pull_diagnostics_result_ids: HashMap::default(),
4284 workspace_pull_diagnostics_result_ids: HashMap::default(),
4285 restricted_worktrees_tasks: HashMap::default(),
4286 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4287 .manifest_file_names(),
4288 }),
4289 last_formatting_failure: None,
4290 downstream_client: None,
4291 buffer_store,
4292 worktree_store,
4293 languages: languages.clone(),
4294 language_server_statuses: Default::default(),
4295 nonce: StdRng::from_os_rng().random(),
4296 diagnostic_summaries: HashMap::default(),
4297 lsp_server_capabilities: HashMap::default(),
4298 semantic_token_config: SemanticTokenConfig::new(cx),
4299 lsp_data: HashMap::default(),
4300 buffer_reload_tasks: HashMap::default(),
4301 next_hint_id: Arc::default(),
4302 active_entry: None,
4303 _maintain_workspace_config,
4304 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4305 }
4306 }
4307
4308 fn send_lsp_proto_request<R: LspCommand>(
4309 &self,
4310 buffer: Entity<Buffer>,
4311 client: AnyProtoClient,
4312 upstream_project_id: u64,
4313 request: R,
4314 cx: &mut Context<LspStore>,
4315 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4316 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4317 return Task::ready(Ok(R::Response::default()));
4318 }
4319 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4320 cx.spawn(async move |this, cx| {
4321 let response = client.request(message).await?;
4322 let this = this.upgrade().context("project dropped")?;
4323 request
4324 .response_from_proto(response, this, buffer, cx.clone())
4325 .await
4326 })
4327 }
4328
4329 pub(super) fn new_remote(
4330 buffer_store: Entity<BufferStore>,
4331 worktree_store: Entity<WorktreeStore>,
4332 languages: Arc<LanguageRegistry>,
4333 upstream_client: AnyProtoClient,
4334 project_id: u64,
4335 cx: &mut Context<Self>,
4336 ) -> Self {
4337 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4338 .detach();
4339 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4340 .detach();
4341 subscribe_to_binary_statuses(&languages, cx).detach();
4342 let _maintain_workspace_config = {
4343 let (sender, receiver) = watch::channel();
4344 (Self::maintain_workspace_config(receiver, cx), sender)
4345 };
4346 Self {
4347 mode: LspStoreMode::Remote(RemoteLspStore {
4348 upstream_client: Some(upstream_client),
4349 upstream_project_id: project_id,
4350 }),
4351 downstream_client: None,
4352 last_formatting_failure: None,
4353 buffer_store,
4354 worktree_store,
4355 languages: languages.clone(),
4356 language_server_statuses: Default::default(),
4357 nonce: StdRng::from_os_rng().random(),
4358 diagnostic_summaries: HashMap::default(),
4359 lsp_server_capabilities: HashMap::default(),
4360 semantic_token_config: SemanticTokenConfig::new(cx),
4361 next_hint_id: Arc::default(),
4362 lsp_data: HashMap::default(),
4363 buffer_reload_tasks: HashMap::default(),
4364 active_entry: None,
4365
4366 _maintain_workspace_config,
4367 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4368 }
4369 }
4370
4371 fn on_buffer_store_event(
4372 &mut self,
4373 _: Entity<BufferStore>,
4374 event: &BufferStoreEvent,
4375 cx: &mut Context<Self>,
4376 ) {
4377 match event {
4378 BufferStoreEvent::BufferAdded(buffer) => {
4379 self.on_buffer_added(buffer, cx).log_err();
4380 }
4381 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4382 let buffer_id = buffer.read(cx).remote_id();
4383 if let Some(local) = self.as_local_mut()
4384 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4385 {
4386 local.reset_buffer(buffer, old_file, cx);
4387
4388 if local.registered_buffers.contains_key(&buffer_id) {
4389 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4390 }
4391 }
4392
4393 self.detect_language_for_buffer(buffer, cx);
4394 if let Some(local) = self.as_local_mut() {
4395 local.initialize_buffer(buffer, cx);
4396 if local.registered_buffers.contains_key(&buffer_id) {
4397 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4398 }
4399 }
4400 }
4401 _ => {}
4402 }
4403 }
4404
4405 fn on_worktree_store_event(
4406 &mut self,
4407 _: Entity<WorktreeStore>,
4408 event: &WorktreeStoreEvent,
4409 cx: &mut Context<Self>,
4410 ) {
4411 match event {
4412 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4413 if !worktree.read(cx).is_local() {
4414 return;
4415 }
4416 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4417 worktree::Event::UpdatedEntries(changes) => {
4418 this.update_local_worktree_language_servers(&worktree, changes, cx);
4419 }
4420 worktree::Event::UpdatedGitRepositories(_)
4421 | worktree::Event::DeletedEntry(_) => {}
4422 })
4423 .detach()
4424 }
4425 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4426 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4427 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4428 }
4429 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4430 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4431 }
4432 WorktreeStoreEvent::WorktreeReleased(..)
4433 | WorktreeStoreEvent::WorktreeOrderChanged
4434 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4435 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4436 }
4437 }
4438
4439 fn on_prettier_store_event(
4440 &mut self,
4441 _: Entity<PrettierStore>,
4442 event: &PrettierStoreEvent,
4443 cx: &mut Context<Self>,
4444 ) {
4445 match event {
4446 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4447 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4448 }
4449 PrettierStoreEvent::LanguageServerAdded {
4450 new_server_id,
4451 name,
4452 prettier_server,
4453 } => {
4454 self.register_supplementary_language_server(
4455 *new_server_id,
4456 name.clone(),
4457 prettier_server.clone(),
4458 cx,
4459 );
4460 }
4461 }
4462 }
4463
4464 fn on_toolchain_store_event(
4465 &mut self,
4466 _: Entity<LocalToolchainStore>,
4467 event: &ToolchainStoreEvent,
4468 _: &mut Context<Self>,
4469 ) {
4470 if let ToolchainStoreEvent::ToolchainActivated = event {
4471 self.request_workspace_config_refresh()
4472 }
4473 }
4474
4475 fn request_workspace_config_refresh(&mut self) {
4476 *self._maintain_workspace_config.1.borrow_mut() = ();
4477 }
4478
4479 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4480 self.as_local().map(|local| local.prettier_store.clone())
4481 }
4482
4483 fn on_buffer_event(
4484 &mut self,
4485 buffer: Entity<Buffer>,
4486 event: &language::BufferEvent,
4487 cx: &mut Context<Self>,
4488 ) {
4489 match event {
4490 language::BufferEvent::Edited { .. } => {
4491 self.on_buffer_edited(buffer, cx);
4492 }
4493
4494 language::BufferEvent::Saved => {
4495 self.on_buffer_saved(buffer, cx);
4496 }
4497
4498 language::BufferEvent::Reloaded => {
4499 self.on_buffer_reloaded(buffer, cx);
4500 }
4501
4502 _ => {}
4503 }
4504 }
4505
4506 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4507 buffer
4508 .read(cx)
4509 .set_language_registry(self.languages.clone());
4510
4511 cx.subscribe(buffer, |this, buffer, event, cx| {
4512 this.on_buffer_event(buffer, event, cx);
4513 })
4514 .detach();
4515
4516 self.parse_modeline(buffer, cx);
4517 self.detect_language_for_buffer(buffer, cx);
4518 if let Some(local) = self.as_local_mut() {
4519 local.initialize_buffer(buffer, cx);
4520 }
4521
4522 Ok(())
4523 }
4524
4525 pub fn refresh_background_diagnostics_for_buffers(
4526 &mut self,
4527 buffers: HashSet<BufferId>,
4528 cx: &mut Context<Self>,
4529 ) -> Shared<Task<()>> {
4530 let Some(local) = self.as_local_mut() else {
4531 return Task::ready(()).shared();
4532 };
4533 for buffer in buffers {
4534 if local.buffers_to_refresh_hash_set.insert(buffer) {
4535 local.buffers_to_refresh_queue.push_back(buffer);
4536 if local.buffers_to_refresh_queue.len() == 1 {
4537 local._background_diagnostics_worker =
4538 Self::background_diagnostics_worker(cx).shared();
4539 }
4540 }
4541 }
4542
4543 local._background_diagnostics_worker.clone()
4544 }
4545
4546 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4547 let buffer_store = self.buffer_store.clone();
4548 let local = self.as_local_mut()?;
4549 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4550 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4551 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4552 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4553 }
4554 }
4555 None
4556 }
4557
4558 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4559 cx.spawn(async move |this, cx| {
4560 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4561 task.await.log_err();
4562 }
4563 })
4564 }
4565
4566 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4567 if self.parse_modeline(&buffer, cx) {
4568 self.detect_language_for_buffer(&buffer, cx);
4569 }
4570
4571 let buffer_id = buffer.read(cx).remote_id();
4572 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4573 self.buffer_reload_tasks.insert(buffer_id, task);
4574 }
4575
4576 pub(crate) fn register_buffer_with_language_servers(
4577 &mut self,
4578 buffer: &Entity<Buffer>,
4579 only_register_servers: HashSet<LanguageServerSelector>,
4580 ignore_refcounts: bool,
4581 cx: &mut Context<Self>,
4582 ) -> OpenLspBufferHandle {
4583 let buffer_id = buffer.read(cx).remote_id();
4584 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4585 if let Some(local) = self.as_local_mut() {
4586 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4587 if !ignore_refcounts {
4588 *refcount += 1;
4589 }
4590
4591 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4592 // 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
4593 // 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
4594 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4595 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4596 return handle;
4597 };
4598 if !file.is_local() {
4599 return handle;
4600 }
4601
4602 if ignore_refcounts || *refcount == 1 {
4603 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4604 }
4605 if !ignore_refcounts {
4606 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4607 let refcount = {
4608 let local = lsp_store.as_local_mut().unwrap();
4609 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4610 debug_panic!("bad refcounting");
4611 return;
4612 };
4613
4614 *refcount -= 1;
4615 *refcount
4616 };
4617 if refcount == 0 {
4618 lsp_store.lsp_data.remove(&buffer_id);
4619 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4620 let local = lsp_store.as_local_mut().unwrap();
4621 local.registered_buffers.remove(&buffer_id);
4622
4623 local.buffers_opened_in_servers.remove(&buffer_id);
4624 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4625 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4626
4627 let buffer_abs_path = file.abs_path(cx);
4628 for (_, buffer_pull_diagnostics_result_ids) in
4629 &mut local.buffer_pull_diagnostics_result_ids
4630 {
4631 buffer_pull_diagnostics_result_ids.retain(
4632 |_, buffer_result_ids| {
4633 buffer_result_ids.remove(&buffer_abs_path);
4634 !buffer_result_ids.is_empty()
4635 },
4636 );
4637 }
4638
4639 let diagnostic_updates = local
4640 .language_servers
4641 .keys()
4642 .cloned()
4643 .map(|server_id| DocumentDiagnosticsUpdate {
4644 diagnostics: DocumentDiagnostics {
4645 document_abs_path: buffer_abs_path.clone(),
4646 version: None,
4647 diagnostics: Vec::new(),
4648 },
4649 result_id: None,
4650 registration_id: None,
4651 server_id,
4652 disk_based_sources: Cow::Borrowed(&[]),
4653 })
4654 .collect::<Vec<_>>();
4655
4656 lsp_store
4657 .merge_diagnostic_entries(
4658 diagnostic_updates,
4659 |_, diagnostic, _| {
4660 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4661 },
4662 cx,
4663 )
4664 .context("Clearing diagnostics for the closed buffer")
4665 .log_err();
4666 }
4667 }
4668 })
4669 .detach();
4670 }
4671 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4672 let buffer_id = buffer.read(cx).remote_id().to_proto();
4673 cx.background_spawn(async move {
4674 upstream_client
4675 .request(proto::RegisterBufferWithLanguageServers {
4676 project_id: upstream_project_id,
4677 buffer_id,
4678 only_servers: only_register_servers
4679 .into_iter()
4680 .map(|selector| {
4681 let selector = match selector {
4682 LanguageServerSelector::Id(language_server_id) => {
4683 proto::language_server_selector::Selector::ServerId(
4684 language_server_id.to_proto(),
4685 )
4686 }
4687 LanguageServerSelector::Name(language_server_name) => {
4688 proto::language_server_selector::Selector::Name(
4689 language_server_name.to_string(),
4690 )
4691 }
4692 };
4693 proto::LanguageServerSelector {
4694 selector: Some(selector),
4695 }
4696 })
4697 .collect(),
4698 })
4699 .await
4700 })
4701 .detach();
4702 } else {
4703 // Our remote connection got closed
4704 }
4705 handle
4706 }
4707
4708 fn maintain_buffer_languages(
4709 languages: Arc<LanguageRegistry>,
4710 cx: &mut Context<Self>,
4711 ) -> Task<()> {
4712 let mut subscription = languages.subscribe();
4713 let mut prev_reload_count = languages.reload_count();
4714 cx.spawn(async move |this, cx| {
4715 while let Some(()) = subscription.next().await {
4716 if let Some(this) = this.upgrade() {
4717 // If the language registry has been reloaded, then remove and
4718 // re-assign the languages on all open buffers.
4719 let reload_count = languages.reload_count();
4720 if reload_count > prev_reload_count {
4721 prev_reload_count = reload_count;
4722 this.update(cx, |this, cx| {
4723 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4724 for buffer in buffer_store.buffers() {
4725 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4726 {
4727 buffer.update(cx, |buffer, cx| {
4728 buffer.set_language_async(None, cx)
4729 });
4730 if let Some(local) = this.as_local_mut() {
4731 local.reset_buffer(&buffer, &f, cx);
4732
4733 if local
4734 .registered_buffers
4735 .contains_key(&buffer.read(cx).remote_id())
4736 && let Some(file_url) =
4737 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4738 {
4739 local.unregister_buffer_from_language_servers(
4740 &buffer, &file_url, cx,
4741 );
4742 }
4743 }
4744 }
4745 }
4746 });
4747 });
4748 }
4749
4750 this.update(cx, |this, cx| {
4751 let mut plain_text_buffers = Vec::new();
4752 let mut buffers_with_unknown_injections = Vec::new();
4753 for handle in this.buffer_store.read(cx).buffers() {
4754 let buffer = handle.read(cx);
4755 if buffer.language().is_none()
4756 || buffer.language() == Some(&*language::PLAIN_TEXT)
4757 {
4758 plain_text_buffers.push(handle);
4759 } else if buffer.contains_unknown_injections() {
4760 buffers_with_unknown_injections.push(handle);
4761 }
4762 }
4763
4764 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4765 // and reused later in the invisible worktrees.
4766 plain_text_buffers.sort_by_key(|buffer| {
4767 Reverse(
4768 File::from_dyn(buffer.read(cx).file())
4769 .map(|file| file.worktree.read(cx).is_visible()),
4770 )
4771 });
4772
4773 for buffer in plain_text_buffers {
4774 this.detect_language_for_buffer(&buffer, cx);
4775 if let Some(local) = this.as_local_mut() {
4776 local.initialize_buffer(&buffer, cx);
4777 if local
4778 .registered_buffers
4779 .contains_key(&buffer.read(cx).remote_id())
4780 {
4781 local.register_buffer_with_language_servers(
4782 &buffer,
4783 HashSet::default(),
4784 cx,
4785 );
4786 }
4787 }
4788 }
4789
4790 for buffer in buffers_with_unknown_injections {
4791 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4792 }
4793 });
4794 }
4795 }
4796 })
4797 }
4798
4799 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4800 let buffer = buffer_handle.read(cx);
4801 let content = buffer.as_rope();
4802
4803 let modeline_settings = {
4804 let settings_store = cx.global::<SettingsStore>();
4805 let modeline_lines = settings_store
4806 .raw_user_settings()
4807 .and_then(|s| s.content.modeline_lines)
4808 .or(settings_store.raw_default_settings().modeline_lines)
4809 .unwrap_or(5);
4810
4811 const MAX_MODELINE_BYTES: usize = 1024;
4812
4813 let first_bytes =
4814 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4815 let mut first_lines = Vec::new();
4816 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4817 for _ in 0..modeline_lines {
4818 if let Some(line) = lines.next() {
4819 first_lines.push(line.to_string());
4820 } else {
4821 break;
4822 }
4823 }
4824 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4825
4826 let last_start =
4827 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4828 let mut last_lines = Vec::new();
4829 let mut lines = content
4830 .reversed_chunks_in_range(last_start..content.len())
4831 .lines();
4832 for _ in 0..modeline_lines {
4833 if let Some(line) = lines.next() {
4834 last_lines.push(line.to_string());
4835 } else {
4836 break;
4837 }
4838 }
4839 let last_lines_ref: Vec<_> =
4840 last_lines.iter().rev().map(|line| line.as_str()).collect();
4841 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4842 };
4843
4844 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4845
4846 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4847 }
4848
4849 fn detect_language_for_buffer(
4850 &mut self,
4851 buffer_handle: &Entity<Buffer>,
4852 cx: &mut Context<Self>,
4853 ) -> Option<language::AvailableLanguage> {
4854 // If the buffer has a language, set it and start the language server if we haven't already.
4855 let buffer = buffer_handle.read(cx);
4856 let file = buffer.file()?;
4857 let content = buffer.as_rope();
4858 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4859
4860 let available_language = if let Some(ModelineSettings {
4861 mode: Some(mode_name),
4862 ..
4863 }) = modeline_settings
4864 {
4865 self.languages
4866 .available_language_for_modeline_name(mode_name)
4867 } else {
4868 self.languages.language_for_file(file, Some(content), cx)
4869 };
4870 if let Some(available_language) = &available_language {
4871 if let Some(Ok(Ok(new_language))) = self
4872 .languages
4873 .load_language(available_language)
4874 .now_or_never()
4875 {
4876 self.set_language_for_buffer(buffer_handle, new_language, cx);
4877 }
4878 } else {
4879 cx.emit(LspStoreEvent::LanguageDetected {
4880 buffer: buffer_handle.clone(),
4881 new_language: None,
4882 });
4883 }
4884
4885 available_language
4886 }
4887
4888 pub(crate) fn set_language_for_buffer(
4889 &mut self,
4890 buffer_entity: &Entity<Buffer>,
4891 new_language: Arc<Language>,
4892 cx: &mut Context<Self>,
4893 ) {
4894 let buffer = buffer_entity.read(cx);
4895 let buffer_file = buffer.file().cloned();
4896 let buffer_id = buffer.remote_id();
4897 if let Some(local_store) = self.as_local_mut()
4898 && local_store.registered_buffers.contains_key(&buffer_id)
4899 && let Some(abs_path) =
4900 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4901 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4902 {
4903 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4904 }
4905 buffer_entity.update(cx, |buffer, cx| {
4906 if buffer
4907 .language()
4908 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4909 {
4910 buffer.set_language_async(Some(new_language.clone()), cx);
4911 }
4912 });
4913
4914 let settings = LanguageSettings::resolve(
4915 Some(&buffer_entity.read(cx)),
4916 Some(&new_language.name()),
4917 cx,
4918 )
4919 .into_owned();
4920 let buffer_file = File::from_dyn(buffer_file.as_ref());
4921
4922 let worktree_id = if let Some(file) = buffer_file {
4923 let worktree = file.worktree.clone();
4924
4925 if let Some(local) = self.as_local_mut()
4926 && local.registered_buffers.contains_key(&buffer_id)
4927 {
4928 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4929 }
4930 Some(worktree.read(cx).id())
4931 } else {
4932 None
4933 };
4934
4935 if settings.prettier.allowed
4936 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4937 {
4938 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4939 if let Some(prettier_store) = prettier_store {
4940 prettier_store.update(cx, |prettier_store, cx| {
4941 prettier_store.install_default_prettier(
4942 worktree_id,
4943 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4944 cx,
4945 )
4946 })
4947 }
4948 }
4949
4950 cx.emit(LspStoreEvent::LanguageDetected {
4951 buffer: buffer_entity.clone(),
4952 new_language: Some(new_language),
4953 })
4954 }
4955
4956 pub fn buffer_store(&self) -> Entity<BufferStore> {
4957 self.buffer_store.clone()
4958 }
4959
4960 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4961 self.active_entry = active_entry;
4962 }
4963
4964 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4965 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4966 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4967 {
4968 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4969 summaries
4970 .iter()
4971 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4972 });
4973 if let Some(summary) = summaries.next() {
4974 client
4975 .send(proto::UpdateDiagnosticSummary {
4976 project_id: downstream_project_id,
4977 worktree_id: worktree.id().to_proto(),
4978 summary: Some(summary),
4979 more_summaries: summaries.collect(),
4980 })
4981 .log_err();
4982 }
4983 }
4984 }
4985
4986 fn is_capable_for_proto_request<R>(
4987 &self,
4988 buffer: &Entity<Buffer>,
4989 request: &R,
4990 cx: &App,
4991 ) -> bool
4992 where
4993 R: LspCommand,
4994 {
4995 self.check_if_capable_for_proto_request(
4996 buffer,
4997 |capabilities| {
4998 request.check_capabilities(AdapterServerCapabilities {
4999 server_capabilities: capabilities.clone(),
5000 code_action_kinds: None,
5001 })
5002 },
5003 cx,
5004 )
5005 }
5006
5007 fn check_if_capable_for_proto_request<F>(
5008 &self,
5009 buffer: &Entity<Buffer>,
5010 check: F,
5011 cx: &App,
5012 ) -> bool
5013 where
5014 F: FnMut(&lsp::ServerCapabilities) -> bool,
5015 {
5016 let Some(language) = buffer.read(cx).language().cloned() else {
5017 return false;
5018 };
5019 let registered_language_servers = self
5020 .languages
5021 .lsp_adapters(&language.name())
5022 .into_iter()
5023 .map(|lsp_adapter| lsp_adapter.name())
5024 .collect::<HashSet<_>>();
5025 self.language_server_statuses
5026 .iter()
5027 .filter_map(|(server_id, server_status)| {
5028 // Include servers that are either registered for this language OR
5029 // available to be loaded (for SSH remote mode where adapters like
5030 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5031 // but only loaded on the server side)
5032 let is_relevant = registered_language_servers.contains(&server_status.name)
5033 || self.languages.is_lsp_adapter_available(&server_status.name);
5034 is_relevant.then_some(server_id)
5035 })
5036 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
5037 .any(check)
5038 }
5039
5040 fn all_capable_for_proto_request<F>(
5041 &self,
5042 buffer: &Entity<Buffer>,
5043 mut check: F,
5044 cx: &App,
5045 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5046 where
5047 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5048 {
5049 let Some(language) = buffer.read(cx).language().cloned() else {
5050 return Vec::default();
5051 };
5052 let registered_language_servers = self
5053 .languages
5054 .lsp_adapters(&language.name())
5055 .into_iter()
5056 .map(|lsp_adapter| lsp_adapter.name())
5057 .collect::<HashSet<_>>();
5058 self.language_server_statuses
5059 .iter()
5060 .filter_map(|(server_id, server_status)| {
5061 // Include servers that are either registered for this language OR
5062 // available to be loaded (for SSH remote mode where adapters like
5063 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5064 // but only loaded on the server side)
5065 let is_relevant = registered_language_servers.contains(&server_status.name)
5066 || self.languages.is_lsp_adapter_available(&server_status.name);
5067 is_relevant.then_some((server_id, &server_status.name))
5068 })
5069 .filter_map(|(server_id, server_name)| {
5070 self.lsp_server_capabilities
5071 .get(server_id)
5072 .map(|c| (server_id, server_name, c))
5073 })
5074 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5075 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5076 .collect()
5077 }
5078
5079 pub fn request_lsp<R>(
5080 &mut self,
5081 buffer: Entity<Buffer>,
5082 server: LanguageServerToQuery,
5083 request: R,
5084 cx: &mut Context<Self>,
5085 ) -> Task<Result<R::Response>>
5086 where
5087 R: LspCommand,
5088 <R::LspRequest as lsp::request::Request>::Result: Send,
5089 <R::LspRequest as lsp::request::Request>::Params: Send,
5090 {
5091 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5092 return self.send_lsp_proto_request(
5093 buffer,
5094 upstream_client,
5095 upstream_project_id,
5096 request,
5097 cx,
5098 );
5099 }
5100
5101 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5102 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5103 local
5104 .language_servers_for_buffer(buffer, cx)
5105 .find(|(_, server)| {
5106 request.check_capabilities(server.adapter_server_capabilities())
5107 })
5108 .map(|(_, server)| server.clone())
5109 }),
5110 LanguageServerToQuery::Other(id) => self
5111 .language_server_for_local_buffer(buffer, id, cx)
5112 .and_then(|(_, server)| {
5113 request
5114 .check_capabilities(server.adapter_server_capabilities())
5115 .then(|| Arc::clone(server))
5116 }),
5117 }) else {
5118 return Task::ready(Ok(Default::default()));
5119 };
5120
5121 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5122
5123 let Some(file) = file else {
5124 return Task::ready(Ok(Default::default()));
5125 };
5126
5127 let lsp_params = match request.to_lsp_params_or_response(
5128 &file.abs_path(cx),
5129 buffer.read(cx),
5130 &language_server,
5131 cx,
5132 ) {
5133 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5134 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5135 Err(err) => {
5136 let message = format!(
5137 "{} via {} failed: {}",
5138 request.display_name(),
5139 language_server.name(),
5140 err
5141 );
5142 // rust-analyzer likes to error with this when its still loading up
5143 if !message.ends_with("content modified") {
5144 log::warn!("{message}");
5145 }
5146 return Task::ready(Err(anyhow!(message)));
5147 }
5148 };
5149
5150 let status = request.status();
5151 let request_timeout = ProjectSettings::get_global(cx)
5152 .global_lsp_settings
5153 .get_request_timeout();
5154
5155 cx.spawn(async move |this, cx| {
5156 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5157
5158 let id = lsp_request.id();
5159 let _cleanup = if status.is_some() {
5160 cx.update(|cx| {
5161 this.update(cx, |this, cx| {
5162 this.on_lsp_work_start(
5163 language_server.server_id(),
5164 ProgressToken::Number(id),
5165 LanguageServerProgress {
5166 is_disk_based_diagnostics_progress: false,
5167 is_cancellable: false,
5168 title: None,
5169 message: status.clone(),
5170 percentage: None,
5171 last_update_at: cx.background_executor().now(),
5172 },
5173 cx,
5174 );
5175 })
5176 })
5177 .log_err();
5178
5179 Some(defer(|| {
5180 cx.update(|cx| {
5181 this.update(cx, |this, cx| {
5182 this.on_lsp_work_end(
5183 language_server.server_id(),
5184 ProgressToken::Number(id),
5185 cx,
5186 );
5187 })
5188 })
5189 .log_err();
5190 }))
5191 } else {
5192 None
5193 };
5194
5195 let result = lsp_request.await.into_response();
5196
5197 let response = result.map_err(|err| {
5198 let message = format!(
5199 "{} via {} failed: {}",
5200 request.display_name(),
5201 language_server.name(),
5202 err
5203 );
5204 // rust-analyzer likes to error with this when its still loading up
5205 if !message.ends_with("content modified") {
5206 log::warn!("{message}");
5207 }
5208 anyhow::anyhow!(message)
5209 })?;
5210
5211 request
5212 .response_from_lsp(
5213 response,
5214 this.upgrade().context("no app context")?,
5215 buffer,
5216 language_server.server_id(),
5217 cx.clone(),
5218 )
5219 .await
5220 })
5221 }
5222
5223 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5224 let mut language_formatters_to_check = Vec::new();
5225 for buffer in self.buffer_store.read(cx).buffers() {
5226 let buffer = buffer.read(cx);
5227 let settings = LanguageSettings::for_buffer(buffer, cx);
5228 if buffer.language().is_some() {
5229 let buffer_file = File::from_dyn(buffer.file());
5230 language_formatters_to_check.push((
5231 buffer_file.map(|f| f.worktree_id(cx)),
5232 settings.into_owned(),
5233 ));
5234 }
5235 }
5236
5237 self.request_workspace_config_refresh();
5238
5239 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5240 prettier_store.update(cx, |prettier_store, cx| {
5241 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5242 })
5243 }
5244
5245 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5246 .global_lsp_settings
5247 .semantic_token_rules
5248 .clone();
5249 self.semantic_token_config
5250 .update_rules(new_semantic_token_rules);
5251 // Always clear cached stylizers so that changes to language-specific
5252 // semantic token rules (e.g. from extension install/uninstall) are
5253 // picked up. Stylizers are recreated lazily, so this is cheap.
5254 self.semantic_token_config.clear_stylizers();
5255
5256 let new_global_semantic_tokens_mode =
5257 all_language_settings(None, cx).defaults.semantic_tokens;
5258 if self
5259 .semantic_token_config
5260 .update_global_mode(new_global_semantic_tokens_mode)
5261 {
5262 self.restart_all_language_servers(cx);
5263 }
5264
5265 cx.notify();
5266 }
5267
5268 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5269 let buffer_store = self.buffer_store.clone();
5270 let Some(local) = self.as_local_mut() else {
5271 return;
5272 };
5273 let mut adapters = BTreeMap::default();
5274 let get_adapter = {
5275 let languages = local.languages.clone();
5276 let environment = local.environment.clone();
5277 let weak = local.weak.clone();
5278 let worktree_store = local.worktree_store.clone();
5279 let http_client = local.http_client.clone();
5280 let fs = local.fs.clone();
5281 move |worktree_id, cx: &mut App| {
5282 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5283 Some(LocalLspAdapterDelegate::new(
5284 languages.clone(),
5285 &environment,
5286 weak.clone(),
5287 &worktree,
5288 http_client.clone(),
5289 fs.clone(),
5290 cx,
5291 ))
5292 }
5293 };
5294
5295 let mut messages_to_report = Vec::new();
5296 let (new_tree, to_stop) = {
5297 let mut rebase = local.lsp_tree.rebase();
5298 let buffers = buffer_store
5299 .read(cx)
5300 .buffers()
5301 .filter_map(|buffer| {
5302 let raw_buffer = buffer.read(cx);
5303 if !local
5304 .registered_buffers
5305 .contains_key(&raw_buffer.remote_id())
5306 {
5307 return None;
5308 }
5309 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5310 let language = raw_buffer.language().cloned()?;
5311 Some((file, language, raw_buffer.remote_id()))
5312 })
5313 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5314 for (file, language, buffer_id) in buffers {
5315 let worktree_id = file.worktree_id(cx);
5316 let Some(worktree) = local
5317 .worktree_store
5318 .read(cx)
5319 .worktree_for_id(worktree_id, cx)
5320 else {
5321 continue;
5322 };
5323
5324 if let Some((_, apply)) = local.reuse_existing_language_server(
5325 rebase.server_tree(),
5326 &worktree,
5327 &language.name(),
5328 cx,
5329 ) {
5330 (apply)(rebase.server_tree());
5331 } else if let Some(lsp_delegate) = adapters
5332 .entry(worktree_id)
5333 .or_insert_with(|| get_adapter(worktree_id, cx))
5334 .clone()
5335 {
5336 let delegate =
5337 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5338 let path = file
5339 .path()
5340 .parent()
5341 .map(Arc::from)
5342 .unwrap_or_else(|| file.path().clone());
5343 let worktree_path = ProjectPath { worktree_id, path };
5344 let abs_path = file.abs_path(cx);
5345 let nodes = rebase
5346 .walk(
5347 worktree_path,
5348 language.name(),
5349 language.manifest(),
5350 delegate.clone(),
5351 cx,
5352 )
5353 .collect::<Vec<_>>();
5354 for node in nodes {
5355 let server_id = node.server_id_or_init(|disposition| {
5356 let path = &disposition.path;
5357 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5358 let key = LanguageServerSeed {
5359 worktree_id,
5360 name: disposition.server_name.clone(),
5361 settings: LanguageServerSeedSettings {
5362 binary: disposition.settings.binary.clone(),
5363 initialization_options: disposition
5364 .settings
5365 .initialization_options
5366 .clone(),
5367 },
5368 toolchain: local.toolchain_store.read(cx).active_toolchain(
5369 path.worktree_id,
5370 &path.path,
5371 language.name(),
5372 ),
5373 };
5374 local.language_server_ids.remove(&key);
5375
5376 let server_id = local.get_or_insert_language_server(
5377 &worktree,
5378 lsp_delegate.clone(),
5379 disposition,
5380 &language.name(),
5381 cx,
5382 );
5383 if let Some(state) = local.language_servers.get(&server_id)
5384 && let Ok(uri) = uri
5385 {
5386 state.add_workspace_folder(uri);
5387 };
5388 server_id
5389 });
5390
5391 if let Some(language_server_id) = server_id {
5392 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5393 language_server_id,
5394 name: node.name(),
5395 message:
5396 proto::update_language_server::Variant::RegisteredForBuffer(
5397 proto::RegisteredForBuffer {
5398 buffer_abs_path: abs_path
5399 .to_string_lossy()
5400 .into_owned(),
5401 buffer_id: buffer_id.to_proto(),
5402 },
5403 ),
5404 });
5405 }
5406 }
5407 } else {
5408 continue;
5409 }
5410 }
5411 rebase.finish()
5412 };
5413 for message in messages_to_report {
5414 cx.emit(message);
5415 }
5416 local.lsp_tree = new_tree;
5417 for (id, _) in to_stop {
5418 self.stop_local_language_server(id, cx).detach();
5419 }
5420 }
5421
5422 pub fn apply_code_action(
5423 &self,
5424 buffer_handle: Entity<Buffer>,
5425 mut action: CodeAction,
5426 push_to_history: bool,
5427 cx: &mut Context<Self>,
5428 ) -> Task<Result<ProjectTransaction>> {
5429 if let Some((upstream_client, project_id)) = self.upstream_client() {
5430 let request = proto::ApplyCodeAction {
5431 project_id,
5432 buffer_id: buffer_handle.read(cx).remote_id().into(),
5433 action: Some(Self::serialize_code_action(&action)),
5434 };
5435 let buffer_store = self.buffer_store();
5436 cx.spawn(async move |_, cx| {
5437 let response = upstream_client
5438 .request(request)
5439 .await?
5440 .transaction
5441 .context("missing transaction")?;
5442
5443 buffer_store
5444 .update(cx, |buffer_store, cx| {
5445 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5446 })
5447 .await
5448 })
5449 } else if self.mode.is_local() {
5450 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5451 let request_timeout = ProjectSettings::get_global(cx)
5452 .global_lsp_settings
5453 .get_request_timeout();
5454 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5455 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5456 }) else {
5457 return Task::ready(Ok(ProjectTransaction::default()));
5458 };
5459
5460 cx.spawn(async move |this, cx| {
5461 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5462 .await
5463 .context("resolving a code action")?;
5464 if let Some(edit) = action.lsp_action.edit()
5465 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5466 return LocalLspStore::deserialize_workspace_edit(
5467 this.upgrade().context("no app present")?,
5468 edit.clone(),
5469 push_to_history,
5470
5471 lang_server.clone(),
5472 cx,
5473 )
5474 .await;
5475 }
5476
5477 let Some(command) = action.lsp_action.command() else {
5478 return Ok(ProjectTransaction::default())
5479 };
5480
5481 let server_capabilities = lang_server.capabilities();
5482 let available_commands = server_capabilities
5483 .execute_command_provider
5484 .as_ref()
5485 .map(|options| options.commands.as_slice())
5486 .unwrap_or_default();
5487
5488 if !available_commands.contains(&command.command) {
5489 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5490 return Ok(ProjectTransaction::default())
5491 }
5492
5493 let request_timeout = cx.update(|app|
5494 ProjectSettings::get_global(app)
5495 .global_lsp_settings
5496 .get_request_timeout()
5497 );
5498
5499 this.update(cx, |this, _| {
5500 this.as_local_mut()
5501 .unwrap()
5502 .last_workspace_edits_by_language_server
5503 .remove(&lang_server.server_id());
5504 })?;
5505
5506 let _result = lang_server
5507 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5508 command: command.command.clone(),
5509 arguments: command.arguments.clone().unwrap_or_default(),
5510 ..lsp::ExecuteCommandParams::default()
5511 }, request_timeout)
5512 .await.into_response()
5513 .context("execute command")?;
5514
5515 return this.update(cx, |this, _| {
5516 this.as_local_mut()
5517 .unwrap()
5518 .last_workspace_edits_by_language_server
5519 .remove(&lang_server.server_id())
5520 .unwrap_or_default()
5521 });
5522 })
5523 } else {
5524 Task::ready(Err(anyhow!("no upstream client and not local")))
5525 }
5526 }
5527
5528 pub fn apply_code_action_kind(
5529 &mut self,
5530 buffers: HashSet<Entity<Buffer>>,
5531 kind: CodeActionKind,
5532 push_to_history: bool,
5533 cx: &mut Context<Self>,
5534 ) -> Task<anyhow::Result<ProjectTransaction>> {
5535 if self.as_local().is_some() {
5536 cx.spawn(async move |lsp_store, cx| {
5537 let buffers = buffers.into_iter().collect::<Vec<_>>();
5538 let result = LocalLspStore::execute_code_action_kind_locally(
5539 lsp_store.clone(),
5540 buffers,
5541 kind,
5542 push_to_history,
5543 cx,
5544 )
5545 .await;
5546 lsp_store.update(cx, |lsp_store, _| {
5547 lsp_store.update_last_formatting_failure(&result);
5548 })?;
5549 result
5550 })
5551 } else if let Some((client, project_id)) = self.upstream_client() {
5552 let buffer_store = self.buffer_store();
5553 cx.spawn(async move |lsp_store, cx| {
5554 let result = client
5555 .request(proto::ApplyCodeActionKind {
5556 project_id,
5557 kind: kind.as_str().to_owned(),
5558 buffer_ids: buffers
5559 .iter()
5560 .map(|buffer| {
5561 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5562 })
5563 .collect(),
5564 })
5565 .await
5566 .and_then(|result| result.transaction.context("missing transaction"));
5567 lsp_store.update(cx, |lsp_store, _| {
5568 lsp_store.update_last_formatting_failure(&result);
5569 })?;
5570
5571 let transaction_response = result?;
5572 buffer_store
5573 .update(cx, |buffer_store, cx| {
5574 buffer_store.deserialize_project_transaction(
5575 transaction_response,
5576 push_to_history,
5577 cx,
5578 )
5579 })
5580 .await
5581 })
5582 } else {
5583 Task::ready(Ok(ProjectTransaction::default()))
5584 }
5585 }
5586
5587 pub fn resolved_hint(
5588 &mut self,
5589 buffer_id: BufferId,
5590 id: InlayId,
5591 cx: &mut Context<Self>,
5592 ) -> Option<ResolvedHint> {
5593 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5594
5595 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5596 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5597 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5598 let (server_id, resolve_data) = match &hint.resolve_state {
5599 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5600 ResolveState::Resolving => {
5601 return Some(ResolvedHint::Resolving(
5602 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5603 ));
5604 }
5605 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5606 };
5607
5608 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5609 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5610 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5611 id,
5612 cx.spawn(async move |lsp_store, cx| {
5613 let resolved_hint = resolve_task.await;
5614 lsp_store
5615 .update(cx, |lsp_store, _| {
5616 if let Some(old_inlay_hint) = lsp_store
5617 .lsp_data
5618 .get_mut(&buffer_id)
5619 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5620 {
5621 match resolved_hint {
5622 Ok(resolved_hint) => {
5623 *old_inlay_hint = resolved_hint;
5624 }
5625 Err(e) => {
5626 old_inlay_hint.resolve_state =
5627 ResolveState::CanResolve(server_id, resolve_data);
5628 log::error!("Inlay hint resolve failed: {e:#}");
5629 }
5630 }
5631 }
5632 })
5633 .ok();
5634 })
5635 .shared(),
5636 );
5637 debug_assert!(
5638 previous_task.is_none(),
5639 "Did not change hint's resolve state after spawning its resolve"
5640 );
5641 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5642 None
5643 }
5644
5645 pub(crate) fn linked_edits(
5646 &mut self,
5647 buffer: &Entity<Buffer>,
5648 position: Anchor,
5649 cx: &mut Context<Self>,
5650 ) -> Task<Result<Vec<Range<Anchor>>>> {
5651 let snapshot = buffer.read(cx).snapshot();
5652 let scope = snapshot.language_scope_at(position);
5653 let Some(server_id) = self
5654 .as_local()
5655 .and_then(|local| {
5656 buffer.update(cx, |buffer, cx| {
5657 local
5658 .language_servers_for_buffer(buffer, cx)
5659 .filter(|(_, server)| {
5660 LinkedEditingRange::check_server_capabilities(server.capabilities())
5661 })
5662 .filter(|(adapter, _)| {
5663 scope
5664 .as_ref()
5665 .map(|scope| scope.language_allowed(&adapter.name))
5666 .unwrap_or(true)
5667 })
5668 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5669 .next()
5670 })
5671 })
5672 .or_else(|| {
5673 self.upstream_client()
5674 .is_some()
5675 .then_some(LanguageServerToQuery::FirstCapable)
5676 })
5677 .filter(|_| {
5678 maybe!({
5679 buffer.read(cx).language_at(position)?;
5680 Some(
5681 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5682 .linked_edits,
5683 )
5684 }) == Some(true)
5685 })
5686 else {
5687 return Task::ready(Ok(Vec::new()));
5688 };
5689
5690 self.request_lsp(
5691 buffer.clone(),
5692 server_id,
5693 LinkedEditingRange { position },
5694 cx,
5695 )
5696 }
5697
5698 fn apply_on_type_formatting(
5699 &mut self,
5700 buffer: Entity<Buffer>,
5701 position: Anchor,
5702 trigger: String,
5703 cx: &mut Context<Self>,
5704 ) -> Task<Result<Option<Transaction>>> {
5705 if let Some((client, project_id)) = self.upstream_client() {
5706 if !self.check_if_capable_for_proto_request(
5707 &buffer,
5708 |capabilities| {
5709 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5710 },
5711 cx,
5712 ) {
5713 return Task::ready(Ok(None));
5714 }
5715 let request = proto::OnTypeFormatting {
5716 project_id,
5717 buffer_id: buffer.read(cx).remote_id().into(),
5718 position: Some(serialize_anchor(&position)),
5719 trigger,
5720 version: serialize_version(&buffer.read(cx).version()),
5721 };
5722 cx.background_spawn(async move {
5723 client
5724 .request(request)
5725 .await?
5726 .transaction
5727 .map(language::proto::deserialize_transaction)
5728 .transpose()
5729 })
5730 } else if let Some(local) = self.as_local_mut() {
5731 let buffer_id = buffer.read(cx).remote_id();
5732 local.buffers_being_formatted.insert(buffer_id);
5733 cx.spawn(async move |this, cx| {
5734 let _cleanup = defer({
5735 let this = this.clone();
5736 let mut cx = cx.clone();
5737 move || {
5738 this.update(&mut cx, |this, _| {
5739 if let Some(local) = this.as_local_mut() {
5740 local.buffers_being_formatted.remove(&buffer_id);
5741 }
5742 })
5743 .ok();
5744 }
5745 });
5746
5747 buffer
5748 .update(cx, |buffer, _| {
5749 buffer.wait_for_edits(Some(position.timestamp()))
5750 })
5751 .await?;
5752 this.update(cx, |this, cx| {
5753 let position = position.to_point_utf16(buffer.read(cx));
5754 this.on_type_format(buffer, position, trigger, false, cx)
5755 })?
5756 .await
5757 })
5758 } else {
5759 Task::ready(Err(anyhow!("No upstream client or local language server")))
5760 }
5761 }
5762
5763 pub fn on_type_format<T: ToPointUtf16>(
5764 &mut self,
5765 buffer: Entity<Buffer>,
5766 position: T,
5767 trigger: String,
5768 push_to_history: bool,
5769 cx: &mut Context<Self>,
5770 ) -> Task<Result<Option<Transaction>>> {
5771 let position = position.to_point_utf16(buffer.read(cx));
5772 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5773 }
5774
5775 fn on_type_format_impl(
5776 &mut self,
5777 buffer: Entity<Buffer>,
5778 position: PointUtf16,
5779 trigger: String,
5780 push_to_history: bool,
5781 cx: &mut Context<Self>,
5782 ) -> Task<Result<Option<Transaction>>> {
5783 let options = buffer.update(cx, |buffer, cx| {
5784 lsp_command::lsp_formatting_options(
5785 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5786 )
5787 });
5788
5789 cx.spawn(async move |this, cx| {
5790 if let Some(waiter) =
5791 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5792 {
5793 waiter.await?;
5794 }
5795 cx.update(|cx| {
5796 this.update(cx, |this, cx| {
5797 this.request_lsp(
5798 buffer.clone(),
5799 LanguageServerToQuery::FirstCapable,
5800 OnTypeFormatting {
5801 position,
5802 trigger,
5803 options,
5804 push_to_history,
5805 },
5806 cx,
5807 )
5808 })
5809 })?
5810 .await
5811 })
5812 }
5813
5814 pub fn definitions(
5815 &mut self,
5816 buffer: &Entity<Buffer>,
5817 position: PointUtf16,
5818 cx: &mut Context<Self>,
5819 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5820 if let Some((upstream_client, project_id)) = self.upstream_client() {
5821 let request = GetDefinitions { position };
5822 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5823 return Task::ready(Ok(None));
5824 }
5825
5826 let request_timeout = ProjectSettings::get_global(cx)
5827 .global_lsp_settings
5828 .get_request_timeout();
5829
5830 let request_task = upstream_client.request_lsp(
5831 project_id,
5832 None,
5833 request_timeout,
5834 cx.background_executor().clone(),
5835 request.to_proto(project_id, buffer.read(cx)),
5836 );
5837 let buffer = buffer.clone();
5838 cx.spawn(async move |weak_lsp_store, cx| {
5839 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5840 return Ok(None);
5841 };
5842 let Some(responses) = request_task.await? else {
5843 return Ok(None);
5844 };
5845 let actions = join_all(responses.payload.into_iter().map(|response| {
5846 GetDefinitions { position }.response_from_proto(
5847 response.response,
5848 lsp_store.clone(),
5849 buffer.clone(),
5850 cx.clone(),
5851 )
5852 }))
5853 .await;
5854
5855 Ok(Some(
5856 actions
5857 .into_iter()
5858 .collect::<Result<Vec<Vec<_>>>>()?
5859 .into_iter()
5860 .flatten()
5861 .dedup()
5862 .collect(),
5863 ))
5864 })
5865 } else {
5866 let definitions_task = self.request_multiple_lsp_locally(
5867 buffer,
5868 Some(position),
5869 GetDefinitions { position },
5870 cx,
5871 );
5872 cx.background_spawn(async move {
5873 Ok(Some(
5874 definitions_task
5875 .await
5876 .into_iter()
5877 .flat_map(|(_, definitions)| definitions)
5878 .dedup()
5879 .collect(),
5880 ))
5881 })
5882 }
5883 }
5884
5885 pub fn declarations(
5886 &mut self,
5887 buffer: &Entity<Buffer>,
5888 position: PointUtf16,
5889 cx: &mut Context<Self>,
5890 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5891 if let Some((upstream_client, project_id)) = self.upstream_client() {
5892 let request = GetDeclarations { position };
5893 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5894 return Task::ready(Ok(None));
5895 }
5896 let request_timeout = ProjectSettings::get_global(cx)
5897 .global_lsp_settings
5898 .get_request_timeout();
5899 let request_task = upstream_client.request_lsp(
5900 project_id,
5901 None,
5902 request_timeout,
5903 cx.background_executor().clone(),
5904 request.to_proto(project_id, buffer.read(cx)),
5905 );
5906 let buffer = buffer.clone();
5907 cx.spawn(async move |weak_lsp_store, cx| {
5908 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5909 return Ok(None);
5910 };
5911 let Some(responses) = request_task.await? else {
5912 return Ok(None);
5913 };
5914 let actions = join_all(responses.payload.into_iter().map(|response| {
5915 GetDeclarations { position }.response_from_proto(
5916 response.response,
5917 lsp_store.clone(),
5918 buffer.clone(),
5919 cx.clone(),
5920 )
5921 }))
5922 .await;
5923
5924 Ok(Some(
5925 actions
5926 .into_iter()
5927 .collect::<Result<Vec<Vec<_>>>>()?
5928 .into_iter()
5929 .flatten()
5930 .dedup()
5931 .collect(),
5932 ))
5933 })
5934 } else {
5935 let declarations_task = self.request_multiple_lsp_locally(
5936 buffer,
5937 Some(position),
5938 GetDeclarations { position },
5939 cx,
5940 );
5941 cx.background_spawn(async move {
5942 Ok(Some(
5943 declarations_task
5944 .await
5945 .into_iter()
5946 .flat_map(|(_, declarations)| declarations)
5947 .dedup()
5948 .collect(),
5949 ))
5950 })
5951 }
5952 }
5953
5954 pub fn type_definitions(
5955 &mut self,
5956 buffer: &Entity<Buffer>,
5957 position: PointUtf16,
5958 cx: &mut Context<Self>,
5959 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5960 if let Some((upstream_client, project_id)) = self.upstream_client() {
5961 let request = GetTypeDefinitions { position };
5962 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5963 return Task::ready(Ok(None));
5964 }
5965 let request_timeout = ProjectSettings::get_global(cx)
5966 .global_lsp_settings
5967 .get_request_timeout();
5968 let request_task = upstream_client.request_lsp(
5969 project_id,
5970 None,
5971 request_timeout,
5972 cx.background_executor().clone(),
5973 request.to_proto(project_id, buffer.read(cx)),
5974 );
5975 let buffer = buffer.clone();
5976 cx.spawn(async move |weak_lsp_store, cx| {
5977 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5978 return Ok(None);
5979 };
5980 let Some(responses) = request_task.await? else {
5981 return Ok(None);
5982 };
5983 let actions = join_all(responses.payload.into_iter().map(|response| {
5984 GetTypeDefinitions { position }.response_from_proto(
5985 response.response,
5986 lsp_store.clone(),
5987 buffer.clone(),
5988 cx.clone(),
5989 )
5990 }))
5991 .await;
5992
5993 Ok(Some(
5994 actions
5995 .into_iter()
5996 .collect::<Result<Vec<Vec<_>>>>()?
5997 .into_iter()
5998 .flatten()
5999 .dedup()
6000 .collect(),
6001 ))
6002 })
6003 } else {
6004 let type_definitions_task = self.request_multiple_lsp_locally(
6005 buffer,
6006 Some(position),
6007 GetTypeDefinitions { position },
6008 cx,
6009 );
6010 cx.background_spawn(async move {
6011 Ok(Some(
6012 type_definitions_task
6013 .await
6014 .into_iter()
6015 .flat_map(|(_, type_definitions)| type_definitions)
6016 .dedup()
6017 .collect(),
6018 ))
6019 })
6020 }
6021 }
6022
6023 pub fn implementations(
6024 &mut self,
6025 buffer: &Entity<Buffer>,
6026 position: PointUtf16,
6027 cx: &mut Context<Self>,
6028 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6029 if let Some((upstream_client, project_id)) = self.upstream_client() {
6030 let request = GetImplementations { position };
6031 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6032 return Task::ready(Ok(None));
6033 }
6034
6035 let request_timeout = ProjectSettings::get_global(cx)
6036 .global_lsp_settings
6037 .get_request_timeout();
6038 let request_task = upstream_client.request_lsp(
6039 project_id,
6040 None,
6041 request_timeout,
6042 cx.background_executor().clone(),
6043 request.to_proto(project_id, buffer.read(cx)),
6044 );
6045 let buffer = buffer.clone();
6046 cx.spawn(async move |weak_lsp_store, cx| {
6047 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6048 return Ok(None);
6049 };
6050 let Some(responses) = request_task.await? else {
6051 return Ok(None);
6052 };
6053 let actions = join_all(responses.payload.into_iter().map(|response| {
6054 GetImplementations { position }.response_from_proto(
6055 response.response,
6056 lsp_store.clone(),
6057 buffer.clone(),
6058 cx.clone(),
6059 )
6060 }))
6061 .await;
6062
6063 Ok(Some(
6064 actions
6065 .into_iter()
6066 .collect::<Result<Vec<Vec<_>>>>()?
6067 .into_iter()
6068 .flatten()
6069 .dedup()
6070 .collect(),
6071 ))
6072 })
6073 } else {
6074 let implementations_task = self.request_multiple_lsp_locally(
6075 buffer,
6076 Some(position),
6077 GetImplementations { position },
6078 cx,
6079 );
6080 cx.background_spawn(async move {
6081 Ok(Some(
6082 implementations_task
6083 .await
6084 .into_iter()
6085 .flat_map(|(_, implementations)| implementations)
6086 .dedup()
6087 .collect(),
6088 ))
6089 })
6090 }
6091 }
6092
6093 pub fn references(
6094 &mut self,
6095 buffer: &Entity<Buffer>,
6096 position: PointUtf16,
6097 cx: &mut Context<Self>,
6098 ) -> Task<Result<Option<Vec<Location>>>> {
6099 if let Some((upstream_client, project_id)) = self.upstream_client() {
6100 let request = GetReferences { position };
6101 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6102 return Task::ready(Ok(None));
6103 }
6104
6105 let request_timeout = ProjectSettings::get_global(cx)
6106 .global_lsp_settings
6107 .get_request_timeout();
6108 let request_task = upstream_client.request_lsp(
6109 project_id,
6110 None,
6111 request_timeout,
6112 cx.background_executor().clone(),
6113 request.to_proto(project_id, buffer.read(cx)),
6114 );
6115 let buffer = buffer.clone();
6116 cx.spawn(async move |weak_lsp_store, cx| {
6117 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6118 return Ok(None);
6119 };
6120 let Some(responses) = request_task.await? else {
6121 return Ok(None);
6122 };
6123
6124 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6125 GetReferences { position }.response_from_proto(
6126 lsp_response.response,
6127 lsp_store.clone(),
6128 buffer.clone(),
6129 cx.clone(),
6130 )
6131 }))
6132 .await
6133 .into_iter()
6134 .collect::<Result<Vec<Vec<_>>>>()?
6135 .into_iter()
6136 .flatten()
6137 .dedup()
6138 .collect();
6139 Ok(Some(locations))
6140 })
6141 } else {
6142 let references_task = self.request_multiple_lsp_locally(
6143 buffer,
6144 Some(position),
6145 GetReferences { position },
6146 cx,
6147 );
6148 cx.background_spawn(async move {
6149 Ok(Some(
6150 references_task
6151 .await
6152 .into_iter()
6153 .flat_map(|(_, references)| references)
6154 .dedup()
6155 .collect(),
6156 ))
6157 })
6158 }
6159 }
6160
6161 pub fn code_actions(
6162 &mut self,
6163 buffer: &Entity<Buffer>,
6164 range: Range<Anchor>,
6165 kinds: Option<Vec<CodeActionKind>>,
6166 cx: &mut Context<Self>,
6167 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6168 if let Some((upstream_client, project_id)) = self.upstream_client() {
6169 let request = GetCodeActions {
6170 range: range.clone(),
6171 kinds: kinds.clone(),
6172 };
6173 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6174 return Task::ready(Ok(None));
6175 }
6176 let request_timeout = ProjectSettings::get_global(cx)
6177 .global_lsp_settings
6178 .get_request_timeout();
6179 let request_task = upstream_client.request_lsp(
6180 project_id,
6181 None,
6182 request_timeout,
6183 cx.background_executor().clone(),
6184 request.to_proto(project_id, buffer.read(cx)),
6185 );
6186 let buffer = buffer.clone();
6187 cx.spawn(async move |weak_lsp_store, cx| {
6188 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6189 return Ok(None);
6190 };
6191 let Some(responses) = request_task.await? else {
6192 return Ok(None);
6193 };
6194 let actions = join_all(responses.payload.into_iter().map(|response| {
6195 GetCodeActions {
6196 range: range.clone(),
6197 kinds: kinds.clone(),
6198 }
6199 .response_from_proto(
6200 response.response,
6201 lsp_store.clone(),
6202 buffer.clone(),
6203 cx.clone(),
6204 )
6205 }))
6206 .await;
6207
6208 Ok(Some(
6209 actions
6210 .into_iter()
6211 .collect::<Result<Vec<Vec<_>>>>()?
6212 .into_iter()
6213 .flatten()
6214 .collect(),
6215 ))
6216 })
6217 } else {
6218 let all_actions_task = self.request_multiple_lsp_locally(
6219 buffer,
6220 Some(range.start),
6221 GetCodeActions { range, kinds },
6222 cx,
6223 );
6224 cx.background_spawn(async move {
6225 Ok(Some(
6226 all_actions_task
6227 .await
6228 .into_iter()
6229 .flat_map(|(_, actions)| actions)
6230 .collect(),
6231 ))
6232 })
6233 }
6234 }
6235
6236 #[inline(never)]
6237 pub fn completions(
6238 &self,
6239 buffer: &Entity<Buffer>,
6240 position: PointUtf16,
6241 context: CompletionContext,
6242 cx: &mut Context<Self>,
6243 ) -> Task<Result<Vec<CompletionResponse>>> {
6244 let language_registry = self.languages.clone();
6245
6246 if let Some((upstream_client, project_id)) = self.upstream_client() {
6247 let snapshot = buffer.read(cx).snapshot();
6248 let offset = position.to_offset(&snapshot);
6249 let scope = snapshot.language_scope_at(offset);
6250 let capable_lsps = self.all_capable_for_proto_request(
6251 buffer,
6252 |server_name, capabilities| {
6253 capabilities.completion_provider.is_some()
6254 && scope
6255 .as_ref()
6256 .map(|scope| scope.language_allowed(server_name))
6257 .unwrap_or(true)
6258 },
6259 cx,
6260 );
6261 if capable_lsps.is_empty() {
6262 return Task::ready(Ok(Vec::new()));
6263 }
6264
6265 let language = buffer.read(cx).language().cloned();
6266
6267 let buffer = buffer.clone();
6268
6269 cx.spawn(async move |this, cx| {
6270 let requests = join_all(
6271 capable_lsps
6272 .into_iter()
6273 .map(|(id, server_name)| {
6274 let request = GetCompletions {
6275 position,
6276 context: context.clone(),
6277 server_id: Some(id),
6278 };
6279 let buffer = buffer.clone();
6280 let language = language.clone();
6281 let lsp_adapter = language.as_ref().and_then(|language| {
6282 let adapters = language_registry.lsp_adapters(&language.name());
6283 adapters
6284 .iter()
6285 .find(|adapter| adapter.name() == server_name)
6286 .or_else(|| adapters.first())
6287 .cloned()
6288 });
6289 let upstream_client = upstream_client.clone();
6290 let response = this
6291 .update(cx, |this, cx| {
6292 this.send_lsp_proto_request(
6293 buffer,
6294 upstream_client,
6295 project_id,
6296 request,
6297 cx,
6298 )
6299 })
6300 .log_err();
6301 async move {
6302 let response = response?.await.log_err()?;
6303
6304 let completions = populate_labels_for_completions(
6305 response.completions,
6306 language,
6307 lsp_adapter,
6308 )
6309 .await;
6310
6311 Some(CompletionResponse {
6312 completions,
6313 display_options: CompletionDisplayOptions::default(),
6314 is_incomplete: response.is_incomplete,
6315 })
6316 }
6317 })
6318 .collect::<Vec<_>>(),
6319 );
6320 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6321 })
6322 } else if let Some(local) = self.as_local() {
6323 let snapshot = buffer.read(cx).snapshot();
6324 let offset = position.to_offset(&snapshot);
6325 let scope = snapshot.language_scope_at(offset);
6326 let language = snapshot.language().cloned();
6327 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6328 .completions
6329 .clone();
6330 if !completion_settings.lsp {
6331 return Task::ready(Ok(Vec::new()));
6332 }
6333
6334 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6335 local
6336 .language_servers_for_buffer(buffer, cx)
6337 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6338 .filter(|(adapter, _)| {
6339 scope
6340 .as_ref()
6341 .map(|scope| scope.language_allowed(&adapter.name))
6342 .unwrap_or(true)
6343 })
6344 .map(|(_, server)| server.server_id())
6345 .collect()
6346 });
6347
6348 let buffer = buffer.clone();
6349 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6350 let lsp_timeout = if lsp_timeout > 0 {
6351 Some(Duration::from_millis(lsp_timeout))
6352 } else {
6353 None
6354 };
6355 cx.spawn(async move |this, cx| {
6356 let mut tasks = Vec::with_capacity(server_ids.len());
6357 this.update(cx, |lsp_store, cx| {
6358 for server_id in server_ids {
6359 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6360 let lsp_timeout = lsp_timeout
6361 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6362 let mut timeout = cx.background_spawn(async move {
6363 match lsp_timeout {
6364 Some(lsp_timeout) => {
6365 lsp_timeout.await;
6366 true
6367 },
6368 None => false,
6369 }
6370 }).fuse();
6371 let mut lsp_request = lsp_store.request_lsp(
6372 buffer.clone(),
6373 LanguageServerToQuery::Other(server_id),
6374 GetCompletions {
6375 position,
6376 context: context.clone(),
6377 server_id: Some(server_id),
6378 },
6379 cx,
6380 ).fuse();
6381 let new_task = cx.background_spawn(async move {
6382 select_biased! {
6383 response = lsp_request => anyhow::Ok(Some(response?)),
6384 timeout_happened = timeout => {
6385 if timeout_happened {
6386 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6387 Ok(None)
6388 } else {
6389 let completions = lsp_request.await?;
6390 Ok(Some(completions))
6391 }
6392 },
6393 }
6394 });
6395 tasks.push((lsp_adapter, new_task));
6396 }
6397 })?;
6398
6399 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6400 let completion_response = task.await.ok()??;
6401 let completions = populate_labels_for_completions(
6402 completion_response.completions,
6403 language.clone(),
6404 lsp_adapter,
6405 )
6406 .await;
6407 Some(CompletionResponse {
6408 completions,
6409 display_options: CompletionDisplayOptions::default(),
6410 is_incomplete: completion_response.is_incomplete,
6411 })
6412 });
6413
6414 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6415
6416 Ok(responses.into_iter().flatten().collect())
6417 })
6418 } else {
6419 Task::ready(Err(anyhow!("No upstream client or local language server")))
6420 }
6421 }
6422
6423 pub fn resolve_completions(
6424 &self,
6425 buffer: Entity<Buffer>,
6426 completion_indices: Vec<usize>,
6427 completions: Rc<RefCell<Box<[Completion]>>>,
6428 cx: &mut Context<Self>,
6429 ) -> Task<Result<bool>> {
6430 let client = self.upstream_client();
6431 let buffer_id = buffer.read(cx).remote_id();
6432 let buffer_snapshot = buffer.read(cx).snapshot();
6433
6434 if !self.check_if_capable_for_proto_request(
6435 &buffer,
6436 GetCompletions::can_resolve_completions,
6437 cx,
6438 ) {
6439 return Task::ready(Ok(false));
6440 }
6441 cx.spawn(async move |lsp_store, cx| {
6442 let request_timeout = cx.update(|app| {
6443 ProjectSettings::get_global(app)
6444 .global_lsp_settings
6445 .get_request_timeout()
6446 });
6447
6448 let mut did_resolve = false;
6449 if let Some((client, project_id)) = client {
6450 for completion_index in completion_indices {
6451 let server_id = {
6452 let completion = &completions.borrow()[completion_index];
6453 completion.source.server_id()
6454 };
6455 if let Some(server_id) = server_id {
6456 if Self::resolve_completion_remote(
6457 project_id,
6458 server_id,
6459 buffer_id,
6460 completions.clone(),
6461 completion_index,
6462 client.clone(),
6463 )
6464 .await
6465 .log_err()
6466 .is_some()
6467 {
6468 did_resolve = true;
6469 }
6470 } else {
6471 resolve_word_completion(
6472 &buffer_snapshot,
6473 &mut completions.borrow_mut()[completion_index],
6474 );
6475 }
6476 }
6477 } else {
6478 for completion_index in completion_indices {
6479 let server_id = {
6480 let completion = &completions.borrow()[completion_index];
6481 completion.source.server_id()
6482 };
6483 if let Some(server_id) = server_id {
6484 let server_and_adapter = lsp_store
6485 .read_with(cx, |lsp_store, _| {
6486 let server = lsp_store.language_server_for_id(server_id)?;
6487 let adapter =
6488 lsp_store.language_server_adapter_for_id(server.server_id())?;
6489 Some((server, adapter))
6490 })
6491 .ok()
6492 .flatten();
6493 let Some((server, adapter)) = server_and_adapter else {
6494 continue;
6495 };
6496
6497 let resolved = Self::resolve_completion_local(
6498 server,
6499 completions.clone(),
6500 completion_index,
6501 request_timeout,
6502 )
6503 .await
6504 .log_err()
6505 .is_some();
6506 if resolved {
6507 Self::regenerate_completion_labels(
6508 adapter,
6509 &buffer_snapshot,
6510 completions.clone(),
6511 completion_index,
6512 )
6513 .await
6514 .log_err();
6515 did_resolve = true;
6516 }
6517 } else {
6518 resolve_word_completion(
6519 &buffer_snapshot,
6520 &mut completions.borrow_mut()[completion_index],
6521 );
6522 }
6523 }
6524 }
6525
6526 Ok(did_resolve)
6527 })
6528 }
6529
6530 async fn resolve_completion_local(
6531 server: Arc<lsp::LanguageServer>,
6532 completions: Rc<RefCell<Box<[Completion]>>>,
6533 completion_index: usize,
6534 request_timeout: Duration,
6535 ) -> Result<()> {
6536 let server_id = server.server_id();
6537 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6538 return Ok(());
6539 }
6540
6541 let request = {
6542 let completion = &completions.borrow()[completion_index];
6543 match &completion.source {
6544 CompletionSource::Lsp {
6545 lsp_completion,
6546 resolved,
6547 server_id: completion_server_id,
6548 ..
6549 } => {
6550 if *resolved {
6551 return Ok(());
6552 }
6553 anyhow::ensure!(
6554 server_id == *completion_server_id,
6555 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6556 );
6557 server.request::<lsp::request::ResolveCompletionItem>(
6558 *lsp_completion.clone(),
6559 request_timeout,
6560 )
6561 }
6562 CompletionSource::BufferWord { .. }
6563 | CompletionSource::Dap { .. }
6564 | CompletionSource::Custom => {
6565 return Ok(());
6566 }
6567 }
6568 };
6569 let resolved_completion = request
6570 .await
6571 .into_response()
6572 .context("resolve completion")?;
6573
6574 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6575 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6576
6577 let mut completions = completions.borrow_mut();
6578 let completion = &mut completions[completion_index];
6579 if let CompletionSource::Lsp {
6580 lsp_completion,
6581 resolved,
6582 server_id: completion_server_id,
6583 ..
6584 } = &mut completion.source
6585 {
6586 if *resolved {
6587 return Ok(());
6588 }
6589 anyhow::ensure!(
6590 server_id == *completion_server_id,
6591 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6592 );
6593 **lsp_completion = resolved_completion;
6594 *resolved = true;
6595 }
6596 Ok(())
6597 }
6598
6599 async fn regenerate_completion_labels(
6600 adapter: Arc<CachedLspAdapter>,
6601 snapshot: &BufferSnapshot,
6602 completions: Rc<RefCell<Box<[Completion]>>>,
6603 completion_index: usize,
6604 ) -> Result<()> {
6605 let completion_item = completions.borrow()[completion_index]
6606 .source
6607 .lsp_completion(true)
6608 .map(Cow::into_owned);
6609 if let Some(lsp_documentation) = completion_item
6610 .as_ref()
6611 .and_then(|completion_item| completion_item.documentation.clone())
6612 {
6613 let mut completions = completions.borrow_mut();
6614 let completion = &mut completions[completion_index];
6615 completion.documentation = Some(lsp_documentation.into());
6616 } else {
6617 let mut completions = completions.borrow_mut();
6618 let completion = &mut completions[completion_index];
6619 completion.documentation = Some(CompletionDocumentation::Undocumented);
6620 }
6621
6622 let mut new_label = match completion_item {
6623 Some(completion_item) => {
6624 // Some language servers always return `detail` lazily via resolve, regardless of
6625 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6626 // See: https://github.com/yioneko/vtsls/issues/213
6627 let language = snapshot.language();
6628 match language {
6629 Some(language) => {
6630 adapter
6631 .labels_for_completions(
6632 std::slice::from_ref(&completion_item),
6633 language,
6634 )
6635 .await?
6636 }
6637 None => Vec::new(),
6638 }
6639 .pop()
6640 .flatten()
6641 .unwrap_or_else(|| {
6642 CodeLabel::fallback_for_completion(
6643 &completion_item,
6644 language.map(|language| language.as_ref()),
6645 )
6646 })
6647 }
6648 None => CodeLabel::plain(
6649 completions.borrow()[completion_index].new_text.clone(),
6650 None,
6651 ),
6652 };
6653 ensure_uniform_list_compatible_label(&mut new_label);
6654
6655 let mut completions = completions.borrow_mut();
6656 let completion = &mut completions[completion_index];
6657 if completion.label.filter_text() == new_label.filter_text() {
6658 completion.label = new_label;
6659 } else {
6660 log::error!(
6661 "Resolved completion changed display label from {} to {}. \
6662 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6663 completion.label.text(),
6664 new_label.text(),
6665 completion.label.filter_text(),
6666 new_label.filter_text()
6667 );
6668 }
6669
6670 Ok(())
6671 }
6672
6673 async fn resolve_completion_remote(
6674 project_id: u64,
6675 server_id: LanguageServerId,
6676 buffer_id: BufferId,
6677 completions: Rc<RefCell<Box<[Completion]>>>,
6678 completion_index: usize,
6679 client: AnyProtoClient,
6680 ) -> Result<()> {
6681 let lsp_completion = {
6682 let completion = &completions.borrow()[completion_index];
6683 match &completion.source {
6684 CompletionSource::Lsp {
6685 lsp_completion,
6686 resolved,
6687 server_id: completion_server_id,
6688 ..
6689 } => {
6690 anyhow::ensure!(
6691 server_id == *completion_server_id,
6692 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6693 );
6694 if *resolved {
6695 return Ok(());
6696 }
6697 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6698 }
6699 CompletionSource::Custom
6700 | CompletionSource::Dap { .. }
6701 | CompletionSource::BufferWord { .. } => {
6702 return Ok(());
6703 }
6704 }
6705 };
6706 let request = proto::ResolveCompletionDocumentation {
6707 project_id,
6708 language_server_id: server_id.0 as u64,
6709 lsp_completion,
6710 buffer_id: buffer_id.into(),
6711 };
6712
6713 let response = client
6714 .request(request)
6715 .await
6716 .context("completion documentation resolve proto request")?;
6717 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6718
6719 let documentation = if response.documentation.is_empty() {
6720 CompletionDocumentation::Undocumented
6721 } else if response.documentation_is_markdown {
6722 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6723 } else if response.documentation.lines().count() <= 1 {
6724 CompletionDocumentation::SingleLine(response.documentation.into())
6725 } else {
6726 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6727 };
6728
6729 let mut completions = completions.borrow_mut();
6730 let completion = &mut completions[completion_index];
6731 completion.documentation = Some(documentation);
6732 if let CompletionSource::Lsp {
6733 insert_range,
6734 lsp_completion,
6735 resolved,
6736 server_id: completion_server_id,
6737 lsp_defaults: _,
6738 } = &mut completion.source
6739 {
6740 let completion_insert_range = response
6741 .old_insert_start
6742 .and_then(deserialize_anchor)
6743 .zip(response.old_insert_end.and_then(deserialize_anchor));
6744 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6745
6746 if *resolved {
6747 return Ok(());
6748 }
6749 anyhow::ensure!(
6750 server_id == *completion_server_id,
6751 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6752 );
6753 **lsp_completion = resolved_lsp_completion;
6754 *resolved = true;
6755 }
6756
6757 let replace_range = response
6758 .old_replace_start
6759 .and_then(deserialize_anchor)
6760 .zip(response.old_replace_end.and_then(deserialize_anchor));
6761 if let Some((old_replace_start, old_replace_end)) = replace_range
6762 && !response.new_text.is_empty()
6763 {
6764 completion.new_text = response.new_text;
6765 completion.replace_range = old_replace_start..old_replace_end;
6766 }
6767
6768 Ok(())
6769 }
6770
6771 pub fn apply_additional_edits_for_completion(
6772 &self,
6773 buffer_handle: Entity<Buffer>,
6774 completions: Rc<RefCell<Box<[Completion]>>>,
6775 completion_index: usize,
6776 push_to_history: bool,
6777 all_commit_ranges: Vec<Range<language::Anchor>>,
6778 cx: &mut Context<Self>,
6779 ) -> Task<Result<Option<Transaction>>> {
6780 if let Some((client, project_id)) = self.upstream_client() {
6781 let buffer = buffer_handle.read(cx);
6782 let buffer_id = buffer.remote_id();
6783 cx.spawn(async move |_, cx| {
6784 let request = {
6785 let completion = completions.borrow()[completion_index].clone();
6786 proto::ApplyCompletionAdditionalEdits {
6787 project_id,
6788 buffer_id: buffer_id.into(),
6789 completion: Some(Self::serialize_completion(&CoreCompletion {
6790 replace_range: completion.replace_range,
6791 new_text: completion.new_text,
6792 source: completion.source,
6793 })),
6794 all_commit_ranges: all_commit_ranges
6795 .iter()
6796 .cloned()
6797 .map(language::proto::serialize_anchor_range)
6798 .collect(),
6799 }
6800 };
6801
6802 let Some(transaction) = client.request(request).await?.transaction else {
6803 return Ok(None);
6804 };
6805
6806 let transaction = language::proto::deserialize_transaction(transaction)?;
6807 buffer_handle
6808 .update(cx, |buffer, _| {
6809 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6810 })
6811 .await?;
6812 if push_to_history {
6813 buffer_handle.update(cx, |buffer, _| {
6814 buffer.push_transaction(transaction.clone(), Instant::now());
6815 buffer.finalize_last_transaction();
6816 });
6817 }
6818 Ok(Some(transaction))
6819 })
6820 } else {
6821 let request_timeout = ProjectSettings::get_global(cx)
6822 .global_lsp_settings
6823 .get_request_timeout();
6824
6825 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6826 let completion = &completions.borrow()[completion_index];
6827 let server_id = completion.source.server_id()?;
6828 Some(
6829 self.language_server_for_local_buffer(buffer, server_id, cx)?
6830 .1
6831 .clone(),
6832 )
6833 }) else {
6834 return Task::ready(Ok(None));
6835 };
6836
6837 cx.spawn(async move |this, cx| {
6838 Self::resolve_completion_local(
6839 server.clone(),
6840 completions.clone(),
6841 completion_index,
6842 request_timeout,
6843 )
6844 .await
6845 .context("resolving completion")?;
6846 let completion = completions.borrow()[completion_index].clone();
6847 let additional_text_edits = completion
6848 .source
6849 .lsp_completion(true)
6850 .as_ref()
6851 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6852 if let Some(edits) = additional_text_edits {
6853 let edits = this
6854 .update(cx, |this, cx| {
6855 this.as_local_mut().unwrap().edits_from_lsp(
6856 &buffer_handle,
6857 edits,
6858 server.server_id(),
6859 None,
6860 cx,
6861 )
6862 })?
6863 .await?;
6864
6865 buffer_handle.update(cx, |buffer, cx| {
6866 buffer.finalize_last_transaction();
6867 buffer.start_transaction();
6868
6869 for (range, text) in edits {
6870 let primary = &completion.replace_range;
6871
6872 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6873 // and the primary completion is just an insertion (empty range), then this is likely
6874 // an auto-import scenario and should not be considered overlapping
6875 // https://github.com/zed-industries/zed/issues/26136
6876 let is_file_start_auto_import = {
6877 let snapshot = buffer.snapshot();
6878 let primary_start_point = primary.start.to_point(&snapshot);
6879 let range_start_point = range.start.to_point(&snapshot);
6880
6881 let result = primary_start_point.row == 0
6882 && primary_start_point.column == 0
6883 && range_start_point.row == 0
6884 && range_start_point.column == 0;
6885
6886 result
6887 };
6888
6889 let has_overlap = if is_file_start_auto_import {
6890 false
6891 } else {
6892 all_commit_ranges.iter().any(|commit_range| {
6893 let start_within =
6894 commit_range.start.cmp(&range.start, buffer).is_le()
6895 && commit_range.end.cmp(&range.start, buffer).is_ge();
6896 let end_within =
6897 range.start.cmp(&commit_range.end, buffer).is_le()
6898 && range.end.cmp(&commit_range.end, buffer).is_ge();
6899 start_within || end_within
6900 })
6901 };
6902
6903 //Skip additional edits which overlap with the primary completion edit
6904 //https://github.com/zed-industries/zed/pull/1871
6905 if !has_overlap {
6906 buffer.edit([(range, text)], None, cx);
6907 }
6908 }
6909
6910 let transaction = if buffer.end_transaction(cx).is_some() {
6911 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6912 if !push_to_history {
6913 buffer.forget_transaction(transaction.id);
6914 }
6915 Some(transaction)
6916 } else {
6917 None
6918 };
6919 Ok(transaction)
6920 })
6921 } else {
6922 Ok(None)
6923 }
6924 })
6925 }
6926 }
6927
6928 pub fn pull_diagnostics(
6929 &mut self,
6930 buffer: Entity<Buffer>,
6931 cx: &mut Context<Self>,
6932 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6933 let buffer_id = buffer.read(cx).remote_id();
6934
6935 if let Some((client, upstream_project_id)) = self.upstream_client() {
6936 let mut suitable_capabilities = None;
6937 // Are we capable for proto request?
6938 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6939 &buffer,
6940 |capabilities| {
6941 if let Some(caps) = &capabilities.diagnostic_provider {
6942 suitable_capabilities = Some(caps.clone());
6943 true
6944 } else {
6945 false
6946 }
6947 },
6948 cx,
6949 );
6950 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6951 let Some(dynamic_caps) = suitable_capabilities else {
6952 return Task::ready(Ok(None));
6953 };
6954 assert!(any_server_has_diagnostics_provider);
6955
6956 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6957 let request = GetDocumentDiagnostics {
6958 previous_result_id: None,
6959 identifier,
6960 registration_id: None,
6961 };
6962 let request_timeout = ProjectSettings::get_global(cx)
6963 .global_lsp_settings
6964 .get_request_timeout();
6965 let request_task = client.request_lsp(
6966 upstream_project_id,
6967 None,
6968 request_timeout,
6969 cx.background_executor().clone(),
6970 request.to_proto(upstream_project_id, buffer.read(cx)),
6971 );
6972 cx.background_spawn(async move {
6973 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6974 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6975 // Do not attempt to further process the dummy responses here.
6976 let _response = request_task.await?;
6977 Ok(None)
6978 })
6979 } else {
6980 let servers = buffer.update(cx, |buffer, cx| {
6981 self.running_language_servers_for_local_buffer(buffer, cx)
6982 .map(|(_, server)| server.clone())
6983 .collect::<Vec<_>>()
6984 });
6985
6986 let pull_diagnostics = servers
6987 .into_iter()
6988 .flat_map(|server| {
6989 let result = maybe!({
6990 let local = self.as_local()?;
6991 let server_id = server.server_id();
6992 let providers_with_identifiers = local
6993 .language_server_dynamic_registrations
6994 .get(&server_id)
6995 .into_iter()
6996 .flat_map(|registrations| registrations.diagnostics.clone())
6997 .collect::<Vec<_>>();
6998 Some(
6999 providers_with_identifiers
7000 .into_iter()
7001 .map(|(registration_id, dynamic_caps)| {
7002 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7003 let registration_id = registration_id.map(SharedString::from);
7004 let result_id = self.result_id_for_buffer_pull(
7005 server_id,
7006 buffer_id,
7007 ®istration_id,
7008 cx,
7009 );
7010 self.request_lsp(
7011 buffer.clone(),
7012 LanguageServerToQuery::Other(server_id),
7013 GetDocumentDiagnostics {
7014 previous_result_id: result_id,
7015 registration_id,
7016 identifier,
7017 },
7018 cx,
7019 )
7020 })
7021 .collect::<Vec<_>>(),
7022 )
7023 });
7024
7025 result.unwrap_or_default()
7026 })
7027 .collect::<Vec<_>>();
7028
7029 cx.background_spawn(async move {
7030 let mut responses = Vec::new();
7031 for diagnostics in join_all(pull_diagnostics).await {
7032 responses.extend(diagnostics?);
7033 }
7034 Ok(Some(responses))
7035 })
7036 }
7037 }
7038
7039 pub fn applicable_inlay_chunks(
7040 &mut self,
7041 buffer: &Entity<Buffer>,
7042 ranges: &[Range<text::Anchor>],
7043 cx: &mut Context<Self>,
7044 ) -> Vec<Range<BufferRow>> {
7045 let buffer_snapshot = buffer.read(cx).snapshot();
7046 let ranges = ranges
7047 .iter()
7048 .map(|range| range.to_point(&buffer_snapshot))
7049 .collect::<Vec<_>>();
7050
7051 self.latest_lsp_data(buffer, cx)
7052 .inlay_hints
7053 .applicable_chunks(ranges.as_slice())
7054 .map(|chunk| chunk.row_range())
7055 .collect()
7056 }
7057
7058 pub fn invalidate_inlay_hints<'a>(
7059 &'a mut self,
7060 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7061 ) {
7062 for buffer_id in for_buffers {
7063 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7064 lsp_data.inlay_hints.clear();
7065 }
7066 }
7067 }
7068
7069 pub fn inlay_hints(
7070 &mut self,
7071 invalidate: InvalidationStrategy,
7072 buffer: Entity<Buffer>,
7073 ranges: Vec<Range<text::Anchor>>,
7074 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7075 cx: &mut Context<Self>,
7076 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7077 let next_hint_id = self.next_hint_id.clone();
7078 let lsp_data = self.latest_lsp_data(&buffer, cx);
7079 let query_version = lsp_data.buffer_version.clone();
7080 let mut lsp_refresh_requested = false;
7081 let for_server = if let InvalidationStrategy::RefreshRequested {
7082 server_id,
7083 request_id,
7084 } = invalidate
7085 {
7086 let invalidated = lsp_data
7087 .inlay_hints
7088 .invalidate_for_server_refresh(server_id, request_id);
7089 lsp_refresh_requested = invalidated;
7090 Some(server_id)
7091 } else {
7092 None
7093 };
7094 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7095 let known_chunks = known_chunks
7096 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7097 .map(|(_, known_chunks)| known_chunks)
7098 .unwrap_or_default();
7099
7100 let buffer_snapshot = buffer.read(cx).snapshot();
7101 let ranges = ranges
7102 .iter()
7103 .map(|range| range.to_point(&buffer_snapshot))
7104 .collect::<Vec<_>>();
7105
7106 let mut hint_fetch_tasks = Vec::new();
7107 let mut cached_inlay_hints = None;
7108 let mut ranges_to_query = None;
7109 let applicable_chunks = existing_inlay_hints
7110 .applicable_chunks(ranges.as_slice())
7111 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7112 .collect::<Vec<_>>();
7113 if applicable_chunks.is_empty() {
7114 return HashMap::default();
7115 }
7116
7117 for row_chunk in applicable_chunks {
7118 match (
7119 existing_inlay_hints
7120 .cached_hints(&row_chunk)
7121 .filter(|_| !lsp_refresh_requested)
7122 .cloned(),
7123 existing_inlay_hints
7124 .fetched_hints(&row_chunk)
7125 .as_ref()
7126 .filter(|_| !lsp_refresh_requested)
7127 .cloned(),
7128 ) {
7129 (None, None) => {
7130 let chunk_range = row_chunk.anchor_range();
7131 ranges_to_query
7132 .get_or_insert_with(Vec::new)
7133 .push((row_chunk, chunk_range));
7134 }
7135 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7136 (Some(cached_hints), None) => {
7137 for (server_id, cached_hints) in cached_hints {
7138 if for_server.is_none_or(|for_server| for_server == server_id) {
7139 cached_inlay_hints
7140 .get_or_insert_with(HashMap::default)
7141 .entry(row_chunk.row_range())
7142 .or_insert_with(HashMap::default)
7143 .entry(server_id)
7144 .or_insert_with(Vec::new)
7145 .extend(cached_hints);
7146 }
7147 }
7148 }
7149 (Some(cached_hints), Some(fetched_hints)) => {
7150 hint_fetch_tasks.push((row_chunk, fetched_hints));
7151 for (server_id, cached_hints) in cached_hints {
7152 if for_server.is_none_or(|for_server| for_server == server_id) {
7153 cached_inlay_hints
7154 .get_or_insert_with(HashMap::default)
7155 .entry(row_chunk.row_range())
7156 .or_insert_with(HashMap::default)
7157 .entry(server_id)
7158 .or_insert_with(Vec::new)
7159 .extend(cached_hints);
7160 }
7161 }
7162 }
7163 }
7164 }
7165
7166 if hint_fetch_tasks.is_empty()
7167 && ranges_to_query
7168 .as_ref()
7169 .is_none_or(|ranges| ranges.is_empty())
7170 && let Some(cached_inlay_hints) = cached_inlay_hints
7171 {
7172 cached_inlay_hints
7173 .into_iter()
7174 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7175 .collect()
7176 } else {
7177 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7178 // When a server refresh was requested, other servers' cached hints
7179 // are unaffected by the refresh and must be included in the result.
7180 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7181 // removes all visible hints but only adds back the requesting
7182 // server's new hints, permanently losing other servers' hints.
7183 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7184 lsp_data
7185 .inlay_hints
7186 .cached_hints(&chunk)
7187 .cloned()
7188 .unwrap_or_default()
7189 } else {
7190 HashMap::default()
7191 };
7192
7193 let next_hint_id = next_hint_id.clone();
7194 let buffer = buffer.clone();
7195 let query_version = query_version.clone();
7196 let new_inlay_hints = cx
7197 .spawn(async move |lsp_store, cx| {
7198 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7199 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7200 })?;
7201 new_fetch_task
7202 .await
7203 .and_then(|new_hints_by_server| {
7204 lsp_store.update(cx, |lsp_store, cx| {
7205 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7206 let update_cache = lsp_data.buffer_version == query_version;
7207 if new_hints_by_server.is_empty() {
7208 if update_cache {
7209 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7210 }
7211 other_servers_cached
7212 } else {
7213 let mut result = other_servers_cached;
7214 for (server_id, new_hints) in new_hints_by_server {
7215 let new_hints = new_hints
7216 .into_iter()
7217 .map(|new_hint| {
7218 (
7219 InlayId::Hint(next_hint_id.fetch_add(
7220 1,
7221 atomic::Ordering::AcqRel,
7222 )),
7223 new_hint,
7224 )
7225 })
7226 .collect::<Vec<_>>();
7227 if update_cache {
7228 lsp_data.inlay_hints.insert_new_hints(
7229 chunk,
7230 server_id,
7231 new_hints.clone(),
7232 );
7233 }
7234 result.insert(server_id, new_hints);
7235 }
7236 result
7237 }
7238 })
7239 })
7240 .map_err(Arc::new)
7241 })
7242 .shared();
7243
7244 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7245 *fetch_task = Some(new_inlay_hints.clone());
7246 hint_fetch_tasks.push((chunk, new_inlay_hints));
7247 }
7248
7249 cached_inlay_hints
7250 .unwrap_or_default()
7251 .into_iter()
7252 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7253 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7254 (
7255 chunk.row_range(),
7256 cx.spawn(async move |_, _| {
7257 hints_fetch.await.map_err(|e| {
7258 if e.error_code() != ErrorCode::Internal {
7259 anyhow!(e.error_code())
7260 } else {
7261 anyhow!("{e:#}")
7262 }
7263 })
7264 }),
7265 )
7266 }))
7267 .collect()
7268 }
7269 }
7270
7271 fn fetch_inlay_hints(
7272 &mut self,
7273 for_server: Option<LanguageServerId>,
7274 buffer: &Entity<Buffer>,
7275 range: Range<Anchor>,
7276 cx: &mut Context<Self>,
7277 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7278 let request = InlayHints {
7279 range: range.clone(),
7280 };
7281 if let Some((upstream_client, project_id)) = self.upstream_client() {
7282 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7283 return Task::ready(Ok(HashMap::default()));
7284 }
7285 let request_timeout = ProjectSettings::get_global(cx)
7286 .global_lsp_settings
7287 .get_request_timeout();
7288 let request_task = upstream_client.request_lsp(
7289 project_id,
7290 for_server.map(|id| id.to_proto()),
7291 request_timeout,
7292 cx.background_executor().clone(),
7293 request.to_proto(project_id, buffer.read(cx)),
7294 );
7295 let buffer = buffer.clone();
7296 cx.spawn(async move |weak_lsp_store, cx| {
7297 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7298 return Ok(HashMap::default());
7299 };
7300 let Some(responses) = request_task.await? else {
7301 return Ok(HashMap::default());
7302 };
7303
7304 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7305 let lsp_store = lsp_store.clone();
7306 let buffer = buffer.clone();
7307 let cx = cx.clone();
7308 let request = request.clone();
7309 async move {
7310 (
7311 LanguageServerId::from_proto(response.server_id),
7312 request
7313 .response_from_proto(response.response, lsp_store, buffer, cx)
7314 .await,
7315 )
7316 }
7317 }))
7318 .await;
7319
7320 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7321 let mut has_errors = false;
7322 let inlay_hints = inlay_hints
7323 .into_iter()
7324 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7325 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7326 Err(e) => {
7327 has_errors = true;
7328 log::error!("{e:#}");
7329 None
7330 }
7331 })
7332 .map(|(server_id, mut new_hints)| {
7333 new_hints.retain(|hint| {
7334 hint.position.is_valid(&buffer_snapshot)
7335 && range.start.is_valid(&buffer_snapshot)
7336 && range.end.is_valid(&buffer_snapshot)
7337 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7338 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7339 });
7340 (server_id, new_hints)
7341 })
7342 .collect::<HashMap<_, _>>();
7343 anyhow::ensure!(
7344 !has_errors || !inlay_hints.is_empty(),
7345 "Failed to fetch inlay hints"
7346 );
7347 Ok(inlay_hints)
7348 })
7349 } else {
7350 let inlay_hints_task = match for_server {
7351 Some(server_id) => {
7352 let server_task = self.request_lsp(
7353 buffer.clone(),
7354 LanguageServerToQuery::Other(server_id),
7355 request,
7356 cx,
7357 );
7358 cx.background_spawn(async move {
7359 let mut responses = Vec::new();
7360 match server_task.await {
7361 Ok(response) => responses.push((server_id, response)),
7362 // rust-analyzer likes to error with this when its still loading up
7363 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7364 Err(e) => log::error!(
7365 "Error handling response for inlay hints request: {e:#}"
7366 ),
7367 }
7368 responses
7369 })
7370 }
7371 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7372 };
7373 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7374 cx.background_spawn(async move {
7375 Ok(inlay_hints_task
7376 .await
7377 .into_iter()
7378 .map(|(server_id, mut new_hints)| {
7379 new_hints.retain(|hint| {
7380 hint.position.is_valid(&buffer_snapshot)
7381 && range.start.is_valid(&buffer_snapshot)
7382 && range.end.is_valid(&buffer_snapshot)
7383 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7384 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7385 });
7386 (server_id, new_hints)
7387 })
7388 .collect())
7389 })
7390 }
7391 }
7392
7393 fn diagnostic_registration_exists(
7394 &self,
7395 server_id: LanguageServerId,
7396 registration_id: &Option<SharedString>,
7397 ) -> bool {
7398 let Some(local) = self.as_local() else {
7399 return false;
7400 };
7401 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7402 else {
7403 return false;
7404 };
7405 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7406 registrations.diagnostics.contains_key(®istration_key)
7407 }
7408
7409 pub fn pull_diagnostics_for_buffer(
7410 &mut self,
7411 buffer: Entity<Buffer>,
7412 cx: &mut Context<Self>,
7413 ) -> Task<anyhow::Result<()>> {
7414 let diagnostics = self.pull_diagnostics(buffer, cx);
7415 cx.spawn(async move |lsp_store, cx| {
7416 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7417 return Ok(());
7418 };
7419 lsp_store.update(cx, |lsp_store, cx| {
7420 if lsp_store.as_local().is_none() {
7421 return;
7422 }
7423
7424 let mut unchanged_buffers = HashMap::default();
7425 let server_diagnostics_updates = diagnostics
7426 .into_iter()
7427 .filter_map(|diagnostics_set| match diagnostics_set {
7428 LspPullDiagnostics::Response {
7429 server_id,
7430 uri,
7431 diagnostics,
7432 registration_id,
7433 } => Some((server_id, uri, diagnostics, registration_id)),
7434 LspPullDiagnostics::Default => None,
7435 })
7436 .filter(|(server_id, _, _, registration_id)| {
7437 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7438 })
7439 .fold(
7440 HashMap::default(),
7441 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7442 let (result_id, diagnostics) = match diagnostics {
7443 PulledDiagnostics::Unchanged { result_id } => {
7444 unchanged_buffers
7445 .entry(new_registration_id.clone())
7446 .or_insert_with(HashSet::default)
7447 .insert(uri.clone());
7448 (Some(result_id), Vec::new())
7449 }
7450 PulledDiagnostics::Changed {
7451 result_id,
7452 diagnostics,
7453 } => (result_id, diagnostics),
7454 };
7455 let disk_based_sources = Cow::Owned(
7456 lsp_store
7457 .language_server_adapter_for_id(server_id)
7458 .as_ref()
7459 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7460 .unwrap_or(&[])
7461 .to_vec(),
7462 );
7463 acc.entry(server_id)
7464 .or_insert_with(HashMap::default)
7465 .entry(new_registration_id.clone())
7466 .or_insert_with(Vec::new)
7467 .push(DocumentDiagnosticsUpdate {
7468 server_id,
7469 diagnostics: lsp::PublishDiagnosticsParams {
7470 uri,
7471 diagnostics,
7472 version: None,
7473 },
7474 result_id: result_id.map(SharedString::new),
7475 disk_based_sources,
7476 registration_id: new_registration_id,
7477 });
7478 acc
7479 },
7480 );
7481
7482 for diagnostic_updates in server_diagnostics_updates.into_values() {
7483 for (registration_id, diagnostic_updates) in diagnostic_updates {
7484 lsp_store
7485 .merge_lsp_diagnostics(
7486 DiagnosticSourceKind::Pulled,
7487 diagnostic_updates,
7488 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7489 DiagnosticSourceKind::Pulled => {
7490 old_diagnostic.registration_id != registration_id
7491 || unchanged_buffers
7492 .get(&old_diagnostic.registration_id)
7493 .is_some_and(|unchanged_buffers| {
7494 unchanged_buffers.contains(&document_uri)
7495 })
7496 }
7497 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7498 true
7499 }
7500 },
7501 cx,
7502 )
7503 .log_err();
7504 }
7505 }
7506 })
7507 })
7508 }
7509
7510 pub fn signature_help<T: ToPointUtf16>(
7511 &mut self,
7512 buffer: &Entity<Buffer>,
7513 position: T,
7514 cx: &mut Context<Self>,
7515 ) -> Task<Option<Vec<SignatureHelp>>> {
7516 let position = position.to_point_utf16(buffer.read(cx));
7517
7518 if let Some((client, upstream_project_id)) = self.upstream_client() {
7519 let request = GetSignatureHelp { position };
7520 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7521 return Task::ready(None);
7522 }
7523 let request_timeout = ProjectSettings::get_global(cx)
7524 .global_lsp_settings
7525 .get_request_timeout();
7526 let request_task = client.request_lsp(
7527 upstream_project_id,
7528 None,
7529 request_timeout,
7530 cx.background_executor().clone(),
7531 request.to_proto(upstream_project_id, buffer.read(cx)),
7532 );
7533 let buffer = buffer.clone();
7534 cx.spawn(async move |weak_lsp_store, cx| {
7535 let lsp_store = weak_lsp_store.upgrade()?;
7536 let signatures = join_all(
7537 request_task
7538 .await
7539 .log_err()
7540 .flatten()
7541 .map(|response| response.payload)
7542 .unwrap_or_default()
7543 .into_iter()
7544 .map(|response| {
7545 let response = GetSignatureHelp { position }.response_from_proto(
7546 response.response,
7547 lsp_store.clone(),
7548 buffer.clone(),
7549 cx.clone(),
7550 );
7551 async move { response.await.log_err().flatten() }
7552 }),
7553 )
7554 .await
7555 .into_iter()
7556 .flatten()
7557 .collect();
7558 Some(signatures)
7559 })
7560 } else {
7561 let all_actions_task = self.request_multiple_lsp_locally(
7562 buffer,
7563 Some(position),
7564 GetSignatureHelp { position },
7565 cx,
7566 );
7567 cx.background_spawn(async move {
7568 Some(
7569 all_actions_task
7570 .await
7571 .into_iter()
7572 .flat_map(|(_, actions)| actions)
7573 .collect::<Vec<_>>(),
7574 )
7575 })
7576 }
7577 }
7578
7579 pub fn hover(
7580 &mut self,
7581 buffer: &Entity<Buffer>,
7582 position: PointUtf16,
7583 cx: &mut Context<Self>,
7584 ) -> Task<Option<Vec<Hover>>> {
7585 if let Some((client, upstream_project_id)) = self.upstream_client() {
7586 let request = GetHover { position };
7587 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7588 return Task::ready(None);
7589 }
7590 let request_timeout = ProjectSettings::get_global(cx)
7591 .global_lsp_settings
7592 .get_request_timeout();
7593 let request_task = client.request_lsp(
7594 upstream_project_id,
7595 None,
7596 request_timeout,
7597 cx.background_executor().clone(),
7598 request.to_proto(upstream_project_id, buffer.read(cx)),
7599 );
7600 let buffer = buffer.clone();
7601 cx.spawn(async move |weak_lsp_store, cx| {
7602 let lsp_store = weak_lsp_store.upgrade()?;
7603 let hovers = join_all(
7604 request_task
7605 .await
7606 .log_err()
7607 .flatten()
7608 .map(|response| response.payload)
7609 .unwrap_or_default()
7610 .into_iter()
7611 .map(|response| {
7612 let response = GetHover { position }.response_from_proto(
7613 response.response,
7614 lsp_store.clone(),
7615 buffer.clone(),
7616 cx.clone(),
7617 );
7618 async move {
7619 response
7620 .await
7621 .log_err()
7622 .flatten()
7623 .and_then(remove_empty_hover_blocks)
7624 }
7625 }),
7626 )
7627 .await
7628 .into_iter()
7629 .flatten()
7630 .collect();
7631 Some(hovers)
7632 })
7633 } else {
7634 let all_actions_task = self.request_multiple_lsp_locally(
7635 buffer,
7636 Some(position),
7637 GetHover { position },
7638 cx,
7639 );
7640 cx.background_spawn(async move {
7641 Some(
7642 all_actions_task
7643 .await
7644 .into_iter()
7645 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7646 .collect::<Vec<Hover>>(),
7647 )
7648 })
7649 }
7650 }
7651
7652 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7653 let language_registry = self.languages.clone();
7654
7655 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7656 let request = upstream_client.request(proto::GetProjectSymbols {
7657 project_id: *project_id,
7658 query: query.to_string(),
7659 });
7660 cx.foreground_executor().spawn(async move {
7661 let response = request.await?;
7662 let mut symbols = Vec::new();
7663 let core_symbols = response
7664 .symbols
7665 .into_iter()
7666 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7667 .collect::<Vec<_>>();
7668 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7669 .await;
7670 Ok(symbols)
7671 })
7672 } else if let Some(local) = self.as_local() {
7673 struct WorkspaceSymbolsResult {
7674 server_id: LanguageServerId,
7675 lsp_adapter: Arc<CachedLspAdapter>,
7676 worktree: WeakEntity<Worktree>,
7677 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7678 }
7679
7680 let mut requests = Vec::new();
7681 let mut requested_servers = BTreeSet::new();
7682 let request_timeout = ProjectSettings::get_global(cx)
7683 .global_lsp_settings
7684 .get_request_timeout();
7685
7686 for (seed, state) in local.language_server_ids.iter() {
7687 let Some(worktree_handle) = self
7688 .worktree_store
7689 .read(cx)
7690 .worktree_for_id(seed.worktree_id, cx)
7691 else {
7692 continue;
7693 };
7694
7695 let worktree = worktree_handle.read(cx);
7696 if !worktree.is_visible() {
7697 continue;
7698 }
7699
7700 if !requested_servers.insert(state.id) {
7701 continue;
7702 }
7703
7704 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7705 Some(LanguageServerState::Running {
7706 adapter, server, ..
7707 }) => (adapter.clone(), server),
7708
7709 _ => continue,
7710 };
7711
7712 let supports_workspace_symbol_request =
7713 match server.capabilities().workspace_symbol_provider {
7714 Some(OneOf::Left(supported)) => supported,
7715 Some(OneOf::Right(_)) => true,
7716 None => false,
7717 };
7718
7719 if !supports_workspace_symbol_request {
7720 continue;
7721 }
7722
7723 let worktree_handle = worktree_handle.clone();
7724 let server_id = server.server_id();
7725 requests.push(
7726 server
7727 .request::<lsp::request::WorkspaceSymbolRequest>(
7728 lsp::WorkspaceSymbolParams {
7729 query: query.to_string(),
7730 ..Default::default()
7731 },
7732 request_timeout,
7733 )
7734 .map(move |response| {
7735 let lsp_symbols = response
7736 .into_response()
7737 .context("workspace symbols request")
7738 .log_err()
7739 .flatten()
7740 .map(|symbol_response| match symbol_response {
7741 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7742 flat_responses
7743 .into_iter()
7744 .map(|lsp_symbol| {
7745 (
7746 lsp_symbol.name,
7747 lsp_symbol.kind,
7748 lsp_symbol.location,
7749 lsp_symbol.container_name,
7750 )
7751 })
7752 .collect::<Vec<_>>()
7753 }
7754 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7755 nested_responses
7756 .into_iter()
7757 .filter_map(|lsp_symbol| {
7758 let location = match lsp_symbol.location {
7759 OneOf::Left(location) => location,
7760 OneOf::Right(_) => {
7761 log::error!(
7762 "Unexpected: client capabilities \
7763 forbid symbol resolutions in \
7764 workspace.symbol.resolveSupport"
7765 );
7766 return None;
7767 }
7768 };
7769 Some((
7770 lsp_symbol.name,
7771 lsp_symbol.kind,
7772 location,
7773 lsp_symbol.container_name,
7774 ))
7775 })
7776 .collect::<Vec<_>>()
7777 }
7778 })
7779 .unwrap_or_default();
7780
7781 WorkspaceSymbolsResult {
7782 server_id,
7783 lsp_adapter,
7784 worktree: worktree_handle.downgrade(),
7785 lsp_symbols,
7786 }
7787 }),
7788 );
7789 }
7790
7791 cx.spawn(async move |this, cx| {
7792 let responses = futures::future::join_all(requests).await;
7793 let this = match this.upgrade() {
7794 Some(this) => this,
7795 None => return Ok(Vec::new()),
7796 };
7797
7798 let mut symbols = Vec::new();
7799 for result in responses {
7800 let core_symbols = this.update(cx, |this, cx| {
7801 result
7802 .lsp_symbols
7803 .into_iter()
7804 .filter_map(
7805 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7806 let abs_path = symbol_location.uri.to_file_path().ok()?;
7807 let source_worktree = result.worktree.upgrade()?;
7808 let source_worktree_id = source_worktree.read(cx).id();
7809
7810 let path = if let Some((tree, rel_path)) =
7811 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7812 {
7813 let worktree_id = tree.read(cx).id();
7814 SymbolLocation::InProject(ProjectPath {
7815 worktree_id,
7816 path: rel_path,
7817 })
7818 } else {
7819 SymbolLocation::OutsideProject {
7820 signature: this.symbol_signature(&abs_path),
7821 abs_path: abs_path.into(),
7822 }
7823 };
7824
7825 Some(CoreSymbol {
7826 source_language_server_id: result.server_id,
7827 language_server_name: result.lsp_adapter.name.clone(),
7828 source_worktree_id,
7829 path,
7830 kind: symbol_kind,
7831 name: collapse_newlines(&symbol_name, "↵ "),
7832 range: range_from_lsp(symbol_location.range),
7833 container_name: container_name
7834 .map(|c| collapse_newlines(&c, "↵ ")),
7835 })
7836 },
7837 )
7838 .collect::<Vec<_>>()
7839 });
7840
7841 populate_labels_for_symbols(
7842 core_symbols,
7843 &language_registry,
7844 Some(result.lsp_adapter),
7845 &mut symbols,
7846 )
7847 .await;
7848 }
7849
7850 Ok(symbols)
7851 })
7852 } else {
7853 Task::ready(Err(anyhow!("No upstream client or local language server")))
7854 }
7855 }
7856
7857 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7858 let mut summary = DiagnosticSummary::default();
7859 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7860 summary.error_count += path_summary.error_count;
7861 summary.warning_count += path_summary.warning_count;
7862 }
7863 summary
7864 }
7865
7866 /// Returns the diagnostic summary for a specific project path.
7867 pub fn diagnostic_summary_for_path(
7868 &self,
7869 project_path: &ProjectPath,
7870 _: &App,
7871 ) -> DiagnosticSummary {
7872 if let Some(summaries) = self
7873 .diagnostic_summaries
7874 .get(&project_path.worktree_id)
7875 .and_then(|map| map.get(&project_path.path))
7876 {
7877 let (error_count, warning_count) = summaries.iter().fold(
7878 (0, 0),
7879 |(error_count, warning_count), (_language_server_id, summary)| {
7880 (
7881 error_count + summary.error_count,
7882 warning_count + summary.warning_count,
7883 )
7884 },
7885 );
7886
7887 DiagnosticSummary {
7888 error_count,
7889 warning_count,
7890 }
7891 } else {
7892 DiagnosticSummary::default()
7893 }
7894 }
7895
7896 pub fn diagnostic_summaries<'a>(
7897 &'a self,
7898 include_ignored: bool,
7899 cx: &'a App,
7900 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7901 self.worktree_store
7902 .read(cx)
7903 .visible_worktrees(cx)
7904 .filter_map(|worktree| {
7905 let worktree = worktree.read(cx);
7906 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7907 })
7908 .flat_map(move |(worktree, summaries)| {
7909 let worktree_id = worktree.id();
7910 summaries
7911 .iter()
7912 .filter(move |(path, _)| {
7913 include_ignored
7914 || worktree
7915 .entry_for_path(path.as_ref())
7916 .is_some_and(|entry| !entry.is_ignored)
7917 })
7918 .flat_map(move |(path, summaries)| {
7919 summaries.iter().map(move |(server_id, summary)| {
7920 (
7921 ProjectPath {
7922 worktree_id,
7923 path: path.clone(),
7924 },
7925 *server_id,
7926 *summary,
7927 )
7928 })
7929 })
7930 })
7931 }
7932
7933 pub fn on_buffer_edited(
7934 &mut self,
7935 buffer: Entity<Buffer>,
7936 cx: &mut Context<Self>,
7937 ) -> Option<()> {
7938 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7939 Some(
7940 self.as_local()?
7941 .language_servers_for_buffer(buffer, cx)
7942 .map(|i| i.1.clone())
7943 .collect(),
7944 )
7945 })?;
7946
7947 let buffer = buffer.read(cx);
7948 let file = File::from_dyn(buffer.file())?;
7949 let abs_path = file.as_local()?.abs_path(cx);
7950 let uri = lsp::Uri::from_file_path(&abs_path)
7951 .ok()
7952 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7953 .log_err()?;
7954 let next_snapshot = buffer.text_snapshot();
7955 for language_server in language_servers {
7956 let language_server = language_server.clone();
7957
7958 let buffer_snapshots = self
7959 .as_local_mut()?
7960 .buffer_snapshots
7961 .get_mut(&buffer.remote_id())
7962 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7963 let previous_snapshot = buffer_snapshots.last()?;
7964
7965 let build_incremental_change = || {
7966 buffer
7967 .edits_since::<Dimensions<PointUtf16, usize>>(
7968 previous_snapshot.snapshot.version(),
7969 )
7970 .map(|edit| {
7971 let edit_start = edit.new.start.0;
7972 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7973 let new_text = next_snapshot
7974 .text_for_range(edit.new.start.1..edit.new.end.1)
7975 .collect();
7976 lsp::TextDocumentContentChangeEvent {
7977 range: Some(lsp::Range::new(
7978 point_to_lsp(edit_start),
7979 point_to_lsp(edit_end),
7980 )),
7981 range_length: None,
7982 text: new_text,
7983 }
7984 })
7985 .collect()
7986 };
7987
7988 let document_sync_kind = language_server
7989 .capabilities()
7990 .text_document_sync
7991 .as_ref()
7992 .and_then(|sync| match sync {
7993 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7994 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7995 });
7996
7997 let content_changes: Vec<_> = match document_sync_kind {
7998 Some(lsp::TextDocumentSyncKind::FULL) => {
7999 vec![lsp::TextDocumentContentChangeEvent {
8000 range: None,
8001 range_length: None,
8002 text: next_snapshot.text(),
8003 }]
8004 }
8005 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8006 _ => {
8007 #[cfg(any(test, feature = "test-support"))]
8008 {
8009 build_incremental_change()
8010 }
8011
8012 #[cfg(not(any(test, feature = "test-support")))]
8013 {
8014 continue;
8015 }
8016 }
8017 };
8018
8019 let next_version = previous_snapshot.version + 1;
8020 buffer_snapshots.push(LspBufferSnapshot {
8021 version: next_version,
8022 snapshot: next_snapshot.clone(),
8023 });
8024
8025 language_server
8026 .notify::<lsp::notification::DidChangeTextDocument>(
8027 lsp::DidChangeTextDocumentParams {
8028 text_document: lsp::VersionedTextDocumentIdentifier::new(
8029 uri.clone(),
8030 next_version,
8031 ),
8032 content_changes,
8033 },
8034 )
8035 .ok();
8036 self.pull_workspace_diagnostics(language_server.server_id());
8037 }
8038
8039 None
8040 }
8041
8042 pub fn on_buffer_saved(
8043 &mut self,
8044 buffer: Entity<Buffer>,
8045 cx: &mut Context<Self>,
8046 ) -> Option<()> {
8047 let file = File::from_dyn(buffer.read(cx).file())?;
8048 let worktree_id = file.worktree_id(cx);
8049 let abs_path = file.as_local()?.abs_path(cx);
8050 let text_document = lsp::TextDocumentIdentifier {
8051 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8052 };
8053 let local = self.as_local()?;
8054
8055 for server in local.language_servers_for_worktree(worktree_id) {
8056 if let Some(include_text) = include_text(server.as_ref()) {
8057 let text = if include_text {
8058 Some(buffer.read(cx).text())
8059 } else {
8060 None
8061 };
8062 server
8063 .notify::<lsp::notification::DidSaveTextDocument>(
8064 lsp::DidSaveTextDocumentParams {
8065 text_document: text_document.clone(),
8066 text,
8067 },
8068 )
8069 .ok();
8070 }
8071 }
8072
8073 let language_servers = buffer.update(cx, |buffer, cx| {
8074 local.language_server_ids_for_buffer(buffer, cx)
8075 });
8076 for language_server_id in language_servers {
8077 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8078 }
8079
8080 None
8081 }
8082
8083 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8084 maybe!(async move {
8085 let mut refreshed_servers = HashSet::default();
8086 let servers = lsp_store
8087 .update(cx, |lsp_store, cx| {
8088 let local = lsp_store.as_local()?;
8089
8090 let servers = local
8091 .language_server_ids
8092 .iter()
8093 .filter_map(|(seed, state)| {
8094 let worktree = lsp_store
8095 .worktree_store
8096 .read(cx)
8097 .worktree_for_id(seed.worktree_id, cx);
8098 let delegate: Arc<dyn LspAdapterDelegate> =
8099 worktree.map(|worktree| {
8100 LocalLspAdapterDelegate::new(
8101 local.languages.clone(),
8102 &local.environment,
8103 cx.weak_entity(),
8104 &worktree,
8105 local.http_client.clone(),
8106 local.fs.clone(),
8107 cx,
8108 )
8109 })?;
8110 let server_id = state.id;
8111
8112 let states = local.language_servers.get(&server_id)?;
8113
8114 match states {
8115 LanguageServerState::Starting { .. } => None,
8116 LanguageServerState::Running {
8117 adapter, server, ..
8118 } => {
8119 let adapter = adapter.clone();
8120 let server = server.clone();
8121 refreshed_servers.insert(server.name());
8122 let toolchain = seed.toolchain.clone();
8123 Some(cx.spawn(async move |_, cx| {
8124 let settings =
8125 LocalLspStore::workspace_configuration_for_adapter(
8126 adapter.adapter.clone(),
8127 &delegate,
8128 toolchain,
8129 None,
8130 cx,
8131 )
8132 .await
8133 .ok()?;
8134 server
8135 .notify::<lsp::notification::DidChangeConfiguration>(
8136 lsp::DidChangeConfigurationParams { settings },
8137 )
8138 .ok()?;
8139 Some(())
8140 }))
8141 }
8142 }
8143 })
8144 .collect::<Vec<_>>();
8145
8146 Some(servers)
8147 })
8148 .ok()
8149 .flatten()?;
8150
8151 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8152 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8153 // to stop and unregister its language server wrapper.
8154 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8155 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8156 let _: Vec<Option<()>> = join_all(servers).await;
8157
8158 Some(())
8159 })
8160 .await;
8161 }
8162
8163 fn maintain_workspace_config(
8164 external_refresh_requests: watch::Receiver<()>,
8165 cx: &mut Context<Self>,
8166 ) -> Task<Result<()>> {
8167 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8168 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8169
8170 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8171 *settings_changed_tx.borrow_mut() = ();
8172 });
8173
8174 let mut joint_future =
8175 futures::stream::select(settings_changed_rx, external_refresh_requests);
8176 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8177 // - 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).
8178 // - 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.
8179 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8180 // - 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,
8181 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8182 cx.spawn(async move |this, cx| {
8183 while let Some(()) = joint_future.next().await {
8184 this.update(cx, |this, cx| {
8185 this.refresh_server_tree(cx);
8186 })
8187 .ok();
8188
8189 Self::refresh_workspace_configurations(&this, cx).await;
8190 }
8191
8192 drop(settings_observation);
8193 anyhow::Ok(())
8194 })
8195 }
8196
8197 pub fn running_language_servers_for_local_buffer<'a>(
8198 &'a self,
8199 buffer: &Buffer,
8200 cx: &mut App,
8201 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8202 let local = self.as_local();
8203 let language_server_ids = local
8204 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8205 .unwrap_or_default();
8206
8207 language_server_ids
8208 .into_iter()
8209 .filter_map(
8210 move |server_id| match local?.language_servers.get(&server_id)? {
8211 LanguageServerState::Running {
8212 adapter, server, ..
8213 } => Some((adapter, server)),
8214 _ => None,
8215 },
8216 )
8217 }
8218
8219 pub fn language_servers_for_local_buffer(
8220 &self,
8221 buffer: &Buffer,
8222 cx: &mut App,
8223 ) -> Vec<LanguageServerId> {
8224 let local = self.as_local();
8225 local
8226 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8227 .unwrap_or_default()
8228 }
8229
8230 pub fn language_server_for_local_buffer<'a>(
8231 &'a self,
8232 buffer: &'a Buffer,
8233 server_id: LanguageServerId,
8234 cx: &'a mut App,
8235 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8236 self.as_local()?
8237 .language_servers_for_buffer(buffer, cx)
8238 .find(|(_, s)| s.server_id() == server_id)
8239 }
8240
8241 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8242 self.diagnostic_summaries.remove(&id_to_remove);
8243 if let Some(local) = self.as_local_mut() {
8244 let to_remove = local.remove_worktree(id_to_remove, cx);
8245 for server in to_remove {
8246 self.language_server_statuses.remove(&server);
8247 }
8248 }
8249 }
8250
8251 fn invalidate_diagnostic_summaries_for_removed_entries(
8252 &mut self,
8253 worktree_id: WorktreeId,
8254 changes: &UpdatedEntriesSet,
8255 cx: &mut Context<Self>,
8256 ) {
8257 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8258 return;
8259 };
8260
8261 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8262 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8263 let downstream = self.downstream_client.clone();
8264
8265 for (path, _, _) in changes
8266 .iter()
8267 .filter(|(_, _, change)| *change == PathChange::Removed)
8268 {
8269 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8270 for (server_id, _) in &summaries_by_server_id {
8271 cleared_server_ids.insert(*server_id);
8272 if let Some((client, project_id)) = &downstream {
8273 client
8274 .send(proto::UpdateDiagnosticSummary {
8275 project_id: *project_id,
8276 worktree_id: worktree_id.to_proto(),
8277 summary: Some(proto::DiagnosticSummary {
8278 path: path.as_ref().to_proto(),
8279 language_server_id: server_id.0 as u64,
8280 error_count: 0,
8281 warning_count: 0,
8282 }),
8283 more_summaries: Vec::new(),
8284 })
8285 .ok();
8286 }
8287 }
8288 cleared_paths.push(ProjectPath {
8289 worktree_id,
8290 path: path.clone(),
8291 });
8292 }
8293 }
8294
8295 if !cleared_paths.is_empty() {
8296 for server_id in cleared_server_ids {
8297 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8298 server_id,
8299 paths: cleared_paths.clone(),
8300 });
8301 }
8302 }
8303 }
8304
8305 pub fn shared(
8306 &mut self,
8307 project_id: u64,
8308 downstream_client: AnyProtoClient,
8309 _: &mut Context<Self>,
8310 ) {
8311 self.downstream_client = Some((downstream_client.clone(), project_id));
8312
8313 for (server_id, status) in &self.language_server_statuses {
8314 if let Some(server) = self.language_server_for_id(*server_id) {
8315 downstream_client
8316 .send(proto::StartLanguageServer {
8317 project_id,
8318 server: Some(proto::LanguageServer {
8319 id: server_id.to_proto(),
8320 name: status.name.to_string(),
8321 worktree_id: status.worktree.map(|id| id.to_proto()),
8322 }),
8323 capabilities: serde_json::to_string(&server.capabilities())
8324 .expect("serializing server LSP capabilities"),
8325 })
8326 .log_err();
8327 }
8328 }
8329 }
8330
8331 pub fn disconnected_from_host(&mut self) {
8332 self.downstream_client.take();
8333 }
8334
8335 pub fn disconnected_from_ssh_remote(&mut self) {
8336 if let LspStoreMode::Remote(RemoteLspStore {
8337 upstream_client, ..
8338 }) = &mut self.mode
8339 {
8340 upstream_client.take();
8341 }
8342 }
8343
8344 pub(crate) fn set_language_server_statuses_from_proto(
8345 &mut self,
8346 project: WeakEntity<Project>,
8347 language_servers: Vec<proto::LanguageServer>,
8348 server_capabilities: Vec<String>,
8349 cx: &mut Context<Self>,
8350 ) {
8351 let lsp_logs = cx
8352 .try_global::<GlobalLogStore>()
8353 .map(|lsp_store| lsp_store.0.clone());
8354
8355 self.language_server_statuses = language_servers
8356 .into_iter()
8357 .zip(server_capabilities)
8358 .map(|(server, server_capabilities)| {
8359 let server_id = LanguageServerId(server.id as usize);
8360 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8361 self.lsp_server_capabilities
8362 .insert(server_id, server_capabilities);
8363 }
8364
8365 let name = LanguageServerName::from_proto(server.name);
8366 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8367
8368 if let Some(lsp_logs) = &lsp_logs {
8369 lsp_logs.update(cx, |lsp_logs, cx| {
8370 lsp_logs.add_language_server(
8371 // Only remote clients get their language servers set from proto
8372 LanguageServerKind::Remote {
8373 project: project.clone(),
8374 },
8375 server_id,
8376 Some(name.clone()),
8377 worktree,
8378 None,
8379 cx,
8380 );
8381 });
8382 }
8383
8384 (
8385 server_id,
8386 LanguageServerStatus {
8387 name,
8388 server_version: None,
8389 server_readable_version: None,
8390 pending_work: Default::default(),
8391 has_pending_diagnostic_updates: false,
8392 progress_tokens: Default::default(),
8393 worktree,
8394 binary: None,
8395 configuration: None,
8396 workspace_folders: BTreeSet::new(),
8397 process_id: None,
8398 },
8399 )
8400 })
8401 .collect();
8402 }
8403
8404 #[cfg(feature = "test-support")]
8405 pub fn update_diagnostic_entries(
8406 &mut self,
8407 server_id: LanguageServerId,
8408 abs_path: PathBuf,
8409 result_id: Option<SharedString>,
8410 version: Option<i32>,
8411 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8412 cx: &mut Context<Self>,
8413 ) -> anyhow::Result<()> {
8414 self.merge_diagnostic_entries(
8415 vec![DocumentDiagnosticsUpdate {
8416 diagnostics: DocumentDiagnostics {
8417 diagnostics,
8418 document_abs_path: abs_path,
8419 version,
8420 },
8421 result_id,
8422 server_id,
8423 disk_based_sources: Cow::Borrowed(&[]),
8424 registration_id: None,
8425 }],
8426 |_, _, _| false,
8427 cx,
8428 )?;
8429 Ok(())
8430 }
8431
8432 pub fn merge_diagnostic_entries<'a>(
8433 &mut self,
8434 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8435 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8436 cx: &mut Context<Self>,
8437 ) -> anyhow::Result<()> {
8438 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8439 let mut updated_diagnostics_paths = HashMap::default();
8440 for mut update in diagnostic_updates {
8441 let abs_path = &update.diagnostics.document_abs_path;
8442 let server_id = update.server_id;
8443 let Some((worktree, relative_path)) =
8444 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8445 else {
8446 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8447 return Ok(());
8448 };
8449
8450 let worktree_id = worktree.read(cx).id();
8451 let project_path = ProjectPath {
8452 worktree_id,
8453 path: relative_path,
8454 };
8455
8456 let document_uri = lsp::Uri::from_file_path(abs_path)
8457 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8458 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8459 let snapshot = buffer_handle.read(cx).snapshot();
8460 let buffer = buffer_handle.read(cx);
8461 let reused_diagnostics = buffer
8462 .buffer_diagnostics(Some(server_id))
8463 .iter()
8464 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8465 .map(|v| {
8466 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8467 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8468 DiagnosticEntry {
8469 range: start..end,
8470 diagnostic: v.diagnostic.clone(),
8471 }
8472 })
8473 .collect::<Vec<_>>();
8474
8475 self.as_local_mut()
8476 .context("cannot merge diagnostics on a remote LspStore")?
8477 .update_buffer_diagnostics(
8478 &buffer_handle,
8479 server_id,
8480 Some(update.registration_id),
8481 update.result_id,
8482 update.diagnostics.version,
8483 update.diagnostics.diagnostics.clone(),
8484 reused_diagnostics.clone(),
8485 cx,
8486 )?;
8487
8488 update.diagnostics.diagnostics.extend(reused_diagnostics);
8489 } else if let Some(local) = self.as_local() {
8490 let reused_diagnostics = local
8491 .diagnostics
8492 .get(&worktree_id)
8493 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8494 .and_then(|diagnostics_by_server_id| {
8495 diagnostics_by_server_id
8496 .binary_search_by_key(&server_id, |e| e.0)
8497 .ok()
8498 .map(|ix| &diagnostics_by_server_id[ix].1)
8499 })
8500 .into_iter()
8501 .flatten()
8502 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8503
8504 update
8505 .diagnostics
8506 .diagnostics
8507 .extend(reused_diagnostics.cloned());
8508 }
8509
8510 let updated = worktree.update(cx, |worktree, cx| {
8511 self.update_worktree_diagnostics(
8512 worktree.id(),
8513 server_id,
8514 project_path.path.clone(),
8515 update.diagnostics.diagnostics,
8516 cx,
8517 )
8518 })?;
8519 match updated {
8520 ControlFlow::Continue(new_summary) => {
8521 if let Some((project_id, new_summary)) = new_summary {
8522 match &mut diagnostics_summary {
8523 Some(diagnostics_summary) => {
8524 diagnostics_summary
8525 .more_summaries
8526 .push(proto::DiagnosticSummary {
8527 path: project_path.path.as_ref().to_proto(),
8528 language_server_id: server_id.0 as u64,
8529 error_count: new_summary.error_count,
8530 warning_count: new_summary.warning_count,
8531 })
8532 }
8533 None => {
8534 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8535 project_id,
8536 worktree_id: worktree_id.to_proto(),
8537 summary: Some(proto::DiagnosticSummary {
8538 path: project_path.path.as_ref().to_proto(),
8539 language_server_id: server_id.0 as u64,
8540 error_count: new_summary.error_count,
8541 warning_count: new_summary.warning_count,
8542 }),
8543 more_summaries: Vec::new(),
8544 })
8545 }
8546 }
8547 }
8548 updated_diagnostics_paths
8549 .entry(server_id)
8550 .or_insert_with(Vec::new)
8551 .push(project_path);
8552 }
8553 ControlFlow::Break(()) => {}
8554 }
8555 }
8556
8557 if let Some((diagnostics_summary, (downstream_client, _))) =
8558 diagnostics_summary.zip(self.downstream_client.as_ref())
8559 {
8560 downstream_client.send(diagnostics_summary).log_err();
8561 }
8562 for (server_id, paths) in updated_diagnostics_paths {
8563 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8564 }
8565 Ok(())
8566 }
8567
8568 fn update_worktree_diagnostics(
8569 &mut self,
8570 worktree_id: WorktreeId,
8571 server_id: LanguageServerId,
8572 path_in_worktree: Arc<RelPath>,
8573 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8574 _: &mut Context<Worktree>,
8575 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8576 let local = match &mut self.mode {
8577 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8578 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8579 };
8580
8581 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8582 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8583 let summaries_by_server_id = summaries_for_tree
8584 .entry(path_in_worktree.clone())
8585 .or_default();
8586
8587 let old_summary = summaries_by_server_id
8588 .remove(&server_id)
8589 .unwrap_or_default();
8590
8591 let new_summary = DiagnosticSummary::new(&diagnostics);
8592 if diagnostics.is_empty() {
8593 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8594 {
8595 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8596 diagnostics_by_server_id.remove(ix);
8597 }
8598 if diagnostics_by_server_id.is_empty() {
8599 diagnostics_for_tree.remove(&path_in_worktree);
8600 }
8601 }
8602 } else {
8603 summaries_by_server_id.insert(server_id, new_summary);
8604 let diagnostics_by_server_id = diagnostics_for_tree
8605 .entry(path_in_worktree.clone())
8606 .or_default();
8607 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8608 Ok(ix) => {
8609 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8610 }
8611 Err(ix) => {
8612 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8613 }
8614 }
8615 }
8616
8617 if !old_summary.is_empty() || !new_summary.is_empty() {
8618 if let Some((_, project_id)) = &self.downstream_client {
8619 Ok(ControlFlow::Continue(Some((
8620 *project_id,
8621 proto::DiagnosticSummary {
8622 path: path_in_worktree.to_proto(),
8623 language_server_id: server_id.0 as u64,
8624 error_count: new_summary.error_count as u32,
8625 warning_count: new_summary.warning_count as u32,
8626 },
8627 ))))
8628 } else {
8629 Ok(ControlFlow::Continue(None))
8630 }
8631 } else {
8632 Ok(ControlFlow::Break(()))
8633 }
8634 }
8635
8636 pub fn open_buffer_for_symbol(
8637 &mut self,
8638 symbol: &Symbol,
8639 cx: &mut Context<Self>,
8640 ) -> Task<Result<Entity<Buffer>>> {
8641 if let Some((client, project_id)) = self.upstream_client() {
8642 let request = client.request(proto::OpenBufferForSymbol {
8643 project_id,
8644 symbol: Some(Self::serialize_symbol(symbol)),
8645 });
8646 cx.spawn(async move |this, cx| {
8647 let response = request.await?;
8648 let buffer_id = BufferId::new(response.buffer_id)?;
8649 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8650 .await
8651 })
8652 } else if let Some(local) = self.as_local() {
8653 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8654 seed.worktree_id == symbol.source_worktree_id
8655 && state.id == symbol.source_language_server_id
8656 && symbol.language_server_name == seed.name
8657 });
8658 if !is_valid {
8659 return Task::ready(Err(anyhow!(
8660 "language server for worktree and language not found"
8661 )));
8662 };
8663
8664 let symbol_abs_path = match &symbol.path {
8665 SymbolLocation::InProject(project_path) => self
8666 .worktree_store
8667 .read(cx)
8668 .absolutize(&project_path, cx)
8669 .context("no such worktree"),
8670 SymbolLocation::OutsideProject {
8671 abs_path,
8672 signature: _,
8673 } => Ok(abs_path.to_path_buf()),
8674 };
8675 let symbol_abs_path = match symbol_abs_path {
8676 Ok(abs_path) => abs_path,
8677 Err(err) => return Task::ready(Err(err)),
8678 };
8679 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8680 uri
8681 } else {
8682 return Task::ready(Err(anyhow!("invalid symbol path")));
8683 };
8684
8685 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8686 } else {
8687 Task::ready(Err(anyhow!("no upstream client or local store")))
8688 }
8689 }
8690
8691 pub(crate) fn open_local_buffer_via_lsp(
8692 &mut self,
8693 abs_path: lsp::Uri,
8694 language_server_id: LanguageServerId,
8695 cx: &mut Context<Self>,
8696 ) -> Task<Result<Entity<Buffer>>> {
8697 let path_style = self.worktree_store.read(cx).path_style();
8698 cx.spawn(async move |lsp_store, cx| {
8699 // Escape percent-encoded string.
8700 let current_scheme = abs_path.scheme().to_owned();
8701 // Uri is immutable, so we can't modify the scheme
8702
8703 let abs_path = abs_path
8704 .to_file_path_ext(path_style)
8705 .map_err(|()| anyhow!("can't convert URI to path"))?;
8706 let p = abs_path.clone();
8707 let yarn_worktree = lsp_store
8708 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8709 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8710 cx.spawn(async move |this, cx| {
8711 let t = this
8712 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8713 .ok()?;
8714 t.await
8715 })
8716 }),
8717 None => Task::ready(None),
8718 })?
8719 .await;
8720 let (worktree_root_target, known_relative_path) =
8721 if let Some((zip_root, relative_path)) = yarn_worktree {
8722 (zip_root, Some(relative_path))
8723 } else {
8724 (Arc::<Path>::from(abs_path.as_path()), None)
8725 };
8726 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8727 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8728 worktree_store.find_worktree(&worktree_root_target, cx)
8729 })
8730 })?;
8731 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8732 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8733 (result.0, relative_path, None)
8734 } else {
8735 let worktree = lsp_store
8736 .update(cx, |lsp_store, cx| {
8737 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8738 worktree_store.create_worktree(&worktree_root_target, false, cx)
8739 })
8740 })?
8741 .await?;
8742 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8743 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8744 lsp_store
8745 .update(cx, |lsp_store, cx| {
8746 if let Some(local) = lsp_store.as_local_mut() {
8747 local.register_language_server_for_invisible_worktree(
8748 &worktree,
8749 language_server_id,
8750 cx,
8751 )
8752 }
8753 match lsp_store.language_server_statuses.get(&language_server_id) {
8754 Some(status) => status.worktree,
8755 None => None,
8756 }
8757 })
8758 .ok()
8759 .flatten()
8760 .zip(Some(worktree_root.clone()))
8761 } else {
8762 None
8763 };
8764 let relative_path = if let Some(known_path) = known_relative_path {
8765 known_path
8766 } else {
8767 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8768 .into_arc()
8769 };
8770 (worktree, relative_path, source_ws)
8771 };
8772 let project_path = ProjectPath {
8773 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8774 path: relative_path,
8775 };
8776 let buffer = lsp_store
8777 .update(cx, |lsp_store, cx| {
8778 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8779 buffer_store.open_buffer(project_path, cx)
8780 })
8781 })?
8782 .await?;
8783 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8784 if let Some((source_ws, worktree_root)) = source_ws {
8785 buffer.update(cx, |buffer, cx| {
8786 let settings = WorktreeSettings::get(
8787 Some(
8788 (&ProjectPath {
8789 worktree_id: source_ws,
8790 path: Arc::from(RelPath::empty()),
8791 })
8792 .into(),
8793 ),
8794 cx,
8795 );
8796 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8797 if is_read_only {
8798 buffer.set_capability(Capability::ReadOnly, cx);
8799 }
8800 });
8801 }
8802 Ok(buffer)
8803 })
8804 }
8805
8806 fn local_lsp_servers_for_buffer(
8807 &self,
8808 buffer: &Entity<Buffer>,
8809 cx: &mut Context<Self>,
8810 ) -> Vec<LanguageServerId> {
8811 let Some(local) = self.as_local() else {
8812 return Vec::new();
8813 };
8814
8815 let snapshot = buffer.read(cx).snapshot();
8816
8817 buffer.update(cx, |buffer, cx| {
8818 local
8819 .language_servers_for_buffer(buffer, cx)
8820 .map(|(_, server)| server.server_id())
8821 .filter(|server_id| {
8822 self.as_local().is_none_or(|local| {
8823 local
8824 .buffers_opened_in_servers
8825 .get(&snapshot.remote_id())
8826 .is_some_and(|servers| servers.contains(server_id))
8827 })
8828 })
8829 .collect()
8830 })
8831 }
8832
8833 fn request_multiple_lsp_locally<P, R>(
8834 &mut self,
8835 buffer: &Entity<Buffer>,
8836 position: Option<P>,
8837 request: R,
8838 cx: &mut Context<Self>,
8839 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8840 where
8841 P: ToOffset,
8842 R: LspCommand + Clone,
8843 <R::LspRequest as lsp::request::Request>::Result: Send,
8844 <R::LspRequest as lsp::request::Request>::Params: Send,
8845 {
8846 let Some(local) = self.as_local() else {
8847 return Task::ready(Vec::new());
8848 };
8849
8850 let snapshot = buffer.read(cx).snapshot();
8851 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8852
8853 let server_ids = buffer.update(cx, |buffer, cx| {
8854 local
8855 .language_servers_for_buffer(buffer, cx)
8856 .filter(|(adapter, _)| {
8857 scope
8858 .as_ref()
8859 .map(|scope| scope.language_allowed(&adapter.name))
8860 .unwrap_or(true)
8861 })
8862 .map(|(_, server)| server.server_id())
8863 .filter(|server_id| {
8864 self.as_local().is_none_or(|local| {
8865 local
8866 .buffers_opened_in_servers
8867 .get(&snapshot.remote_id())
8868 .is_some_and(|servers| servers.contains(server_id))
8869 })
8870 })
8871 .collect::<Vec<_>>()
8872 });
8873
8874 let mut response_results = server_ids
8875 .into_iter()
8876 .map(|server_id| {
8877 let task = self.request_lsp(
8878 buffer.clone(),
8879 LanguageServerToQuery::Other(server_id),
8880 request.clone(),
8881 cx,
8882 );
8883 async move { (server_id, task.await) }
8884 })
8885 .collect::<FuturesUnordered<_>>();
8886
8887 cx.background_spawn(async move {
8888 let mut responses = Vec::with_capacity(response_results.len());
8889 while let Some((server_id, response_result)) = response_results.next().await {
8890 match response_result {
8891 Ok(response) => responses.push((server_id, response)),
8892 // rust-analyzer likes to error with this when its still loading up
8893 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8894 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8895 }
8896 }
8897 responses
8898 })
8899 }
8900
8901 async fn handle_lsp_get_completions(
8902 this: Entity<Self>,
8903 envelope: TypedEnvelope<proto::GetCompletions>,
8904 mut cx: AsyncApp,
8905 ) -> Result<proto::GetCompletionsResponse> {
8906 let sender_id = envelope.original_sender_id().unwrap_or_default();
8907
8908 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8909 let buffer_handle = this.update(&mut cx, |this, cx| {
8910 this.buffer_store.read(cx).get_existing(buffer_id)
8911 })?;
8912 let request = GetCompletions::from_proto(
8913 envelope.payload,
8914 this.clone(),
8915 buffer_handle.clone(),
8916 cx.clone(),
8917 )
8918 .await?;
8919
8920 let server_to_query = match request.server_id {
8921 Some(server_id) => LanguageServerToQuery::Other(server_id),
8922 None => LanguageServerToQuery::FirstCapable,
8923 };
8924
8925 let response = this
8926 .update(&mut cx, |this, cx| {
8927 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8928 })
8929 .await?;
8930 this.update(&mut cx, |this, cx| {
8931 Ok(GetCompletions::response_to_proto(
8932 response,
8933 this,
8934 sender_id,
8935 &buffer_handle.read(cx).version(),
8936 cx,
8937 ))
8938 })
8939 }
8940
8941 async fn handle_lsp_command<T: LspCommand>(
8942 this: Entity<Self>,
8943 envelope: TypedEnvelope<T::ProtoRequest>,
8944 mut cx: AsyncApp,
8945 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8946 where
8947 <T::LspRequest as lsp::request::Request>::Params: Send,
8948 <T::LspRequest as lsp::request::Request>::Result: Send,
8949 {
8950 let sender_id = envelope.original_sender_id().unwrap_or_default();
8951 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8952 let buffer_handle = this.update(&mut cx, |this, cx| {
8953 this.buffer_store.read(cx).get_existing(buffer_id)
8954 })?;
8955 let request = T::from_proto(
8956 envelope.payload,
8957 this.clone(),
8958 buffer_handle.clone(),
8959 cx.clone(),
8960 )
8961 .await?;
8962 let response = this
8963 .update(&mut cx, |this, cx| {
8964 this.request_lsp(
8965 buffer_handle.clone(),
8966 LanguageServerToQuery::FirstCapable,
8967 request,
8968 cx,
8969 )
8970 })
8971 .await?;
8972 this.update(&mut cx, |this, cx| {
8973 Ok(T::response_to_proto(
8974 response,
8975 this,
8976 sender_id,
8977 &buffer_handle.read(cx).version(),
8978 cx,
8979 ))
8980 })
8981 }
8982
8983 async fn handle_lsp_query(
8984 lsp_store: Entity<Self>,
8985 envelope: TypedEnvelope<proto::LspQuery>,
8986 mut cx: AsyncApp,
8987 ) -> Result<proto::Ack> {
8988 use proto::lsp_query::Request;
8989 let sender_id = envelope.original_sender_id().unwrap_or_default();
8990 let lsp_query = envelope.payload;
8991 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8992 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8993 match lsp_query.request.context("invalid LSP query request")? {
8994 Request::GetReferences(get_references) => {
8995 let position = get_references.position.clone().and_then(deserialize_anchor);
8996 Self::query_lsp_locally::<GetReferences>(
8997 lsp_store,
8998 server_id,
8999 sender_id,
9000 lsp_request_id,
9001 get_references,
9002 position,
9003 &mut cx,
9004 )
9005 .await?;
9006 }
9007 Request::GetDocumentColor(get_document_color) => {
9008 Self::query_lsp_locally::<GetDocumentColor>(
9009 lsp_store,
9010 server_id,
9011 sender_id,
9012 lsp_request_id,
9013 get_document_color,
9014 None,
9015 &mut cx,
9016 )
9017 .await?;
9018 }
9019 Request::GetFoldingRanges(get_folding_ranges) => {
9020 Self::query_lsp_locally::<GetFoldingRanges>(
9021 lsp_store,
9022 server_id,
9023 sender_id,
9024 lsp_request_id,
9025 get_folding_ranges,
9026 None,
9027 &mut cx,
9028 )
9029 .await?;
9030 }
9031 Request::GetDocumentSymbols(get_document_symbols) => {
9032 Self::query_lsp_locally::<GetDocumentSymbols>(
9033 lsp_store,
9034 server_id,
9035 sender_id,
9036 lsp_request_id,
9037 get_document_symbols,
9038 None,
9039 &mut cx,
9040 )
9041 .await?;
9042 }
9043 Request::GetHover(get_hover) => {
9044 let position = get_hover.position.clone().and_then(deserialize_anchor);
9045 Self::query_lsp_locally::<GetHover>(
9046 lsp_store,
9047 server_id,
9048 sender_id,
9049 lsp_request_id,
9050 get_hover,
9051 position,
9052 &mut cx,
9053 )
9054 .await?;
9055 }
9056 Request::GetCodeActions(get_code_actions) => {
9057 Self::query_lsp_locally::<GetCodeActions>(
9058 lsp_store,
9059 server_id,
9060 sender_id,
9061 lsp_request_id,
9062 get_code_actions,
9063 None,
9064 &mut cx,
9065 )
9066 .await?;
9067 }
9068 Request::GetSignatureHelp(get_signature_help) => {
9069 let position = get_signature_help
9070 .position
9071 .clone()
9072 .and_then(deserialize_anchor);
9073 Self::query_lsp_locally::<GetSignatureHelp>(
9074 lsp_store,
9075 server_id,
9076 sender_id,
9077 lsp_request_id,
9078 get_signature_help,
9079 position,
9080 &mut cx,
9081 )
9082 .await?;
9083 }
9084 Request::GetCodeLens(get_code_lens) => {
9085 Self::query_lsp_locally::<GetCodeLens>(
9086 lsp_store,
9087 server_id,
9088 sender_id,
9089 lsp_request_id,
9090 get_code_lens,
9091 None,
9092 &mut cx,
9093 )
9094 .await?;
9095 }
9096 Request::GetDefinition(get_definition) => {
9097 let position = get_definition.position.clone().and_then(deserialize_anchor);
9098 Self::query_lsp_locally::<GetDefinitions>(
9099 lsp_store,
9100 server_id,
9101 sender_id,
9102 lsp_request_id,
9103 get_definition,
9104 position,
9105 &mut cx,
9106 )
9107 .await?;
9108 }
9109 Request::GetDeclaration(get_declaration) => {
9110 let position = get_declaration
9111 .position
9112 .clone()
9113 .and_then(deserialize_anchor);
9114 Self::query_lsp_locally::<GetDeclarations>(
9115 lsp_store,
9116 server_id,
9117 sender_id,
9118 lsp_request_id,
9119 get_declaration,
9120 position,
9121 &mut cx,
9122 )
9123 .await?;
9124 }
9125 Request::GetTypeDefinition(get_type_definition) => {
9126 let position = get_type_definition
9127 .position
9128 .clone()
9129 .and_then(deserialize_anchor);
9130 Self::query_lsp_locally::<GetTypeDefinitions>(
9131 lsp_store,
9132 server_id,
9133 sender_id,
9134 lsp_request_id,
9135 get_type_definition,
9136 position,
9137 &mut cx,
9138 )
9139 .await?;
9140 }
9141 Request::GetImplementation(get_implementation) => {
9142 let position = get_implementation
9143 .position
9144 .clone()
9145 .and_then(deserialize_anchor);
9146 Self::query_lsp_locally::<GetImplementations>(
9147 lsp_store,
9148 server_id,
9149 sender_id,
9150 lsp_request_id,
9151 get_implementation,
9152 position,
9153 &mut cx,
9154 )
9155 .await?;
9156 }
9157 Request::InlayHints(inlay_hints) => {
9158 let query_start = inlay_hints
9159 .start
9160 .clone()
9161 .and_then(deserialize_anchor)
9162 .context("invalid inlay hints range start")?;
9163 let query_end = inlay_hints
9164 .end
9165 .clone()
9166 .and_then(deserialize_anchor)
9167 .context("invalid inlay hints range end")?;
9168 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9169 &lsp_store,
9170 server_id,
9171 lsp_request_id,
9172 &inlay_hints,
9173 query_start..query_end,
9174 &mut cx,
9175 )
9176 .await
9177 .context("preparing inlay hints request")?;
9178 Self::query_lsp_locally::<InlayHints>(
9179 lsp_store,
9180 server_id,
9181 sender_id,
9182 lsp_request_id,
9183 inlay_hints,
9184 None,
9185 &mut cx,
9186 )
9187 .await
9188 .context("querying for inlay hints")?
9189 }
9190 //////////////////////////////
9191 // Below are LSP queries that need to fetch more data,
9192 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9193 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9194 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9195 &lsp_store,
9196 &get_document_diagnostics,
9197 &mut cx,
9198 )
9199 .await?;
9200 lsp_store.update(&mut cx, |lsp_store, cx| {
9201 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9202 let key = LspKey {
9203 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9204 server_queried: server_id,
9205 };
9206 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9207 ) {
9208 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9209 lsp_requests.clear();
9210 };
9211 }
9212
9213 lsp_data.lsp_requests.entry(key).or_default().insert(
9214 lsp_request_id,
9215 cx.spawn(async move |lsp_store, cx| {
9216 let diagnostics_pull = lsp_store
9217 .update(cx, |lsp_store, cx| {
9218 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9219 })
9220 .ok();
9221 if let Some(diagnostics_pull) = diagnostics_pull {
9222 match diagnostics_pull.await {
9223 Ok(()) => {}
9224 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9225 };
9226 }
9227 }),
9228 );
9229 });
9230 }
9231 Request::SemanticTokens(semantic_tokens) => {
9232 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9233 &lsp_store,
9234 &semantic_tokens,
9235 &mut cx,
9236 )
9237 .await?;
9238 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9239 lsp_store.update(&mut cx, |lsp_store, cx| {
9240 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9241 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9242 let key = LspKey {
9243 request_type: TypeId::of::<SemanticTokensFull>(),
9244 server_queried: server_id,
9245 };
9246 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9247 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9248 lsp_requests.clear();
9249 };
9250 }
9251
9252 lsp_data.lsp_requests.entry(key).or_default().insert(
9253 lsp_request_id,
9254 cx.spawn(async move |lsp_store, cx| {
9255 let tokens_fetch = lsp_store
9256 .update(cx, |lsp_store, cx| {
9257 lsp_store
9258 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9259 })
9260 .ok();
9261 if let Some(tokens_fetch) = tokens_fetch {
9262 let new_tokens = tokens_fetch.await;
9263 if let Some(new_tokens) = new_tokens {
9264 lsp_store
9265 .update(cx, |lsp_store, cx| {
9266 let response = new_tokens
9267 .into_iter()
9268 .map(|(server_id, response)| {
9269 (
9270 server_id.to_proto(),
9271 SemanticTokensFull::response_to_proto(
9272 response,
9273 lsp_store,
9274 sender_id,
9275 &buffer_version,
9276 cx,
9277 ),
9278 )
9279 })
9280 .collect::<HashMap<_, _>>();
9281 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9282 project_id,
9283 lsp_request_id,
9284 response,
9285 ) {
9286 Ok(()) => {}
9287 Err(e) => {
9288 log::error!(
9289 "Failed to send semantic tokens LSP response: {e:#}",
9290 )
9291 }
9292 }
9293 })
9294 .ok();
9295 }
9296 }
9297 }),
9298 );
9299 }
9300 });
9301 }
9302 }
9303 Ok(proto::Ack {})
9304 }
9305
9306 async fn handle_lsp_query_response(
9307 lsp_store: Entity<Self>,
9308 envelope: TypedEnvelope<proto::LspQueryResponse>,
9309 cx: AsyncApp,
9310 ) -> Result<()> {
9311 lsp_store.read_with(&cx, |lsp_store, _| {
9312 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9313 upstream_client.handle_lsp_response(envelope.clone());
9314 }
9315 });
9316 Ok(())
9317 }
9318
9319 async fn handle_apply_code_action(
9320 this: Entity<Self>,
9321 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9322 mut cx: AsyncApp,
9323 ) -> Result<proto::ApplyCodeActionResponse> {
9324 let sender_id = envelope.original_sender_id().unwrap_or_default();
9325 let action =
9326 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9327 let apply_code_action = this.update(&mut cx, |this, cx| {
9328 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9329 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9330 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9331 })?;
9332
9333 let project_transaction = apply_code_action.await?;
9334 let project_transaction = this.update(&mut cx, |this, cx| {
9335 this.buffer_store.update(cx, |buffer_store, cx| {
9336 buffer_store.serialize_project_transaction_for_peer(
9337 project_transaction,
9338 sender_id,
9339 cx,
9340 )
9341 })
9342 });
9343 Ok(proto::ApplyCodeActionResponse {
9344 transaction: Some(project_transaction),
9345 })
9346 }
9347
9348 async fn handle_register_buffer_with_language_servers(
9349 this: Entity<Self>,
9350 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9351 mut cx: AsyncApp,
9352 ) -> Result<proto::Ack> {
9353 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9354 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9355 this.update(&mut cx, |this, cx| {
9356 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9357 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9358 project_id: upstream_project_id,
9359 buffer_id: buffer_id.to_proto(),
9360 only_servers: envelope.payload.only_servers,
9361 });
9362 }
9363
9364 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9365 anyhow::bail!("buffer is not open");
9366 };
9367
9368 let handle = this.register_buffer_with_language_servers(
9369 &buffer,
9370 envelope
9371 .payload
9372 .only_servers
9373 .into_iter()
9374 .filter_map(|selector| {
9375 Some(match selector.selector? {
9376 proto::language_server_selector::Selector::ServerId(server_id) => {
9377 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9378 }
9379 proto::language_server_selector::Selector::Name(name) => {
9380 LanguageServerSelector::Name(LanguageServerName(
9381 SharedString::from(name),
9382 ))
9383 }
9384 })
9385 })
9386 .collect(),
9387 false,
9388 cx,
9389 );
9390 // Pull diagnostics for the buffer even if it was already registered.
9391 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9392 // but it's unclear if we need it.
9393 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9394 .detach();
9395 this.buffer_store().update(cx, |buffer_store, _| {
9396 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9397 });
9398
9399 Ok(())
9400 })?;
9401 Ok(proto::Ack {})
9402 }
9403
9404 async fn handle_rename_project_entry(
9405 this: Entity<Self>,
9406 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9407 mut cx: AsyncApp,
9408 ) -> Result<proto::ProjectEntryResponse> {
9409 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9410 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9411 let new_path =
9412 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9413
9414 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9415 .update(&mut cx, |this, cx| {
9416 let (worktree, entry) = this
9417 .worktree_store
9418 .read(cx)
9419 .worktree_and_entry_for_id(entry_id, cx)?;
9420 let new_worktree = this
9421 .worktree_store
9422 .read(cx)
9423 .worktree_for_id(new_worktree_id, cx)?;
9424 Some((
9425 this.worktree_store.clone(),
9426 worktree,
9427 new_worktree,
9428 entry.clone(),
9429 ))
9430 })
9431 .context("worktree not found")?;
9432 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9433 (worktree.absolutize(&old_entry.path), worktree.id())
9434 });
9435 let new_abs_path =
9436 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9437
9438 let _transaction = Self::will_rename_entry(
9439 this.downgrade(),
9440 old_worktree_id,
9441 &old_abs_path,
9442 &new_abs_path,
9443 old_entry.is_dir(),
9444 cx.clone(),
9445 )
9446 .await;
9447 let response = WorktreeStore::handle_rename_project_entry(
9448 worktree_store,
9449 envelope.payload,
9450 cx.clone(),
9451 )
9452 .await;
9453 this.read_with(&cx, |this, _| {
9454 this.did_rename_entry(
9455 old_worktree_id,
9456 &old_abs_path,
9457 &new_abs_path,
9458 old_entry.is_dir(),
9459 );
9460 });
9461 response
9462 }
9463
9464 async fn handle_update_diagnostic_summary(
9465 this: Entity<Self>,
9466 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9467 mut cx: AsyncApp,
9468 ) -> Result<()> {
9469 this.update(&mut cx, |lsp_store, cx| {
9470 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9471 let mut updated_diagnostics_paths = HashMap::default();
9472 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9473 for message_summary in envelope
9474 .payload
9475 .summary
9476 .into_iter()
9477 .chain(envelope.payload.more_summaries)
9478 {
9479 let project_path = ProjectPath {
9480 worktree_id,
9481 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9482 };
9483 let path = project_path.path.clone();
9484 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9485 let summary = DiagnosticSummary {
9486 error_count: message_summary.error_count as usize,
9487 warning_count: message_summary.warning_count as usize,
9488 };
9489
9490 if summary.is_empty() {
9491 if let Some(worktree_summaries) =
9492 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9493 && let Some(summaries) = worktree_summaries.get_mut(&path)
9494 {
9495 summaries.remove(&server_id);
9496 if summaries.is_empty() {
9497 worktree_summaries.remove(&path);
9498 }
9499 }
9500 } else {
9501 lsp_store
9502 .diagnostic_summaries
9503 .entry(worktree_id)
9504 .or_default()
9505 .entry(path)
9506 .or_default()
9507 .insert(server_id, summary);
9508 }
9509
9510 if let Some((_, project_id)) = &lsp_store.downstream_client {
9511 match &mut diagnostics_summary {
9512 Some(diagnostics_summary) => {
9513 diagnostics_summary
9514 .more_summaries
9515 .push(proto::DiagnosticSummary {
9516 path: project_path.path.as_ref().to_proto(),
9517 language_server_id: server_id.0 as u64,
9518 error_count: summary.error_count as u32,
9519 warning_count: summary.warning_count as u32,
9520 })
9521 }
9522 None => {
9523 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9524 project_id: *project_id,
9525 worktree_id: worktree_id.to_proto(),
9526 summary: Some(proto::DiagnosticSummary {
9527 path: project_path.path.as_ref().to_proto(),
9528 language_server_id: server_id.0 as u64,
9529 error_count: summary.error_count as u32,
9530 warning_count: summary.warning_count as u32,
9531 }),
9532 more_summaries: Vec::new(),
9533 })
9534 }
9535 }
9536 }
9537 updated_diagnostics_paths
9538 .entry(server_id)
9539 .or_insert_with(Vec::new)
9540 .push(project_path);
9541 }
9542
9543 if let Some((diagnostics_summary, (downstream_client, _))) =
9544 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9545 {
9546 downstream_client.send(diagnostics_summary).log_err();
9547 }
9548 for (server_id, paths) in updated_diagnostics_paths {
9549 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9550 }
9551 Ok(())
9552 })
9553 }
9554
9555 async fn handle_start_language_server(
9556 lsp_store: Entity<Self>,
9557 envelope: TypedEnvelope<proto::StartLanguageServer>,
9558 mut cx: AsyncApp,
9559 ) -> Result<()> {
9560 let server = envelope.payload.server.context("invalid server")?;
9561 let server_capabilities =
9562 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9563 .with_context(|| {
9564 format!(
9565 "incorrect server capabilities {}",
9566 envelope.payload.capabilities
9567 )
9568 })?;
9569 lsp_store.update(&mut cx, |lsp_store, cx| {
9570 let server_id = LanguageServerId(server.id as usize);
9571 let server_name = LanguageServerName::from_proto(server.name.clone());
9572 lsp_store
9573 .lsp_server_capabilities
9574 .insert(server_id, server_capabilities);
9575 lsp_store.language_server_statuses.insert(
9576 server_id,
9577 LanguageServerStatus {
9578 name: server_name.clone(),
9579 server_version: None,
9580 server_readable_version: None,
9581 pending_work: Default::default(),
9582 has_pending_diagnostic_updates: false,
9583 progress_tokens: Default::default(),
9584 worktree: server.worktree_id.map(WorktreeId::from_proto),
9585 binary: None,
9586 configuration: None,
9587 workspace_folders: BTreeSet::new(),
9588 process_id: None,
9589 },
9590 );
9591 cx.emit(LspStoreEvent::LanguageServerAdded(
9592 server_id,
9593 server_name,
9594 server.worktree_id.map(WorktreeId::from_proto),
9595 ));
9596 cx.notify();
9597 });
9598 Ok(())
9599 }
9600
9601 async fn handle_update_language_server(
9602 lsp_store: Entity<Self>,
9603 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9604 mut cx: AsyncApp,
9605 ) -> Result<()> {
9606 lsp_store.update(&mut cx, |lsp_store, cx| {
9607 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9608
9609 match envelope.payload.variant.context("invalid variant")? {
9610 proto::update_language_server::Variant::WorkStart(payload) => {
9611 lsp_store.on_lsp_work_start(
9612 language_server_id,
9613 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9614 .context("invalid progress token value")?,
9615 LanguageServerProgress {
9616 title: payload.title,
9617 is_disk_based_diagnostics_progress: false,
9618 is_cancellable: payload.is_cancellable.unwrap_or(false),
9619 message: payload.message,
9620 percentage: payload.percentage.map(|p| p as usize),
9621 last_update_at: cx.background_executor().now(),
9622 },
9623 cx,
9624 );
9625 }
9626 proto::update_language_server::Variant::WorkProgress(payload) => {
9627 lsp_store.on_lsp_work_progress(
9628 language_server_id,
9629 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9630 .context("invalid progress token value")?,
9631 LanguageServerProgress {
9632 title: None,
9633 is_disk_based_diagnostics_progress: false,
9634 is_cancellable: payload.is_cancellable.unwrap_or(false),
9635 message: payload.message,
9636 percentage: payload.percentage.map(|p| p as usize),
9637 last_update_at: cx.background_executor().now(),
9638 },
9639 cx,
9640 );
9641 }
9642
9643 proto::update_language_server::Variant::WorkEnd(payload) => {
9644 lsp_store.on_lsp_work_end(
9645 language_server_id,
9646 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9647 .context("invalid progress token value")?,
9648 cx,
9649 );
9650 }
9651
9652 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9653 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9654 }
9655
9656 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9657 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9658 }
9659
9660 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9661 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9662 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9663 cx.emit(LspStoreEvent::LanguageServerUpdate {
9664 language_server_id,
9665 name: envelope
9666 .payload
9667 .server_name
9668 .map(SharedString::new)
9669 .map(LanguageServerName),
9670 message: non_lsp,
9671 });
9672 }
9673 }
9674
9675 Ok(())
9676 })
9677 }
9678
9679 async fn handle_language_server_log(
9680 this: Entity<Self>,
9681 envelope: TypedEnvelope<proto::LanguageServerLog>,
9682 mut cx: AsyncApp,
9683 ) -> Result<()> {
9684 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9685 let log_type = envelope
9686 .payload
9687 .log_type
9688 .map(LanguageServerLogType::from_proto)
9689 .context("invalid language server log type")?;
9690
9691 let message = envelope.payload.message;
9692
9693 this.update(&mut cx, |_, cx| {
9694 cx.emit(LspStoreEvent::LanguageServerLog(
9695 language_server_id,
9696 log_type,
9697 message,
9698 ));
9699 });
9700 Ok(())
9701 }
9702
9703 async fn handle_lsp_ext_cancel_flycheck(
9704 lsp_store: Entity<Self>,
9705 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9706 cx: AsyncApp,
9707 ) -> Result<proto::Ack> {
9708 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9709 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9710 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9711 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9712 } else {
9713 None
9714 }
9715 });
9716 if let Some(task) = task {
9717 task.context("handling lsp ext cancel flycheck")?;
9718 }
9719
9720 Ok(proto::Ack {})
9721 }
9722
9723 async fn handle_lsp_ext_run_flycheck(
9724 lsp_store: Entity<Self>,
9725 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9726 mut cx: AsyncApp,
9727 ) -> Result<proto::Ack> {
9728 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9729 lsp_store.update(&mut cx, |lsp_store, cx| {
9730 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9731 let text_document = if envelope.payload.current_file_only {
9732 let buffer_id = envelope
9733 .payload
9734 .buffer_id
9735 .map(|id| BufferId::new(id))
9736 .transpose()?;
9737 buffer_id
9738 .and_then(|buffer_id| {
9739 lsp_store
9740 .buffer_store()
9741 .read(cx)
9742 .get(buffer_id)
9743 .and_then(|buffer| {
9744 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9745 })
9746 .map(|path| make_text_document_identifier(&path))
9747 })
9748 .transpose()?
9749 } else {
9750 None
9751 };
9752 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9753 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9754 )?;
9755 }
9756 anyhow::Ok(())
9757 })?;
9758
9759 Ok(proto::Ack {})
9760 }
9761
9762 async fn handle_lsp_ext_clear_flycheck(
9763 lsp_store: Entity<Self>,
9764 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9765 cx: AsyncApp,
9766 ) -> Result<proto::Ack> {
9767 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9768 lsp_store.read_with(&cx, |lsp_store, _| {
9769 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9770 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9771 } else {
9772 None
9773 }
9774 });
9775
9776 Ok(proto::Ack {})
9777 }
9778
9779 pub fn disk_based_diagnostics_started(
9780 &mut self,
9781 language_server_id: LanguageServerId,
9782 cx: &mut Context<Self>,
9783 ) {
9784 if let Some(language_server_status) =
9785 self.language_server_statuses.get_mut(&language_server_id)
9786 {
9787 language_server_status.has_pending_diagnostic_updates = true;
9788 }
9789
9790 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9791 cx.emit(LspStoreEvent::LanguageServerUpdate {
9792 language_server_id,
9793 name: self
9794 .language_server_adapter_for_id(language_server_id)
9795 .map(|adapter| adapter.name()),
9796 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9797 Default::default(),
9798 ),
9799 })
9800 }
9801
9802 pub fn disk_based_diagnostics_finished(
9803 &mut self,
9804 language_server_id: LanguageServerId,
9805 cx: &mut Context<Self>,
9806 ) {
9807 if let Some(language_server_status) =
9808 self.language_server_statuses.get_mut(&language_server_id)
9809 {
9810 language_server_status.has_pending_diagnostic_updates = false;
9811 }
9812
9813 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9814 cx.emit(LspStoreEvent::LanguageServerUpdate {
9815 language_server_id,
9816 name: self
9817 .language_server_adapter_for_id(language_server_id)
9818 .map(|adapter| adapter.name()),
9819 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9820 Default::default(),
9821 ),
9822 })
9823 }
9824
9825 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9826 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9827 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9828 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9829 // the language server might take some time to publish diagnostics.
9830 fn simulate_disk_based_diagnostics_events_if_needed(
9831 &mut self,
9832 language_server_id: LanguageServerId,
9833 cx: &mut Context<Self>,
9834 ) {
9835 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9836
9837 let Some(LanguageServerState::Running {
9838 simulate_disk_based_diagnostics_completion,
9839 adapter,
9840 ..
9841 }) = self
9842 .as_local_mut()
9843 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9844 else {
9845 return;
9846 };
9847
9848 if adapter.disk_based_diagnostics_progress_token.is_some() {
9849 return;
9850 }
9851
9852 let prev_task =
9853 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9854 cx.background_executor()
9855 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9856 .await;
9857
9858 this.update(cx, |this, cx| {
9859 this.disk_based_diagnostics_finished(language_server_id, cx);
9860
9861 if let Some(LanguageServerState::Running {
9862 simulate_disk_based_diagnostics_completion,
9863 ..
9864 }) = this.as_local_mut().and_then(|local_store| {
9865 local_store.language_servers.get_mut(&language_server_id)
9866 }) {
9867 *simulate_disk_based_diagnostics_completion = None;
9868 }
9869 })
9870 .ok();
9871 }));
9872
9873 if prev_task.is_none() {
9874 self.disk_based_diagnostics_started(language_server_id, cx);
9875 }
9876 }
9877
9878 pub fn language_server_statuses(
9879 &self,
9880 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9881 self.language_server_statuses
9882 .iter()
9883 .map(|(key, value)| (*key, value))
9884 }
9885
9886 pub(super) fn did_rename_entry(
9887 &self,
9888 worktree_id: WorktreeId,
9889 old_path: &Path,
9890 new_path: &Path,
9891 is_dir: bool,
9892 ) {
9893 maybe!({
9894 let local_store = self.as_local()?;
9895
9896 let old_uri = lsp::Uri::from_file_path(old_path)
9897 .ok()
9898 .map(|uri| uri.to_string())?;
9899 let new_uri = lsp::Uri::from_file_path(new_path)
9900 .ok()
9901 .map(|uri| uri.to_string())?;
9902
9903 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9904 let Some(filter) = local_store
9905 .language_server_paths_watched_for_rename
9906 .get(&language_server.server_id())
9907 else {
9908 continue;
9909 };
9910
9911 if filter.should_send_did_rename(&old_uri, is_dir) {
9912 language_server
9913 .notify::<DidRenameFiles>(RenameFilesParams {
9914 files: vec![FileRename {
9915 old_uri: old_uri.clone(),
9916 new_uri: new_uri.clone(),
9917 }],
9918 })
9919 .ok();
9920 }
9921 }
9922 Some(())
9923 });
9924 }
9925
9926 pub(super) fn will_rename_entry(
9927 this: WeakEntity<Self>,
9928 worktree_id: WorktreeId,
9929 old_path: &Path,
9930 new_path: &Path,
9931 is_dir: bool,
9932 cx: AsyncApp,
9933 ) -> Task<ProjectTransaction> {
9934 let old_uri = lsp::Uri::from_file_path(old_path)
9935 .ok()
9936 .map(|uri| uri.to_string());
9937 let new_uri = lsp::Uri::from_file_path(new_path)
9938 .ok()
9939 .map(|uri| uri.to_string());
9940 cx.spawn(async move |cx| {
9941 let mut tasks = vec![];
9942 this.update(cx, |this, cx| {
9943 let local_store = this.as_local()?;
9944 let old_uri = old_uri?;
9945 let new_uri = new_uri?;
9946 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9947 let Some(filter) = local_store
9948 .language_server_paths_watched_for_rename
9949 .get(&language_server.server_id())
9950 else {
9951 continue;
9952 };
9953
9954 if !filter.should_send_will_rename(&old_uri, is_dir) {
9955 continue;
9956 }
9957 let request_timeout = ProjectSettings::get_global(cx)
9958 .global_lsp_settings
9959 .get_request_timeout();
9960
9961 let apply_edit = cx.spawn({
9962 let old_uri = old_uri.clone();
9963 let new_uri = new_uri.clone();
9964 let language_server = language_server.clone();
9965 async move |this, cx| {
9966 let edit = language_server
9967 .request::<WillRenameFiles>(
9968 RenameFilesParams {
9969 files: vec![FileRename { old_uri, new_uri }],
9970 },
9971 request_timeout,
9972 )
9973 .await
9974 .into_response()
9975 .context("will rename files")
9976 .log_err()
9977 .flatten()?;
9978
9979 LocalLspStore::deserialize_workspace_edit(
9980 this.upgrade()?,
9981 edit,
9982 false,
9983 language_server.clone(),
9984 cx,
9985 )
9986 .await
9987 .ok()
9988 }
9989 });
9990 tasks.push(apply_edit);
9991 }
9992 Some(())
9993 })
9994 .ok()
9995 .flatten();
9996 let mut merged_transaction = ProjectTransaction::default();
9997 for task in tasks {
9998 // Await on tasks sequentially so that the order of application of edits is deterministic
9999 // (at least with regards to the order of registration of language servers)
10000 if let Some(transaction) = task.await {
10001 for (buffer, buffer_transaction) in transaction.0 {
10002 merged_transaction.0.insert(buffer, buffer_transaction);
10003 }
10004 }
10005 }
10006 merged_transaction
10007 })
10008 }
10009
10010 fn lsp_notify_abs_paths_changed(
10011 &mut self,
10012 server_id: LanguageServerId,
10013 changes: Vec<PathEvent>,
10014 ) {
10015 maybe!({
10016 let server = self.language_server_for_id(server_id)?;
10017 let changes = changes
10018 .into_iter()
10019 .filter_map(|event| {
10020 let typ = match event.kind? {
10021 PathEventKind::Created => lsp::FileChangeType::CREATED,
10022 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10023 PathEventKind::Changed | PathEventKind::Rescan => {
10024 lsp::FileChangeType::CHANGED
10025 }
10026 };
10027 Some(lsp::FileEvent {
10028 uri: file_path_to_lsp_url(&event.path).log_err()?,
10029 typ,
10030 })
10031 })
10032 .collect::<Vec<_>>();
10033 if !changes.is_empty() {
10034 server
10035 .notify::<lsp::notification::DidChangeWatchedFiles>(
10036 lsp::DidChangeWatchedFilesParams { changes },
10037 )
10038 .ok();
10039 }
10040 Some(())
10041 });
10042 }
10043
10044 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10045 self.as_local()?.language_server_for_id(id)
10046 }
10047
10048 fn on_lsp_progress(
10049 &mut self,
10050 progress_params: lsp::ProgressParams,
10051 language_server_id: LanguageServerId,
10052 disk_based_diagnostics_progress_token: Option<String>,
10053 cx: &mut Context<Self>,
10054 ) {
10055 match progress_params.value {
10056 lsp::ProgressParamsValue::WorkDone(progress) => {
10057 self.handle_work_done_progress(
10058 progress,
10059 language_server_id,
10060 disk_based_diagnostics_progress_token,
10061 ProgressToken::from_lsp(progress_params.token),
10062 cx,
10063 );
10064 }
10065 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10066 let registration_id = match progress_params.token {
10067 lsp::NumberOrString::Number(_) => None,
10068 lsp::NumberOrString::String(token) => token
10069 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10070 .map(|(_, id)| id.to_owned()),
10071 };
10072 if let Some(LanguageServerState::Running {
10073 workspace_diagnostics_refresh_tasks,
10074 ..
10075 }) = self
10076 .as_local_mut()
10077 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10078 && let Some(workspace_diagnostics) =
10079 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10080 {
10081 workspace_diagnostics.progress_tx.try_send(()).ok();
10082 self.apply_workspace_diagnostic_report(
10083 language_server_id,
10084 report,
10085 registration_id.map(SharedString::from),
10086 cx,
10087 )
10088 }
10089 }
10090 }
10091 }
10092
10093 fn handle_work_done_progress(
10094 &mut self,
10095 progress: lsp::WorkDoneProgress,
10096 language_server_id: LanguageServerId,
10097 disk_based_diagnostics_progress_token: Option<String>,
10098 token: ProgressToken,
10099 cx: &mut Context<Self>,
10100 ) {
10101 let language_server_status =
10102 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10103 status
10104 } else {
10105 return;
10106 };
10107
10108 if !language_server_status.progress_tokens.contains(&token) {
10109 return;
10110 }
10111
10112 let is_disk_based_diagnostics_progress =
10113 if let (Some(disk_based_token), ProgressToken::String(token)) =
10114 (&disk_based_diagnostics_progress_token, &token)
10115 {
10116 token.starts_with(disk_based_token)
10117 } else {
10118 false
10119 };
10120
10121 match progress {
10122 lsp::WorkDoneProgress::Begin(report) => {
10123 if is_disk_based_diagnostics_progress {
10124 self.disk_based_diagnostics_started(language_server_id, cx);
10125 }
10126 self.on_lsp_work_start(
10127 language_server_id,
10128 token.clone(),
10129 LanguageServerProgress {
10130 title: Some(report.title),
10131 is_disk_based_diagnostics_progress,
10132 is_cancellable: report.cancellable.unwrap_or(false),
10133 message: report.message.clone(),
10134 percentage: report.percentage.map(|p| p as usize),
10135 last_update_at: cx.background_executor().now(),
10136 },
10137 cx,
10138 );
10139 }
10140 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10141 language_server_id,
10142 token,
10143 LanguageServerProgress {
10144 title: None,
10145 is_disk_based_diagnostics_progress,
10146 is_cancellable: report.cancellable.unwrap_or(false),
10147 message: report.message,
10148 percentage: report.percentage.map(|p| p as usize),
10149 last_update_at: cx.background_executor().now(),
10150 },
10151 cx,
10152 ),
10153 lsp::WorkDoneProgress::End(_) => {
10154 language_server_status.progress_tokens.remove(&token);
10155 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10156 if is_disk_based_diagnostics_progress {
10157 self.disk_based_diagnostics_finished(language_server_id, cx);
10158 }
10159 }
10160 }
10161 }
10162
10163 fn on_lsp_work_start(
10164 &mut self,
10165 language_server_id: LanguageServerId,
10166 token: ProgressToken,
10167 progress: LanguageServerProgress,
10168 cx: &mut Context<Self>,
10169 ) {
10170 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10171 status.pending_work.insert(token.clone(), progress.clone());
10172 cx.notify();
10173 }
10174 cx.emit(LspStoreEvent::LanguageServerUpdate {
10175 language_server_id,
10176 name: self
10177 .language_server_adapter_for_id(language_server_id)
10178 .map(|adapter| adapter.name()),
10179 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10180 token: Some(token.to_proto()),
10181 title: progress.title,
10182 message: progress.message,
10183 percentage: progress.percentage.map(|p| p as u32),
10184 is_cancellable: Some(progress.is_cancellable),
10185 }),
10186 })
10187 }
10188
10189 fn on_lsp_work_progress(
10190 &mut self,
10191 language_server_id: LanguageServerId,
10192 token: ProgressToken,
10193 progress: LanguageServerProgress,
10194 cx: &mut Context<Self>,
10195 ) {
10196 let mut did_update = false;
10197 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10198 match status.pending_work.entry(token.clone()) {
10199 btree_map::Entry::Vacant(entry) => {
10200 entry.insert(progress.clone());
10201 did_update = true;
10202 }
10203 btree_map::Entry::Occupied(mut entry) => {
10204 let entry = entry.get_mut();
10205 if (progress.last_update_at - entry.last_update_at)
10206 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10207 {
10208 entry.last_update_at = progress.last_update_at;
10209 if progress.message.is_some() {
10210 entry.message = progress.message.clone();
10211 }
10212 if progress.percentage.is_some() {
10213 entry.percentage = progress.percentage;
10214 }
10215 if progress.is_cancellable != entry.is_cancellable {
10216 entry.is_cancellable = progress.is_cancellable;
10217 }
10218 did_update = true;
10219 }
10220 }
10221 }
10222 }
10223
10224 if did_update {
10225 cx.emit(LspStoreEvent::LanguageServerUpdate {
10226 language_server_id,
10227 name: self
10228 .language_server_adapter_for_id(language_server_id)
10229 .map(|adapter| adapter.name()),
10230 message: proto::update_language_server::Variant::WorkProgress(
10231 proto::LspWorkProgress {
10232 token: Some(token.to_proto()),
10233 message: progress.message,
10234 percentage: progress.percentage.map(|p| p as u32),
10235 is_cancellable: Some(progress.is_cancellable),
10236 },
10237 ),
10238 })
10239 }
10240 }
10241
10242 fn on_lsp_work_end(
10243 &mut self,
10244 language_server_id: LanguageServerId,
10245 token: ProgressToken,
10246 cx: &mut Context<Self>,
10247 ) {
10248 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10249 if let Some(work) = status.pending_work.remove(&token)
10250 && !work.is_disk_based_diagnostics_progress
10251 {
10252 cx.emit(LspStoreEvent::RefreshInlayHints {
10253 server_id: language_server_id,
10254 request_id: None,
10255 });
10256 }
10257 cx.notify();
10258 }
10259
10260 cx.emit(LspStoreEvent::LanguageServerUpdate {
10261 language_server_id,
10262 name: self
10263 .language_server_adapter_for_id(language_server_id)
10264 .map(|adapter| adapter.name()),
10265 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10266 token: Some(token.to_proto()),
10267 }),
10268 })
10269 }
10270
10271 pub async fn handle_resolve_completion_documentation(
10272 this: Entity<Self>,
10273 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10274 mut cx: AsyncApp,
10275 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10276 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10277
10278 let completion = this
10279 .read_with(&cx, |this, cx| {
10280 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10281 let server = this
10282 .language_server_for_id(id)
10283 .with_context(|| format!("No language server {id}"))?;
10284
10285 let request_timeout = ProjectSettings::get_global(cx)
10286 .global_lsp_settings
10287 .get_request_timeout();
10288
10289 anyhow::Ok(cx.background_spawn(async move {
10290 let can_resolve = server
10291 .capabilities()
10292 .completion_provider
10293 .as_ref()
10294 .and_then(|options| options.resolve_provider)
10295 .unwrap_or(false);
10296 if can_resolve {
10297 server
10298 .request::<lsp::request::ResolveCompletionItem>(
10299 lsp_completion,
10300 request_timeout,
10301 )
10302 .await
10303 .into_response()
10304 .context("resolve completion item")
10305 } else {
10306 anyhow::Ok(lsp_completion)
10307 }
10308 }))
10309 })?
10310 .await?;
10311
10312 let mut documentation_is_markdown = false;
10313 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10314 let documentation = match completion.documentation {
10315 Some(lsp::Documentation::String(text)) => text,
10316
10317 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10318 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10319 value
10320 }
10321
10322 _ => String::new(),
10323 };
10324
10325 // If we have a new buffer_id, that means we're talking to a new client
10326 // and want to check for new text_edits in the completion too.
10327 let mut old_replace_start = None;
10328 let mut old_replace_end = None;
10329 let mut old_insert_start = None;
10330 let mut old_insert_end = None;
10331 let mut new_text = String::default();
10332 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10333 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10334 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10335 anyhow::Ok(buffer.read(cx).snapshot())
10336 })?;
10337
10338 if let Some(text_edit) = completion.text_edit.as_ref() {
10339 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10340
10341 if let Some(mut edit) = edit {
10342 LineEnding::normalize(&mut edit.new_text);
10343
10344 new_text = edit.new_text;
10345 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10346 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10347 if let Some(insert_range) = edit.insert_range {
10348 old_insert_start = Some(serialize_anchor(&insert_range.start));
10349 old_insert_end = Some(serialize_anchor(&insert_range.end));
10350 }
10351 }
10352 }
10353 }
10354
10355 Ok(proto::ResolveCompletionDocumentationResponse {
10356 documentation,
10357 documentation_is_markdown,
10358 old_replace_start,
10359 old_replace_end,
10360 new_text,
10361 lsp_completion,
10362 old_insert_start,
10363 old_insert_end,
10364 })
10365 }
10366
10367 async fn handle_on_type_formatting(
10368 this: Entity<Self>,
10369 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10370 mut cx: AsyncApp,
10371 ) -> Result<proto::OnTypeFormattingResponse> {
10372 let on_type_formatting = this.update(&mut cx, |this, cx| {
10373 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10374 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10375 let position = envelope
10376 .payload
10377 .position
10378 .and_then(deserialize_anchor)
10379 .context("invalid position")?;
10380 anyhow::Ok(this.apply_on_type_formatting(
10381 buffer,
10382 position,
10383 envelope.payload.trigger.clone(),
10384 cx,
10385 ))
10386 })?;
10387
10388 let transaction = on_type_formatting
10389 .await?
10390 .as_ref()
10391 .map(language::proto::serialize_transaction);
10392 Ok(proto::OnTypeFormattingResponse { transaction })
10393 }
10394
10395 async fn handle_pull_workspace_diagnostics(
10396 lsp_store: Entity<Self>,
10397 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10398 mut cx: AsyncApp,
10399 ) -> Result<proto::Ack> {
10400 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10401 lsp_store.update(&mut cx, |lsp_store, _| {
10402 lsp_store.pull_workspace_diagnostics(server_id);
10403 });
10404 Ok(proto::Ack {})
10405 }
10406
10407 async fn handle_open_buffer_for_symbol(
10408 this: Entity<Self>,
10409 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10410 mut cx: AsyncApp,
10411 ) -> Result<proto::OpenBufferForSymbolResponse> {
10412 let peer_id = envelope.original_sender_id().unwrap_or_default();
10413 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10414 let symbol = Self::deserialize_symbol(symbol)?;
10415 this.read_with(&cx, |this, _| {
10416 if let SymbolLocation::OutsideProject {
10417 abs_path,
10418 signature,
10419 } = &symbol.path
10420 {
10421 let new_signature = this.symbol_signature(&abs_path);
10422 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10423 }
10424 Ok(())
10425 })?;
10426 let buffer = this
10427 .update(&mut cx, |this, cx| {
10428 this.open_buffer_for_symbol(
10429 &Symbol {
10430 language_server_name: symbol.language_server_name,
10431 source_worktree_id: symbol.source_worktree_id,
10432 source_language_server_id: symbol.source_language_server_id,
10433 path: symbol.path,
10434 name: symbol.name,
10435 kind: symbol.kind,
10436 range: symbol.range,
10437 label: CodeLabel::default(),
10438 container_name: symbol.container_name,
10439 },
10440 cx,
10441 )
10442 })
10443 .await?;
10444
10445 this.update(&mut cx, |this, cx| {
10446 let is_private = buffer
10447 .read(cx)
10448 .file()
10449 .map(|f| f.is_private())
10450 .unwrap_or_default();
10451 if is_private {
10452 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10453 } else {
10454 this.buffer_store
10455 .update(cx, |buffer_store, cx| {
10456 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10457 })
10458 .detach_and_log_err(cx);
10459 let buffer_id = buffer.read(cx).remote_id().to_proto();
10460 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10461 }
10462 })
10463 }
10464
10465 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10466 let mut hasher = Sha256::new();
10467 hasher.update(abs_path.to_string_lossy().as_bytes());
10468 hasher.update(self.nonce.to_be_bytes());
10469 hasher.finalize().as_slice().try_into().unwrap()
10470 }
10471
10472 pub async fn handle_get_project_symbols(
10473 this: Entity<Self>,
10474 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10475 mut cx: AsyncApp,
10476 ) -> Result<proto::GetProjectSymbolsResponse> {
10477 let symbols = this
10478 .update(&mut cx, |this, cx| {
10479 this.symbols(&envelope.payload.query, cx)
10480 })
10481 .await?;
10482
10483 Ok(proto::GetProjectSymbolsResponse {
10484 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10485 })
10486 }
10487
10488 pub async fn handle_restart_language_servers(
10489 this: Entity<Self>,
10490 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10491 mut cx: AsyncApp,
10492 ) -> Result<proto::Ack> {
10493 this.update(&mut cx, |lsp_store, cx| {
10494 let buffers =
10495 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10496 lsp_store.restart_language_servers_for_buffers(
10497 buffers,
10498 envelope
10499 .payload
10500 .only_servers
10501 .into_iter()
10502 .filter_map(|selector| {
10503 Some(match selector.selector? {
10504 proto::language_server_selector::Selector::ServerId(server_id) => {
10505 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10506 }
10507 proto::language_server_selector::Selector::Name(name) => {
10508 LanguageServerSelector::Name(LanguageServerName(
10509 SharedString::from(name),
10510 ))
10511 }
10512 })
10513 })
10514 .collect(),
10515 cx,
10516 );
10517 });
10518
10519 Ok(proto::Ack {})
10520 }
10521
10522 pub async fn handle_stop_language_servers(
10523 lsp_store: Entity<Self>,
10524 envelope: TypedEnvelope<proto::StopLanguageServers>,
10525 mut cx: AsyncApp,
10526 ) -> Result<proto::Ack> {
10527 lsp_store.update(&mut cx, |lsp_store, cx| {
10528 if envelope.payload.all
10529 && envelope.payload.also_servers.is_empty()
10530 && envelope.payload.buffer_ids.is_empty()
10531 {
10532 lsp_store.stop_all_language_servers(cx);
10533 } else {
10534 let buffers =
10535 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10536 lsp_store
10537 .stop_language_servers_for_buffers(
10538 buffers,
10539 envelope
10540 .payload
10541 .also_servers
10542 .into_iter()
10543 .filter_map(|selector| {
10544 Some(match selector.selector? {
10545 proto::language_server_selector::Selector::ServerId(
10546 server_id,
10547 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10548 server_id,
10549 )),
10550 proto::language_server_selector::Selector::Name(name) => {
10551 LanguageServerSelector::Name(LanguageServerName(
10552 SharedString::from(name),
10553 ))
10554 }
10555 })
10556 })
10557 .collect(),
10558 cx,
10559 )
10560 .detach_and_log_err(cx);
10561 }
10562 });
10563
10564 Ok(proto::Ack {})
10565 }
10566
10567 pub async fn handle_cancel_language_server_work(
10568 lsp_store: Entity<Self>,
10569 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10570 mut cx: AsyncApp,
10571 ) -> Result<proto::Ack> {
10572 lsp_store.update(&mut cx, |lsp_store, cx| {
10573 if let Some(work) = envelope.payload.work {
10574 match work {
10575 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10576 let buffers =
10577 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10578 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10579 }
10580 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10581 let server_id = LanguageServerId::from_proto(work.language_server_id);
10582 let token = work
10583 .token
10584 .map(|token| {
10585 ProgressToken::from_proto(token)
10586 .context("invalid work progress token")
10587 })
10588 .transpose()?;
10589 lsp_store.cancel_language_server_work(server_id, token, cx);
10590 }
10591 }
10592 }
10593 anyhow::Ok(())
10594 })?;
10595
10596 Ok(proto::Ack {})
10597 }
10598
10599 fn buffer_ids_to_buffers(
10600 &mut self,
10601 buffer_ids: impl Iterator<Item = u64>,
10602 cx: &mut Context<Self>,
10603 ) -> Vec<Entity<Buffer>> {
10604 buffer_ids
10605 .into_iter()
10606 .flat_map(|buffer_id| {
10607 self.buffer_store
10608 .read(cx)
10609 .get(BufferId::new(buffer_id).log_err()?)
10610 })
10611 .collect::<Vec<_>>()
10612 }
10613
10614 async fn handle_apply_additional_edits_for_completion(
10615 this: Entity<Self>,
10616 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10617 mut cx: AsyncApp,
10618 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10619 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10620 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10621 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10622 let completion = Self::deserialize_completion(
10623 envelope.payload.completion.context("invalid completion")?,
10624 )?;
10625 let all_commit_ranges = envelope
10626 .payload
10627 .all_commit_ranges
10628 .into_iter()
10629 .map(language::proto::deserialize_anchor_range)
10630 .collect::<Result<Vec<_>, _>>()?;
10631 anyhow::Ok((buffer, completion, all_commit_ranges))
10632 })?;
10633
10634 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10635 this.apply_additional_edits_for_completion(
10636 buffer,
10637 Rc::new(RefCell::new(Box::new([Completion {
10638 replace_range: completion.replace_range,
10639 new_text: completion.new_text,
10640 source: completion.source,
10641 documentation: None,
10642 label: CodeLabel::default(),
10643 match_start: None,
10644 snippet_deduplication_key: None,
10645 insert_text_mode: None,
10646 icon_path: None,
10647 confirm: None,
10648 }]))),
10649 0,
10650 false,
10651 all_commit_ranges,
10652 cx,
10653 )
10654 });
10655
10656 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10657 transaction: apply_additional_edits
10658 .await?
10659 .as_ref()
10660 .map(language::proto::serialize_transaction),
10661 })
10662 }
10663
10664 pub fn last_formatting_failure(&self) -> Option<&str> {
10665 self.last_formatting_failure.as_deref()
10666 }
10667
10668 pub fn reset_last_formatting_failure(&mut self) {
10669 self.last_formatting_failure = None;
10670 }
10671
10672 pub fn environment_for_buffer(
10673 &self,
10674 buffer: &Entity<Buffer>,
10675 cx: &mut Context<Self>,
10676 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10677 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10678 environment.update(cx, |env, cx| {
10679 env.buffer_environment(buffer, &self.worktree_store, cx)
10680 })
10681 } else {
10682 Task::ready(None).shared()
10683 }
10684 }
10685
10686 pub fn format(
10687 &mut self,
10688 buffers: HashSet<Entity<Buffer>>,
10689 target: LspFormatTarget,
10690 push_to_history: bool,
10691 trigger: FormatTrigger,
10692 cx: &mut Context<Self>,
10693 ) -> Task<anyhow::Result<ProjectTransaction>> {
10694 let logger = zlog::scoped!("format");
10695 if self.as_local().is_some() {
10696 zlog::trace!(logger => "Formatting locally");
10697 let logger = zlog::scoped!(logger => "local");
10698 let buffers = buffers
10699 .into_iter()
10700 .map(|buffer_handle| {
10701 let buffer = buffer_handle.read(cx);
10702 let buffer_abs_path = File::from_dyn(buffer.file())
10703 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10704
10705 (buffer_handle, buffer_abs_path, buffer.remote_id())
10706 })
10707 .collect::<Vec<_>>();
10708
10709 cx.spawn(async move |lsp_store, cx| {
10710 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10711
10712 for (handle, abs_path, id) in buffers {
10713 let env = lsp_store
10714 .update(cx, |lsp_store, cx| {
10715 lsp_store.environment_for_buffer(&handle, cx)
10716 })?
10717 .await;
10718
10719 let ranges = match &target {
10720 LspFormatTarget::Buffers => None,
10721 LspFormatTarget::Ranges(ranges) => {
10722 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10723 }
10724 };
10725
10726 formattable_buffers.push(FormattableBuffer {
10727 handle,
10728 abs_path,
10729 env,
10730 ranges,
10731 });
10732 }
10733 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10734
10735 let format_timer = zlog::time!(logger => "Formatting buffers");
10736 let result = LocalLspStore::format_locally(
10737 lsp_store.clone(),
10738 formattable_buffers,
10739 push_to_history,
10740 trigger,
10741 logger,
10742 cx,
10743 )
10744 .await;
10745 format_timer.end();
10746
10747 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10748
10749 lsp_store.update(cx, |lsp_store, _| {
10750 lsp_store.update_last_formatting_failure(&result);
10751 })?;
10752
10753 result
10754 })
10755 } else if let Some((client, project_id)) = self.upstream_client() {
10756 zlog::trace!(logger => "Formatting remotely");
10757 let logger = zlog::scoped!(logger => "remote");
10758
10759 let buffer_ranges = match &target {
10760 LspFormatTarget::Buffers => Vec::new(),
10761 LspFormatTarget::Ranges(ranges) => ranges
10762 .iter()
10763 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10764 buffer_id: buffer_id.to_proto(),
10765 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10766 })
10767 .collect(),
10768 };
10769
10770 let buffer_store = self.buffer_store();
10771 cx.spawn(async move |lsp_store, cx| {
10772 zlog::trace!(logger => "Sending remote format request");
10773 let request_timer = zlog::time!(logger => "remote format request");
10774 let result = client
10775 .request(proto::FormatBuffers {
10776 project_id,
10777 trigger: trigger as i32,
10778 buffer_ids: buffers
10779 .iter()
10780 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10781 .collect(),
10782 buffer_ranges,
10783 })
10784 .await
10785 .and_then(|result| result.transaction.context("missing transaction"));
10786 request_timer.end();
10787
10788 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10789
10790 lsp_store.update(cx, |lsp_store, _| {
10791 lsp_store.update_last_formatting_failure(&result);
10792 })?;
10793
10794 let transaction_response = result?;
10795 let _timer = zlog::time!(logger => "deserializing project transaction");
10796 buffer_store
10797 .update(cx, |buffer_store, cx| {
10798 buffer_store.deserialize_project_transaction(
10799 transaction_response,
10800 push_to_history,
10801 cx,
10802 )
10803 })
10804 .await
10805 })
10806 } else {
10807 zlog::trace!(logger => "Not formatting");
10808 Task::ready(Ok(ProjectTransaction::default()))
10809 }
10810 }
10811
10812 async fn handle_format_buffers(
10813 this: Entity<Self>,
10814 envelope: TypedEnvelope<proto::FormatBuffers>,
10815 mut cx: AsyncApp,
10816 ) -> Result<proto::FormatBuffersResponse> {
10817 let sender_id = envelope.original_sender_id().unwrap_or_default();
10818 let format = this.update(&mut cx, |this, cx| {
10819 let mut buffers = HashSet::default();
10820 for buffer_id in &envelope.payload.buffer_ids {
10821 let buffer_id = BufferId::new(*buffer_id)?;
10822 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10823 }
10824
10825 let target = if envelope.payload.buffer_ranges.is_empty() {
10826 LspFormatTarget::Buffers
10827 } else {
10828 let mut ranges_map = BTreeMap::new();
10829 for buffer_range in &envelope.payload.buffer_ranges {
10830 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10831 let ranges: Result<Vec<_>> = buffer_range
10832 .ranges
10833 .iter()
10834 .map(|range| {
10835 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10836 })
10837 .collect();
10838 ranges_map.insert(buffer_id, ranges?);
10839 }
10840 LspFormatTarget::Ranges(ranges_map)
10841 };
10842
10843 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10844 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10845 })?;
10846
10847 let project_transaction = format.await?;
10848 let project_transaction = this.update(&mut cx, |this, cx| {
10849 this.buffer_store.update(cx, |buffer_store, cx| {
10850 buffer_store.serialize_project_transaction_for_peer(
10851 project_transaction,
10852 sender_id,
10853 cx,
10854 )
10855 })
10856 });
10857 Ok(proto::FormatBuffersResponse {
10858 transaction: Some(project_transaction),
10859 })
10860 }
10861
10862 async fn handle_apply_code_action_kind(
10863 this: Entity<Self>,
10864 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10865 mut cx: AsyncApp,
10866 ) -> Result<proto::ApplyCodeActionKindResponse> {
10867 let sender_id = envelope.original_sender_id().unwrap_or_default();
10868 let format = this.update(&mut cx, |this, cx| {
10869 let mut buffers = HashSet::default();
10870 for buffer_id in &envelope.payload.buffer_ids {
10871 let buffer_id = BufferId::new(*buffer_id)?;
10872 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10873 }
10874 let kind = match envelope.payload.kind.as_str() {
10875 "" => CodeActionKind::EMPTY,
10876 "quickfix" => CodeActionKind::QUICKFIX,
10877 "refactor" => CodeActionKind::REFACTOR,
10878 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10879 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10880 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10881 "source" => CodeActionKind::SOURCE,
10882 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10883 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10884 _ => anyhow::bail!(
10885 "Invalid code action kind {}",
10886 envelope.payload.kind.as_str()
10887 ),
10888 };
10889 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, 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::ApplyCodeActionKindResponse {
10903 transaction: Some(project_transaction),
10904 })
10905 }
10906
10907 async fn shutdown_language_server(
10908 server_state: Option<LanguageServerState>,
10909 name: LanguageServerName,
10910 cx: &mut AsyncApp,
10911 ) {
10912 let server = match server_state {
10913 Some(LanguageServerState::Starting { startup, .. }) => {
10914 let mut timer = cx
10915 .background_executor()
10916 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10917 .fuse();
10918
10919 select! {
10920 server = startup.fuse() => server,
10921 () = timer => {
10922 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10923 None
10924 },
10925 }
10926 }
10927
10928 Some(LanguageServerState::Running { server, .. }) => Some(server),
10929
10930 None => None,
10931 };
10932
10933 let Some(server) = server else { return };
10934 if let Some(shutdown) = server.shutdown() {
10935 shutdown.await;
10936 }
10937 }
10938
10939 // Returns a list of all of the worktrees which no longer have a language server and the root path
10940 // for the stopped server
10941 fn stop_local_language_server(
10942 &mut self,
10943 server_id: LanguageServerId,
10944 cx: &mut Context<Self>,
10945 ) -> Task<()> {
10946 let local = match &mut self.mode {
10947 LspStoreMode::Local(local) => local,
10948 _ => {
10949 return Task::ready(());
10950 }
10951 };
10952
10953 // Remove this server ID from all entries in the given worktree.
10954 local
10955 .language_server_ids
10956 .retain(|_, state| state.id != server_id);
10957 self.buffer_store.update(cx, |buffer_store, cx| {
10958 for buffer in buffer_store.buffers() {
10959 buffer.update(cx, |buffer, cx| {
10960 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10961 buffer.set_completion_triggers(server_id, Default::default(), cx);
10962 });
10963 }
10964 });
10965
10966 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10967 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10968 summaries.retain(|path, summaries_by_server_id| {
10969 if summaries_by_server_id.remove(&server_id).is_some() {
10970 if let Some((client, project_id)) = self.downstream_client.clone() {
10971 client
10972 .send(proto::UpdateDiagnosticSummary {
10973 project_id,
10974 worktree_id: worktree_id.to_proto(),
10975 summary: Some(proto::DiagnosticSummary {
10976 path: path.as_ref().to_proto(),
10977 language_server_id: server_id.0 as u64,
10978 error_count: 0,
10979 warning_count: 0,
10980 }),
10981 more_summaries: Vec::new(),
10982 })
10983 .log_err();
10984 }
10985 cleared_paths.push(ProjectPath {
10986 worktree_id: *worktree_id,
10987 path: path.clone(),
10988 });
10989 !summaries_by_server_id.is_empty()
10990 } else {
10991 true
10992 }
10993 });
10994 }
10995 if !cleared_paths.is_empty() {
10996 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10997 server_id,
10998 paths: cleared_paths,
10999 });
11000 }
11001
11002 let local = self.as_local_mut().unwrap();
11003 for diagnostics in local.diagnostics.values_mut() {
11004 diagnostics.retain(|_, diagnostics_by_server_id| {
11005 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11006 diagnostics_by_server_id.remove(ix);
11007 !diagnostics_by_server_id.is_empty()
11008 } else {
11009 true
11010 }
11011 });
11012 }
11013 local.language_server_watched_paths.remove(&server_id);
11014
11015 let server_state = local.language_servers.remove(&server_id);
11016 self.cleanup_lsp_data(server_id);
11017 let name = self
11018 .language_server_statuses
11019 .remove(&server_id)
11020 .map(|status| status.name)
11021 .or_else(|| {
11022 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11023 Some(adapter.name())
11024 } else {
11025 None
11026 }
11027 });
11028
11029 if let Some(name) = name {
11030 log::info!("stopping language server {name}");
11031 self.languages
11032 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11033 cx.notify();
11034
11035 return cx.spawn(async move |lsp_store, cx| {
11036 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11037 lsp_store
11038 .update(cx, |lsp_store, cx| {
11039 lsp_store
11040 .languages
11041 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11042 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11043 cx.notify();
11044 })
11045 .ok();
11046 });
11047 }
11048
11049 if server_state.is_some() {
11050 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11051 }
11052 Task::ready(())
11053 }
11054
11055 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11056 self.shutdown_all_language_servers(cx).detach();
11057 }
11058
11059 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11060 if let Some((client, project_id)) = self.upstream_client() {
11061 let request = client.request(proto::StopLanguageServers {
11062 project_id,
11063 buffer_ids: Vec::new(),
11064 also_servers: Vec::new(),
11065 all: true,
11066 });
11067 cx.background_spawn(async move {
11068 request.await.ok();
11069 })
11070 } else {
11071 let Some(local) = self.as_local_mut() else {
11072 return Task::ready(());
11073 };
11074 let language_servers_to_stop = local
11075 .language_server_ids
11076 .values()
11077 .map(|state| state.id)
11078 .collect();
11079 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11080 let tasks = language_servers_to_stop
11081 .into_iter()
11082 .map(|server| self.stop_local_language_server(server, cx))
11083 .collect::<Vec<_>>();
11084 cx.background_spawn(async move {
11085 futures::future::join_all(tasks).await;
11086 })
11087 }
11088 }
11089
11090 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11091 let buffers = self.buffer_store.read(cx).buffers().collect();
11092 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11093 }
11094
11095 pub fn restart_language_servers_for_buffers(
11096 &mut self,
11097 buffers: Vec<Entity<Buffer>>,
11098 only_restart_servers: HashSet<LanguageServerSelector>,
11099 cx: &mut Context<Self>,
11100 ) {
11101 if let Some((client, project_id)) = self.upstream_client() {
11102 let request = client.request(proto::RestartLanguageServers {
11103 project_id,
11104 buffer_ids: buffers
11105 .into_iter()
11106 .map(|b| b.read(cx).remote_id().to_proto())
11107 .collect(),
11108 only_servers: only_restart_servers
11109 .into_iter()
11110 .map(|selector| {
11111 let selector = match selector {
11112 LanguageServerSelector::Id(language_server_id) => {
11113 proto::language_server_selector::Selector::ServerId(
11114 language_server_id.to_proto(),
11115 )
11116 }
11117 LanguageServerSelector::Name(language_server_name) => {
11118 proto::language_server_selector::Selector::Name(
11119 language_server_name.to_string(),
11120 )
11121 }
11122 };
11123 proto::LanguageServerSelector {
11124 selector: Some(selector),
11125 }
11126 })
11127 .collect(),
11128 all: false,
11129 });
11130 cx.background_spawn(request).detach_and_log_err(cx);
11131 } else {
11132 let stop_task = if only_restart_servers.is_empty() {
11133 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11134 } else {
11135 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11136 };
11137 cx.spawn(async move |lsp_store, cx| {
11138 stop_task.await;
11139 lsp_store.update(cx, |lsp_store, cx| {
11140 for buffer in buffers {
11141 lsp_store.register_buffer_with_language_servers(
11142 &buffer,
11143 only_restart_servers.clone(),
11144 true,
11145 cx,
11146 );
11147 }
11148 })
11149 })
11150 .detach();
11151 }
11152 }
11153
11154 pub fn stop_language_servers_for_buffers(
11155 &mut self,
11156 buffers: Vec<Entity<Buffer>>,
11157 also_stop_servers: HashSet<LanguageServerSelector>,
11158 cx: &mut Context<Self>,
11159 ) -> Task<Result<()>> {
11160 if let Some((client, project_id)) = self.upstream_client() {
11161 let request = client.request(proto::StopLanguageServers {
11162 project_id,
11163 buffer_ids: buffers
11164 .into_iter()
11165 .map(|b| b.read(cx).remote_id().to_proto())
11166 .collect(),
11167 also_servers: also_stop_servers
11168 .into_iter()
11169 .map(|selector| {
11170 let selector = match selector {
11171 LanguageServerSelector::Id(language_server_id) => {
11172 proto::language_server_selector::Selector::ServerId(
11173 language_server_id.to_proto(),
11174 )
11175 }
11176 LanguageServerSelector::Name(language_server_name) => {
11177 proto::language_server_selector::Selector::Name(
11178 language_server_name.to_string(),
11179 )
11180 }
11181 };
11182 proto::LanguageServerSelector {
11183 selector: Some(selector),
11184 }
11185 })
11186 .collect(),
11187 all: false,
11188 });
11189 cx.background_spawn(async move {
11190 let _ = request.await?;
11191 Ok(())
11192 })
11193 } else {
11194 let task =
11195 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11196 cx.background_spawn(async move {
11197 task.await;
11198 Ok(())
11199 })
11200 }
11201 }
11202
11203 fn stop_local_language_servers_for_buffers(
11204 &mut self,
11205 buffers: &[Entity<Buffer>],
11206 also_stop_servers: HashSet<LanguageServerSelector>,
11207 cx: &mut Context<Self>,
11208 ) -> Task<()> {
11209 let Some(local) = self.as_local_mut() else {
11210 return Task::ready(());
11211 };
11212 let mut language_server_names_to_stop = BTreeSet::default();
11213 let mut language_servers_to_stop = also_stop_servers
11214 .into_iter()
11215 .flat_map(|selector| match selector {
11216 LanguageServerSelector::Id(id) => Some(id),
11217 LanguageServerSelector::Name(name) => {
11218 language_server_names_to_stop.insert(name);
11219 None
11220 }
11221 })
11222 .collect::<BTreeSet<_>>();
11223
11224 let mut covered_worktrees = HashSet::default();
11225 for buffer in buffers {
11226 buffer.update(cx, |buffer, cx| {
11227 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11228 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11229 && covered_worktrees.insert(worktree_id)
11230 {
11231 language_server_names_to_stop.retain(|name| {
11232 let old_ids_count = language_servers_to_stop.len();
11233 let all_language_servers_with_this_name = local
11234 .language_server_ids
11235 .iter()
11236 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11237 language_servers_to_stop.extend(all_language_servers_with_this_name);
11238 old_ids_count == language_servers_to_stop.len()
11239 });
11240 }
11241 });
11242 }
11243 for name in language_server_names_to_stop {
11244 language_servers_to_stop.extend(
11245 local
11246 .language_server_ids
11247 .iter()
11248 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11249 );
11250 }
11251
11252 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11253 let tasks = language_servers_to_stop
11254 .into_iter()
11255 .map(|server| self.stop_local_language_server(server, cx))
11256 .collect::<Vec<_>>();
11257
11258 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11259 }
11260
11261 #[cfg(any(test, feature = "test-support"))]
11262 pub fn update_diagnostics(
11263 &mut self,
11264 server_id: LanguageServerId,
11265 diagnostics: lsp::PublishDiagnosticsParams,
11266 result_id: Option<SharedString>,
11267 source_kind: DiagnosticSourceKind,
11268 disk_based_sources: &[String],
11269 cx: &mut Context<Self>,
11270 ) -> Result<()> {
11271 self.merge_lsp_diagnostics(
11272 source_kind,
11273 vec![DocumentDiagnosticsUpdate {
11274 diagnostics,
11275 result_id,
11276 server_id,
11277 disk_based_sources: Cow::Borrowed(disk_based_sources),
11278 registration_id: None,
11279 }],
11280 |_, _, _| false,
11281 cx,
11282 )
11283 }
11284
11285 pub fn merge_lsp_diagnostics(
11286 &mut self,
11287 source_kind: DiagnosticSourceKind,
11288 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11289 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11290 cx: &mut Context<Self>,
11291 ) -> Result<()> {
11292 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11293 let updates = lsp_diagnostics
11294 .into_iter()
11295 .filter_map(|update| {
11296 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11297 Some(DocumentDiagnosticsUpdate {
11298 diagnostics: self.lsp_to_document_diagnostics(
11299 abs_path,
11300 source_kind,
11301 update.server_id,
11302 update.diagnostics,
11303 &update.disk_based_sources,
11304 update.registration_id.clone(),
11305 ),
11306 result_id: update.result_id,
11307 server_id: update.server_id,
11308 disk_based_sources: update.disk_based_sources,
11309 registration_id: update.registration_id,
11310 })
11311 })
11312 .collect();
11313 self.merge_diagnostic_entries(updates, merge, cx)?;
11314 Ok(())
11315 }
11316
11317 fn lsp_to_document_diagnostics(
11318 &mut self,
11319 document_abs_path: PathBuf,
11320 source_kind: DiagnosticSourceKind,
11321 server_id: LanguageServerId,
11322 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11323 disk_based_sources: &[String],
11324 registration_id: Option<SharedString>,
11325 ) -> DocumentDiagnostics {
11326 let mut diagnostics = Vec::default();
11327 let mut primary_diagnostic_group_ids = HashMap::default();
11328 let mut sources_by_group_id = HashMap::default();
11329 let mut supporting_diagnostics = HashMap::default();
11330
11331 let adapter = self.language_server_adapter_for_id(server_id);
11332
11333 // Ensure that primary diagnostics are always the most severe
11334 lsp_diagnostics
11335 .diagnostics
11336 .sort_by_key(|item| item.severity);
11337
11338 for diagnostic in &lsp_diagnostics.diagnostics {
11339 let source = diagnostic.source.as_ref();
11340 let range = range_from_lsp(diagnostic.range);
11341 let is_supporting = diagnostic
11342 .related_information
11343 .as_ref()
11344 .is_some_and(|infos| {
11345 infos.iter().any(|info| {
11346 primary_diagnostic_group_ids.contains_key(&(
11347 source,
11348 diagnostic.code.clone(),
11349 range_from_lsp(info.location.range),
11350 ))
11351 })
11352 });
11353
11354 let is_unnecessary = diagnostic
11355 .tags
11356 .as_ref()
11357 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11358
11359 let underline = self
11360 .language_server_adapter_for_id(server_id)
11361 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11362
11363 if is_supporting {
11364 supporting_diagnostics.insert(
11365 (source, diagnostic.code.clone(), range),
11366 (diagnostic.severity, is_unnecessary),
11367 );
11368 } else {
11369 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11370 let is_disk_based =
11371 source.is_some_and(|source| disk_based_sources.contains(source));
11372
11373 sources_by_group_id.insert(group_id, source);
11374 primary_diagnostic_group_ids
11375 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11376
11377 diagnostics.push(DiagnosticEntry {
11378 range,
11379 diagnostic: Diagnostic {
11380 source: diagnostic.source.clone(),
11381 source_kind,
11382 code: diagnostic.code.clone(),
11383 code_description: diagnostic
11384 .code_description
11385 .as_ref()
11386 .and_then(|d| d.href.clone()),
11387 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11388 markdown: adapter.as_ref().and_then(|adapter| {
11389 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11390 }),
11391 message: diagnostic.message.trim().to_string(),
11392 group_id,
11393 is_primary: true,
11394 is_disk_based,
11395 is_unnecessary,
11396 underline,
11397 data: diagnostic.data.clone(),
11398 registration_id: registration_id.clone(),
11399 },
11400 });
11401 if let Some(infos) = &diagnostic.related_information {
11402 for info in infos {
11403 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11404 let range = range_from_lsp(info.location.range);
11405 diagnostics.push(DiagnosticEntry {
11406 range,
11407 diagnostic: Diagnostic {
11408 source: diagnostic.source.clone(),
11409 source_kind,
11410 code: diagnostic.code.clone(),
11411 code_description: diagnostic
11412 .code_description
11413 .as_ref()
11414 .and_then(|d| d.href.clone()),
11415 severity: DiagnosticSeverity::INFORMATION,
11416 markdown: adapter.as_ref().and_then(|adapter| {
11417 adapter.diagnostic_message_to_markdown(&info.message)
11418 }),
11419 message: info.message.trim().to_string(),
11420 group_id,
11421 is_primary: false,
11422 is_disk_based,
11423 is_unnecessary: false,
11424 underline,
11425 data: diagnostic.data.clone(),
11426 registration_id: registration_id.clone(),
11427 },
11428 });
11429 }
11430 }
11431 }
11432 }
11433 }
11434
11435 for entry in &mut diagnostics {
11436 let diagnostic = &mut entry.diagnostic;
11437 if !diagnostic.is_primary {
11438 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11439 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11440 source,
11441 diagnostic.code.clone(),
11442 entry.range.clone(),
11443 )) {
11444 if let Some(severity) = severity {
11445 diagnostic.severity = severity;
11446 }
11447 diagnostic.is_unnecessary = is_unnecessary;
11448 }
11449 }
11450 }
11451
11452 DocumentDiagnostics {
11453 diagnostics,
11454 document_abs_path,
11455 version: lsp_diagnostics.version,
11456 }
11457 }
11458
11459 fn insert_newly_running_language_server(
11460 &mut self,
11461 adapter: Arc<CachedLspAdapter>,
11462 language_server: Arc<LanguageServer>,
11463 server_id: LanguageServerId,
11464 key: LanguageServerSeed,
11465 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11466 cx: &mut Context<Self>,
11467 ) {
11468 let Some(local) = self.as_local_mut() else {
11469 return;
11470 };
11471 // If the language server for this key doesn't match the server id, don't store the
11472 // server. Which will cause it to be dropped, killing the process
11473 if local
11474 .language_server_ids
11475 .get(&key)
11476 .map(|state| state.id != server_id)
11477 .unwrap_or(false)
11478 {
11479 return;
11480 }
11481
11482 // Update language_servers collection with Running variant of LanguageServerState
11483 // indicating that the server is up and running and ready
11484 let workspace_folders = workspace_folders.lock().clone();
11485 language_server.set_workspace_folders(workspace_folders);
11486
11487 let workspace_diagnostics_refresh_tasks = language_server
11488 .capabilities()
11489 .diagnostic_provider
11490 .and_then(|provider| {
11491 local
11492 .language_server_dynamic_registrations
11493 .entry(server_id)
11494 .or_default()
11495 .diagnostics
11496 .entry(None)
11497 .or_insert(provider.clone());
11498 let workspace_refresher =
11499 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11500
11501 Some((None, workspace_refresher))
11502 })
11503 .into_iter()
11504 .collect();
11505 local.language_servers.insert(
11506 server_id,
11507 LanguageServerState::Running {
11508 workspace_diagnostics_refresh_tasks,
11509 adapter: adapter.clone(),
11510 server: language_server.clone(),
11511 simulate_disk_based_diagnostics_completion: None,
11512 },
11513 );
11514 local
11515 .languages
11516 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11517 if let Some(file_ops_caps) = language_server
11518 .capabilities()
11519 .workspace
11520 .as_ref()
11521 .and_then(|ws| ws.file_operations.as_ref())
11522 {
11523 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11524 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11525 if did_rename_caps.or(will_rename_caps).is_some() {
11526 let watcher = RenamePathsWatchedForServer::default()
11527 .with_did_rename_patterns(did_rename_caps)
11528 .with_will_rename_patterns(will_rename_caps);
11529 local
11530 .language_server_paths_watched_for_rename
11531 .insert(server_id, watcher);
11532 }
11533 }
11534
11535 self.language_server_statuses.insert(
11536 server_id,
11537 LanguageServerStatus {
11538 name: language_server.name(),
11539 server_version: language_server.version(),
11540 server_readable_version: language_server.readable_version(),
11541 pending_work: Default::default(),
11542 has_pending_diagnostic_updates: false,
11543 progress_tokens: Default::default(),
11544 worktree: Some(key.worktree_id),
11545 binary: Some(language_server.binary().clone()),
11546 configuration: Some(language_server.configuration().clone()),
11547 workspace_folders: language_server.workspace_folders(),
11548 process_id: language_server.process_id(),
11549 },
11550 );
11551
11552 cx.emit(LspStoreEvent::LanguageServerAdded(
11553 server_id,
11554 language_server.name(),
11555 Some(key.worktree_id),
11556 ));
11557
11558 let server_capabilities = language_server.capabilities();
11559 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11560 downstream_client
11561 .send(proto::StartLanguageServer {
11562 project_id: *project_id,
11563 server: Some(proto::LanguageServer {
11564 id: server_id.to_proto(),
11565 name: language_server.name().to_string(),
11566 worktree_id: Some(key.worktree_id.to_proto()),
11567 }),
11568 capabilities: serde_json::to_string(&server_capabilities)
11569 .expect("serializing server LSP capabilities"),
11570 })
11571 .log_err();
11572 }
11573 self.lsp_server_capabilities
11574 .insert(server_id, server_capabilities);
11575
11576 // Tell the language server about every open buffer in the worktree that matches the language.
11577 // Also check for buffers in worktrees that reused this server
11578 let mut worktrees_using_server = vec![key.worktree_id];
11579 if let Some(local) = self.as_local() {
11580 // Find all worktrees that have this server in their language server tree
11581 for (worktree_id, servers) in &local.lsp_tree.instances {
11582 if *worktree_id != key.worktree_id {
11583 for server_map in servers.roots.values() {
11584 if server_map
11585 .values()
11586 .any(|(node, _)| node.id() == Some(server_id))
11587 {
11588 worktrees_using_server.push(*worktree_id);
11589 }
11590 }
11591 }
11592 }
11593 }
11594
11595 let mut buffer_paths_registered = Vec::new();
11596 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11597 let mut lsp_adapters = HashMap::default();
11598 for buffer_handle in buffer_store.buffers() {
11599 let buffer = buffer_handle.read(cx);
11600 let file = match File::from_dyn(buffer.file()) {
11601 Some(file) => file,
11602 None => continue,
11603 };
11604 let language = match buffer.language() {
11605 Some(language) => language,
11606 None => continue,
11607 };
11608
11609 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11610 || !lsp_adapters
11611 .entry(language.name())
11612 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11613 .iter()
11614 .any(|a| a.name == key.name)
11615 {
11616 continue;
11617 }
11618 // didOpen
11619 let file = match file.as_local() {
11620 Some(file) => file,
11621 None => continue,
11622 };
11623
11624 let local = self.as_local_mut().unwrap();
11625
11626 let buffer_id = buffer.remote_id();
11627 if local.registered_buffers.contains_key(&buffer_id) {
11628 let abs_path = file.abs_path(cx);
11629 let uri = match lsp::Uri::from_file_path(&abs_path) {
11630 Ok(uri) => uri,
11631 Err(()) => {
11632 log::error!("failed to convert path to URI: {:?}", abs_path);
11633 continue;
11634 }
11635 };
11636
11637 let versions = local
11638 .buffer_snapshots
11639 .entry(buffer_id)
11640 .or_default()
11641 .entry(server_id)
11642 .and_modify(|_| {
11643 assert!(
11644 false,
11645 "There should not be an existing snapshot for a newly inserted buffer"
11646 )
11647 })
11648 .or_insert_with(|| {
11649 vec![LspBufferSnapshot {
11650 version: 0,
11651 snapshot: buffer.text_snapshot(),
11652 }]
11653 });
11654
11655 let snapshot = versions.last().unwrap();
11656 let version = snapshot.version;
11657 let initial_snapshot = &snapshot.snapshot;
11658 language_server.register_buffer(
11659 uri,
11660 adapter.language_id(&language.name()),
11661 version,
11662 initial_snapshot.text(),
11663 );
11664 buffer_paths_registered.push((buffer_id, abs_path));
11665 local
11666 .buffers_opened_in_servers
11667 .entry(buffer_id)
11668 .or_default()
11669 .insert(server_id);
11670 }
11671 buffer_handle.update(cx, |buffer, cx| {
11672 buffer.set_completion_triggers(
11673 server_id,
11674 language_server
11675 .capabilities()
11676 .completion_provider
11677 .as_ref()
11678 .and_then(|provider| {
11679 provider
11680 .trigger_characters
11681 .as_ref()
11682 .map(|characters| characters.iter().cloned().collect())
11683 })
11684 .unwrap_or_default(),
11685 cx,
11686 )
11687 });
11688 }
11689 });
11690
11691 for (buffer_id, abs_path) in buffer_paths_registered {
11692 cx.emit(LspStoreEvent::LanguageServerUpdate {
11693 language_server_id: server_id,
11694 name: Some(adapter.name()),
11695 message: proto::update_language_server::Variant::RegisteredForBuffer(
11696 proto::RegisteredForBuffer {
11697 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11698 buffer_id: buffer_id.to_proto(),
11699 },
11700 ),
11701 });
11702 }
11703
11704 cx.notify();
11705 }
11706
11707 pub fn language_servers_running_disk_based_diagnostics(
11708 &self,
11709 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11710 self.language_server_statuses
11711 .iter()
11712 .filter_map(|(id, status)| {
11713 if status.has_pending_diagnostic_updates {
11714 Some(*id)
11715 } else {
11716 None
11717 }
11718 })
11719 }
11720
11721 pub(crate) fn cancel_language_server_work_for_buffers(
11722 &mut self,
11723 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11724 cx: &mut Context<Self>,
11725 ) {
11726 if let Some((client, project_id)) = self.upstream_client() {
11727 let request = client.request(proto::CancelLanguageServerWork {
11728 project_id,
11729 work: Some(proto::cancel_language_server_work::Work::Buffers(
11730 proto::cancel_language_server_work::Buffers {
11731 buffer_ids: buffers
11732 .into_iter()
11733 .map(|b| b.read(cx).remote_id().to_proto())
11734 .collect(),
11735 },
11736 )),
11737 });
11738 cx.background_spawn(request).detach_and_log_err(cx);
11739 } else if let Some(local) = self.as_local() {
11740 let servers = buffers
11741 .into_iter()
11742 .flat_map(|buffer| {
11743 buffer.update(cx, |buffer, cx| {
11744 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11745 })
11746 })
11747 .collect::<HashSet<_>>();
11748 for server_id in servers {
11749 self.cancel_language_server_work(server_id, None, cx);
11750 }
11751 }
11752 }
11753
11754 pub(crate) fn cancel_language_server_work(
11755 &mut self,
11756 server_id: LanguageServerId,
11757 token_to_cancel: Option<ProgressToken>,
11758 cx: &mut Context<Self>,
11759 ) {
11760 if let Some(local) = self.as_local() {
11761 let status = self.language_server_statuses.get(&server_id);
11762 let server = local.language_servers.get(&server_id);
11763 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11764 {
11765 for (token, progress) in &status.pending_work {
11766 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11767 && token != token_to_cancel
11768 {
11769 continue;
11770 }
11771 if progress.is_cancellable {
11772 server
11773 .notify::<lsp::notification::WorkDoneProgressCancel>(
11774 WorkDoneProgressCancelParams {
11775 token: token.to_lsp(),
11776 },
11777 )
11778 .ok();
11779 }
11780 }
11781 }
11782 } else if let Some((client, project_id)) = self.upstream_client() {
11783 let request = client.request(proto::CancelLanguageServerWork {
11784 project_id,
11785 work: Some(
11786 proto::cancel_language_server_work::Work::LanguageServerWork(
11787 proto::cancel_language_server_work::LanguageServerWork {
11788 language_server_id: server_id.to_proto(),
11789 token: token_to_cancel.map(|token| token.to_proto()),
11790 },
11791 ),
11792 ),
11793 });
11794 cx.background_spawn(request).detach_and_log_err(cx);
11795 }
11796 }
11797
11798 fn register_supplementary_language_server(
11799 &mut self,
11800 id: LanguageServerId,
11801 name: LanguageServerName,
11802 server: Arc<LanguageServer>,
11803 cx: &mut Context<Self>,
11804 ) {
11805 if let Some(local) = self.as_local_mut() {
11806 local
11807 .supplementary_language_servers
11808 .insert(id, (name.clone(), server));
11809 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11810 }
11811 }
11812
11813 fn unregister_supplementary_language_server(
11814 &mut self,
11815 id: LanguageServerId,
11816 cx: &mut Context<Self>,
11817 ) {
11818 if let Some(local) = self.as_local_mut() {
11819 local.supplementary_language_servers.remove(&id);
11820 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11821 }
11822 }
11823
11824 pub(crate) fn supplementary_language_servers(
11825 &self,
11826 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11827 self.as_local().into_iter().flat_map(|local| {
11828 local
11829 .supplementary_language_servers
11830 .iter()
11831 .map(|(id, (name, _))| (*id, name.clone()))
11832 })
11833 }
11834
11835 pub fn language_server_adapter_for_id(
11836 &self,
11837 id: LanguageServerId,
11838 ) -> Option<Arc<CachedLspAdapter>> {
11839 self.as_local()
11840 .and_then(|local| local.language_servers.get(&id))
11841 .and_then(|language_server_state| match language_server_state {
11842 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11843 _ => None,
11844 })
11845 }
11846
11847 pub(super) fn update_local_worktree_language_servers(
11848 &mut self,
11849 worktree_handle: &Entity<Worktree>,
11850 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11851 cx: &mut Context<Self>,
11852 ) {
11853 if changes.is_empty() {
11854 return;
11855 }
11856
11857 let Some(local) = self.as_local() else { return };
11858
11859 local.prettier_store.update(cx, |prettier_store, cx| {
11860 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11861 });
11862
11863 let worktree_id = worktree_handle.read(cx).id();
11864 let mut language_server_ids = local
11865 .language_server_ids
11866 .iter()
11867 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11868 .collect::<Vec<_>>();
11869 language_server_ids.sort();
11870 language_server_ids.dedup();
11871
11872 // let abs_path = worktree_handle.read(cx).abs_path();
11873 for server_id in &language_server_ids {
11874 if let Some(LanguageServerState::Running { server, .. }) =
11875 local.language_servers.get(server_id)
11876 && let Some(watched_paths) = local
11877 .language_server_watched_paths
11878 .get(server_id)
11879 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11880 {
11881 let params = lsp::DidChangeWatchedFilesParams {
11882 changes: changes
11883 .iter()
11884 .filter_map(|(path, _, change)| {
11885 if !watched_paths.is_match(path.as_std_path()) {
11886 return None;
11887 }
11888 let typ = match change {
11889 PathChange::Loaded => return None,
11890 PathChange::Added => lsp::FileChangeType::CREATED,
11891 PathChange::Removed => lsp::FileChangeType::DELETED,
11892 PathChange::Updated => lsp::FileChangeType::CHANGED,
11893 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11894 };
11895 let uri = lsp::Uri::from_file_path(
11896 worktree_handle.read(cx).absolutize(&path),
11897 )
11898 .ok()?;
11899 Some(lsp::FileEvent { uri, typ })
11900 })
11901 .collect(),
11902 };
11903 if !params.changes.is_empty() {
11904 server
11905 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11906 .ok();
11907 }
11908 }
11909 }
11910 for (path, _, _) in changes {
11911 if let Some(file_name) = path.file_name()
11912 && local.watched_manifest_filenames.contains(file_name)
11913 {
11914 self.request_workspace_config_refresh();
11915 break;
11916 }
11917 }
11918 }
11919
11920 pub fn wait_for_remote_buffer(
11921 &mut self,
11922 id: BufferId,
11923 cx: &mut Context<Self>,
11924 ) -> Task<Result<Entity<Buffer>>> {
11925 self.buffer_store.update(cx, |buffer_store, cx| {
11926 buffer_store.wait_for_remote_buffer(id, cx)
11927 })
11928 }
11929
11930 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11931 let mut result = proto::Symbol {
11932 language_server_name: symbol.language_server_name.0.to_string(),
11933 source_worktree_id: symbol.source_worktree_id.to_proto(),
11934 language_server_id: symbol.source_language_server_id.to_proto(),
11935 name: symbol.name.clone(),
11936 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11937 start: Some(proto::PointUtf16 {
11938 row: symbol.range.start.0.row,
11939 column: symbol.range.start.0.column,
11940 }),
11941 end: Some(proto::PointUtf16 {
11942 row: symbol.range.end.0.row,
11943 column: symbol.range.end.0.column,
11944 }),
11945 worktree_id: Default::default(),
11946 path: Default::default(),
11947 signature: Default::default(),
11948 container_name: symbol.container_name.clone(),
11949 };
11950 match &symbol.path {
11951 SymbolLocation::InProject(path) => {
11952 result.worktree_id = path.worktree_id.to_proto();
11953 result.path = path.path.to_proto();
11954 }
11955 SymbolLocation::OutsideProject {
11956 abs_path,
11957 signature,
11958 } => {
11959 result.path = abs_path.to_string_lossy().into_owned();
11960 result.signature = signature.to_vec();
11961 }
11962 }
11963 result
11964 }
11965
11966 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11967 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11968 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11969 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11970
11971 let path = if serialized_symbol.signature.is_empty() {
11972 SymbolLocation::InProject(ProjectPath {
11973 worktree_id,
11974 path: RelPath::from_proto(&serialized_symbol.path)
11975 .context("invalid symbol path")?,
11976 })
11977 } else {
11978 SymbolLocation::OutsideProject {
11979 abs_path: Path::new(&serialized_symbol.path).into(),
11980 signature: serialized_symbol
11981 .signature
11982 .try_into()
11983 .map_err(|_| anyhow!("invalid signature"))?,
11984 }
11985 };
11986
11987 let start = serialized_symbol.start.context("invalid start")?;
11988 let end = serialized_symbol.end.context("invalid end")?;
11989 Ok(CoreSymbol {
11990 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11991 source_worktree_id,
11992 source_language_server_id: LanguageServerId::from_proto(
11993 serialized_symbol.language_server_id,
11994 ),
11995 path,
11996 name: serialized_symbol.name,
11997 range: Unclipped(PointUtf16::new(start.row, start.column))
11998 ..Unclipped(PointUtf16::new(end.row, end.column)),
11999 kind,
12000 container_name: serialized_symbol.container_name,
12001 })
12002 }
12003
12004 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12005 let mut serialized_completion = proto::Completion {
12006 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12007 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12008 new_text: completion.new_text.clone(),
12009 ..proto::Completion::default()
12010 };
12011 match &completion.source {
12012 CompletionSource::Lsp {
12013 insert_range,
12014 server_id,
12015 lsp_completion,
12016 lsp_defaults,
12017 resolved,
12018 } => {
12019 let (old_insert_start, old_insert_end) = insert_range
12020 .as_ref()
12021 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12022 .unzip();
12023
12024 serialized_completion.old_insert_start = old_insert_start;
12025 serialized_completion.old_insert_end = old_insert_end;
12026 serialized_completion.source = proto::completion::Source::Lsp as i32;
12027 serialized_completion.server_id = server_id.0 as u64;
12028 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12029 serialized_completion.lsp_defaults = lsp_defaults
12030 .as_deref()
12031 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12032 serialized_completion.resolved = *resolved;
12033 }
12034 CompletionSource::BufferWord {
12035 word_range,
12036 resolved,
12037 } => {
12038 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12039 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12040 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12041 serialized_completion.resolved = *resolved;
12042 }
12043 CompletionSource::Custom => {
12044 serialized_completion.source = proto::completion::Source::Custom as i32;
12045 serialized_completion.resolved = true;
12046 }
12047 CompletionSource::Dap { sort_text } => {
12048 serialized_completion.source = proto::completion::Source::Dap as i32;
12049 serialized_completion.sort_text = Some(sort_text.clone());
12050 }
12051 }
12052
12053 serialized_completion
12054 }
12055
12056 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12057 let old_replace_start = completion
12058 .old_replace_start
12059 .and_then(deserialize_anchor)
12060 .context("invalid old start")?;
12061 let old_replace_end = completion
12062 .old_replace_end
12063 .and_then(deserialize_anchor)
12064 .context("invalid old end")?;
12065 let insert_range = {
12066 match completion.old_insert_start.zip(completion.old_insert_end) {
12067 Some((start, end)) => {
12068 let start = deserialize_anchor(start).context("invalid insert old start")?;
12069 let end = deserialize_anchor(end).context("invalid insert old end")?;
12070 Some(start..end)
12071 }
12072 None => None,
12073 }
12074 };
12075 Ok(CoreCompletion {
12076 replace_range: old_replace_start..old_replace_end,
12077 new_text: completion.new_text,
12078 source: match proto::completion::Source::from_i32(completion.source) {
12079 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12080 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12081 insert_range,
12082 server_id: LanguageServerId::from_proto(completion.server_id),
12083 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12084 lsp_defaults: completion
12085 .lsp_defaults
12086 .as_deref()
12087 .map(serde_json::from_slice)
12088 .transpose()?,
12089 resolved: completion.resolved,
12090 },
12091 Some(proto::completion::Source::BufferWord) => {
12092 let word_range = completion
12093 .buffer_word_start
12094 .and_then(deserialize_anchor)
12095 .context("invalid buffer word start")?
12096 ..completion
12097 .buffer_word_end
12098 .and_then(deserialize_anchor)
12099 .context("invalid buffer word end")?;
12100 CompletionSource::BufferWord {
12101 word_range,
12102 resolved: completion.resolved,
12103 }
12104 }
12105 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12106 sort_text: completion
12107 .sort_text
12108 .context("expected sort text to exist")?,
12109 },
12110 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12111 },
12112 })
12113 }
12114
12115 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12116 let (kind, lsp_action) = match &action.lsp_action {
12117 LspAction::Action(code_action) => (
12118 proto::code_action::Kind::Action as i32,
12119 serde_json::to_vec(code_action).unwrap(),
12120 ),
12121 LspAction::Command(command) => (
12122 proto::code_action::Kind::Command as i32,
12123 serde_json::to_vec(command).unwrap(),
12124 ),
12125 LspAction::CodeLens(code_lens) => (
12126 proto::code_action::Kind::CodeLens as i32,
12127 serde_json::to_vec(code_lens).unwrap(),
12128 ),
12129 };
12130
12131 proto::CodeAction {
12132 server_id: action.server_id.0 as u64,
12133 start: Some(serialize_anchor(&action.range.start)),
12134 end: Some(serialize_anchor(&action.range.end)),
12135 lsp_action,
12136 kind,
12137 resolved: action.resolved,
12138 }
12139 }
12140
12141 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12142 let start = action
12143 .start
12144 .and_then(deserialize_anchor)
12145 .context("invalid start")?;
12146 let end = action
12147 .end
12148 .and_then(deserialize_anchor)
12149 .context("invalid end")?;
12150 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12151 Some(proto::code_action::Kind::Action) => {
12152 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12153 }
12154 Some(proto::code_action::Kind::Command) => {
12155 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12156 }
12157 Some(proto::code_action::Kind::CodeLens) => {
12158 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12159 }
12160 None => anyhow::bail!("Unknown action kind {}", action.kind),
12161 };
12162 Ok(CodeAction {
12163 server_id: LanguageServerId(action.server_id as usize),
12164 range: start..end,
12165 resolved: action.resolved,
12166 lsp_action,
12167 })
12168 }
12169
12170 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12171 match &formatting_result {
12172 Ok(_) => self.last_formatting_failure = None,
12173 Err(error) => {
12174 let error_string = format!("{error:#}");
12175 log::error!("Formatting failed: {error_string}");
12176 self.last_formatting_failure
12177 .replace(error_string.lines().join(" "));
12178 }
12179 }
12180 }
12181
12182 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12183 self.lsp_server_capabilities.remove(&for_server);
12184 self.semantic_token_config.remove_server_data(for_server);
12185 for lsp_data in self.lsp_data.values_mut() {
12186 lsp_data.remove_server_data(for_server);
12187 }
12188 if let Some(local) = self.as_local_mut() {
12189 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12190 local
12191 .workspace_pull_diagnostics_result_ids
12192 .remove(&for_server);
12193 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12194 buffer_servers.remove(&for_server);
12195 }
12196 }
12197 }
12198
12199 pub fn result_id_for_buffer_pull(
12200 &self,
12201 server_id: LanguageServerId,
12202 buffer_id: BufferId,
12203 registration_id: &Option<SharedString>,
12204 cx: &App,
12205 ) -> Option<SharedString> {
12206 let abs_path = self
12207 .buffer_store
12208 .read(cx)
12209 .get(buffer_id)
12210 .and_then(|b| File::from_dyn(b.read(cx).file()))
12211 .map(|f| f.abs_path(cx))?;
12212 self.as_local()?
12213 .buffer_pull_diagnostics_result_ids
12214 .get(&server_id)?
12215 .get(registration_id)?
12216 .get(&abs_path)?
12217 .clone()
12218 }
12219
12220 /// Gets all result_ids for a workspace diagnostics pull request.
12221 /// 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.
12222 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12223 pub fn result_ids_for_workspace_refresh(
12224 &self,
12225 server_id: LanguageServerId,
12226 registration_id: &Option<SharedString>,
12227 ) -> HashMap<PathBuf, SharedString> {
12228 let Some(local) = self.as_local() else {
12229 return HashMap::default();
12230 };
12231 local
12232 .workspace_pull_diagnostics_result_ids
12233 .get(&server_id)
12234 .into_iter()
12235 .filter_map(|diagnostics| diagnostics.get(registration_id))
12236 .flatten()
12237 .filter_map(|(abs_path, result_id)| {
12238 let result_id = local
12239 .buffer_pull_diagnostics_result_ids
12240 .get(&server_id)
12241 .and_then(|buffer_ids_result_ids| {
12242 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12243 })
12244 .cloned()
12245 .flatten()
12246 .or_else(|| result_id.clone())?;
12247 Some((abs_path.clone(), result_id))
12248 })
12249 .collect()
12250 }
12251
12252 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12253 if let Some(LanguageServerState::Running {
12254 workspace_diagnostics_refresh_tasks,
12255 ..
12256 }) = self
12257 .as_local_mut()
12258 .and_then(|local| local.language_servers.get_mut(&server_id))
12259 {
12260 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12261 diagnostics.refresh_tx.try_send(()).ok();
12262 }
12263 }
12264 }
12265
12266 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12267 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12268 /// which requires refreshing both workspace and document diagnostics.
12269 pub fn pull_document_diagnostics_for_server(
12270 &mut self,
12271 server_id: LanguageServerId,
12272 source_buffer_id: Option<BufferId>,
12273 cx: &mut Context<Self>,
12274 ) -> Shared<Task<()>> {
12275 let Some(local) = self.as_local_mut() else {
12276 return Task::ready(()).shared();
12277 };
12278 let mut buffers_to_refresh = HashSet::default();
12279 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12280 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12281 buffers_to_refresh.insert(*buffer_id);
12282 }
12283 }
12284
12285 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12286 }
12287
12288 pub fn pull_document_diagnostics_for_buffer_edit(
12289 &mut self,
12290 buffer_id: BufferId,
12291 cx: &mut Context<Self>,
12292 ) {
12293 let Some(local) = self.as_local_mut() else {
12294 return;
12295 };
12296 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12297 else {
12298 return;
12299 };
12300 for server_id in languages_servers {
12301 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12302 }
12303 }
12304
12305 fn apply_workspace_diagnostic_report(
12306 &mut self,
12307 server_id: LanguageServerId,
12308 report: lsp::WorkspaceDiagnosticReportResult,
12309 registration_id: Option<SharedString>,
12310 cx: &mut Context<Self>,
12311 ) {
12312 let mut workspace_diagnostics =
12313 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12314 report,
12315 server_id,
12316 registration_id,
12317 );
12318 workspace_diagnostics.retain(|d| match &d.diagnostics {
12319 LspPullDiagnostics::Response {
12320 server_id,
12321 registration_id,
12322 ..
12323 } => self.diagnostic_registration_exists(*server_id, registration_id),
12324 LspPullDiagnostics::Default => false,
12325 });
12326 let mut unchanged_buffers = HashMap::default();
12327 let workspace_diagnostics_updates = workspace_diagnostics
12328 .into_iter()
12329 .filter_map(
12330 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12331 LspPullDiagnostics::Response {
12332 server_id,
12333 uri,
12334 diagnostics,
12335 registration_id,
12336 } => Some((
12337 server_id,
12338 uri,
12339 diagnostics,
12340 workspace_diagnostics.version,
12341 registration_id,
12342 )),
12343 LspPullDiagnostics::Default => None,
12344 },
12345 )
12346 .fold(
12347 HashMap::default(),
12348 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12349 let (result_id, diagnostics) = match diagnostics {
12350 PulledDiagnostics::Unchanged { result_id } => {
12351 unchanged_buffers
12352 .entry(new_registration_id.clone())
12353 .or_insert_with(HashSet::default)
12354 .insert(uri.clone());
12355 (Some(result_id), Vec::new())
12356 }
12357 PulledDiagnostics::Changed {
12358 result_id,
12359 diagnostics,
12360 } => (result_id, diagnostics),
12361 };
12362 let disk_based_sources = Cow::Owned(
12363 self.language_server_adapter_for_id(server_id)
12364 .as_ref()
12365 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12366 .unwrap_or(&[])
12367 .to_vec(),
12368 );
12369
12370 let Some(abs_path) = uri.to_file_path().ok() else {
12371 return acc;
12372 };
12373 let Some((worktree, relative_path)) =
12374 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12375 else {
12376 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12377 return acc;
12378 };
12379 let worktree_id = worktree.read(cx).id();
12380 let project_path = ProjectPath {
12381 worktree_id,
12382 path: relative_path,
12383 };
12384 if let Some(local_lsp_store) = self.as_local_mut() {
12385 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12386 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12387 }
12388 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12389 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12390 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12391 acc.entry(server_id)
12392 .or_insert_with(HashMap::default)
12393 .entry(new_registration_id.clone())
12394 .or_insert_with(Vec::new)
12395 .push(DocumentDiagnosticsUpdate {
12396 server_id,
12397 diagnostics: lsp::PublishDiagnosticsParams {
12398 uri,
12399 diagnostics,
12400 version,
12401 },
12402 result_id: result_id.map(SharedString::new),
12403 disk_based_sources,
12404 registration_id: new_registration_id,
12405 });
12406 }
12407 acc
12408 },
12409 );
12410
12411 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12412 for (registration_id, diagnostic_updates) in diagnostic_updates {
12413 self.merge_lsp_diagnostics(
12414 DiagnosticSourceKind::Pulled,
12415 diagnostic_updates,
12416 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12417 DiagnosticSourceKind::Pulled => {
12418 old_diagnostic.registration_id != registration_id
12419 || unchanged_buffers
12420 .get(&old_diagnostic.registration_id)
12421 .is_some_and(|unchanged_buffers| {
12422 unchanged_buffers.contains(&document_uri)
12423 })
12424 }
12425 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12426 },
12427 cx,
12428 )
12429 .log_err();
12430 }
12431 }
12432 }
12433
12434 fn register_server_capabilities(
12435 &mut self,
12436 server_id: LanguageServerId,
12437 params: lsp::RegistrationParams,
12438 cx: &mut Context<Self>,
12439 ) -> anyhow::Result<()> {
12440 let server = self
12441 .language_server_for_id(server_id)
12442 .with_context(|| format!("no server {server_id} found"))?;
12443 for reg in params.registrations {
12444 match reg.method.as_str() {
12445 "workspace/didChangeWatchedFiles" => {
12446 if let Some(options) = reg.register_options {
12447 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12448 let caps = serde_json::from_value(options)?;
12449 local_lsp_store
12450 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12451 true
12452 } else {
12453 false
12454 };
12455 if notify {
12456 notify_server_capabilities_updated(&server, cx);
12457 }
12458 }
12459 }
12460 "workspace/didChangeConfiguration" => {
12461 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12462 }
12463 "workspace/didChangeWorkspaceFolders" => {
12464 // In this case register options is an empty object, we can ignore it
12465 let caps = lsp::WorkspaceFoldersServerCapabilities {
12466 supported: Some(true),
12467 change_notifications: Some(OneOf::Right(reg.id)),
12468 };
12469 server.update_capabilities(|capabilities| {
12470 capabilities
12471 .workspace
12472 .get_or_insert_default()
12473 .workspace_folders = Some(caps);
12474 });
12475 notify_server_capabilities_updated(&server, cx);
12476 }
12477 "workspace/symbol" => {
12478 let options = parse_register_capabilities(reg)?;
12479 server.update_capabilities(|capabilities| {
12480 capabilities.workspace_symbol_provider = Some(options);
12481 });
12482 notify_server_capabilities_updated(&server, cx);
12483 }
12484 "workspace/fileOperations" => {
12485 if let Some(options) = reg.register_options {
12486 let caps = serde_json::from_value(options)?;
12487 server.update_capabilities(|capabilities| {
12488 capabilities
12489 .workspace
12490 .get_or_insert_default()
12491 .file_operations = Some(caps);
12492 });
12493 notify_server_capabilities_updated(&server, cx);
12494 }
12495 }
12496 "workspace/executeCommand" => {
12497 if let Some(options) = reg.register_options {
12498 let options = serde_json::from_value(options)?;
12499 server.update_capabilities(|capabilities| {
12500 capabilities.execute_command_provider = Some(options);
12501 });
12502 notify_server_capabilities_updated(&server, cx);
12503 }
12504 }
12505 "textDocument/rangeFormatting" => {
12506 let options = parse_register_capabilities(reg)?;
12507 server.update_capabilities(|capabilities| {
12508 capabilities.document_range_formatting_provider = Some(options);
12509 });
12510 notify_server_capabilities_updated(&server, cx);
12511 }
12512 "textDocument/onTypeFormatting" => {
12513 if let Some(options) = reg
12514 .register_options
12515 .map(serde_json::from_value)
12516 .transpose()?
12517 {
12518 server.update_capabilities(|capabilities| {
12519 capabilities.document_on_type_formatting_provider = Some(options);
12520 });
12521 notify_server_capabilities_updated(&server, cx);
12522 }
12523 }
12524 "textDocument/formatting" => {
12525 let options = parse_register_capabilities(reg)?;
12526 server.update_capabilities(|capabilities| {
12527 capabilities.document_formatting_provider = Some(options);
12528 });
12529 notify_server_capabilities_updated(&server, cx);
12530 }
12531 "textDocument/rename" => {
12532 let options = parse_register_capabilities(reg)?;
12533 server.update_capabilities(|capabilities| {
12534 capabilities.rename_provider = Some(options);
12535 });
12536 notify_server_capabilities_updated(&server, cx);
12537 }
12538 "textDocument/inlayHint" => {
12539 let options = parse_register_capabilities(reg)?;
12540 server.update_capabilities(|capabilities| {
12541 capabilities.inlay_hint_provider = Some(options);
12542 });
12543 notify_server_capabilities_updated(&server, cx);
12544 }
12545 "textDocument/documentSymbol" => {
12546 let options = parse_register_capabilities(reg)?;
12547 server.update_capabilities(|capabilities| {
12548 capabilities.document_symbol_provider = Some(options);
12549 });
12550 notify_server_capabilities_updated(&server, cx);
12551 }
12552 "textDocument/codeAction" => {
12553 let options = parse_register_capabilities(reg)?;
12554 let provider = match options {
12555 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12556 OneOf::Right(caps) => caps,
12557 };
12558 server.update_capabilities(|capabilities| {
12559 capabilities.code_action_provider = Some(provider);
12560 });
12561 notify_server_capabilities_updated(&server, cx);
12562 }
12563 "textDocument/definition" => {
12564 let options = parse_register_capabilities(reg)?;
12565 server.update_capabilities(|capabilities| {
12566 capabilities.definition_provider = Some(options);
12567 });
12568 notify_server_capabilities_updated(&server, cx);
12569 }
12570 "textDocument/completion" => {
12571 if let Some(caps) = reg
12572 .register_options
12573 .map(serde_json::from_value::<CompletionOptions>)
12574 .transpose()?
12575 {
12576 server.update_capabilities(|capabilities| {
12577 capabilities.completion_provider = Some(caps.clone());
12578 });
12579
12580 if let Some(local) = self.as_local() {
12581 let mut buffers_with_language_server = Vec::new();
12582 for handle in self.buffer_store.read(cx).buffers() {
12583 let buffer_id = handle.read(cx).remote_id();
12584 if local
12585 .buffers_opened_in_servers
12586 .get(&buffer_id)
12587 .filter(|s| s.contains(&server_id))
12588 .is_some()
12589 {
12590 buffers_with_language_server.push(handle);
12591 }
12592 }
12593 let triggers = caps
12594 .trigger_characters
12595 .unwrap_or_default()
12596 .into_iter()
12597 .collect::<BTreeSet<_>>();
12598 for handle in buffers_with_language_server {
12599 let triggers = triggers.clone();
12600 let _ = handle.update(cx, move |buffer, cx| {
12601 buffer.set_completion_triggers(server_id, triggers, cx);
12602 });
12603 }
12604 }
12605 notify_server_capabilities_updated(&server, cx);
12606 }
12607 }
12608 "textDocument/hover" => {
12609 let options = parse_register_capabilities(reg)?;
12610 let provider = match options {
12611 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12612 OneOf::Right(caps) => caps,
12613 };
12614 server.update_capabilities(|capabilities| {
12615 capabilities.hover_provider = Some(provider);
12616 });
12617 notify_server_capabilities_updated(&server, cx);
12618 }
12619 "textDocument/signatureHelp" => {
12620 if let Some(caps) = reg
12621 .register_options
12622 .map(serde_json::from_value)
12623 .transpose()?
12624 {
12625 server.update_capabilities(|capabilities| {
12626 capabilities.signature_help_provider = Some(caps);
12627 });
12628 notify_server_capabilities_updated(&server, cx);
12629 }
12630 }
12631 "textDocument/didChange" => {
12632 if let Some(sync_kind) = reg
12633 .register_options
12634 .and_then(|opts| opts.get("syncKind").cloned())
12635 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12636 .transpose()?
12637 {
12638 server.update_capabilities(|capabilities| {
12639 let mut sync_options =
12640 Self::take_text_document_sync_options(capabilities);
12641 sync_options.change = Some(sync_kind);
12642 capabilities.text_document_sync =
12643 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12644 });
12645 notify_server_capabilities_updated(&server, cx);
12646 }
12647 }
12648 "textDocument/didSave" => {
12649 if let Some(include_text) = reg
12650 .register_options
12651 .map(|opts| {
12652 let transpose = opts
12653 .get("includeText")
12654 .cloned()
12655 .map(serde_json::from_value::<Option<bool>>)
12656 .transpose();
12657 match transpose {
12658 Ok(value) => Ok(value.flatten()),
12659 Err(e) => Err(e),
12660 }
12661 })
12662 .transpose()?
12663 {
12664 server.update_capabilities(|capabilities| {
12665 let mut sync_options =
12666 Self::take_text_document_sync_options(capabilities);
12667 sync_options.save =
12668 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12669 include_text,
12670 }));
12671 capabilities.text_document_sync =
12672 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12673 });
12674 notify_server_capabilities_updated(&server, cx);
12675 }
12676 }
12677 "textDocument/codeLens" => {
12678 if let Some(caps) = reg
12679 .register_options
12680 .map(serde_json::from_value)
12681 .transpose()?
12682 {
12683 server.update_capabilities(|capabilities| {
12684 capabilities.code_lens_provider = Some(caps);
12685 });
12686 notify_server_capabilities_updated(&server, cx);
12687 }
12688 }
12689 "textDocument/diagnostic" => {
12690 if let Some(caps) = reg
12691 .register_options
12692 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12693 .transpose()?
12694 {
12695 let local = self
12696 .as_local_mut()
12697 .context("Expected LSP Store to be local")?;
12698 let state = local
12699 .language_servers
12700 .get_mut(&server_id)
12701 .context("Could not obtain Language Servers state")?;
12702 local
12703 .language_server_dynamic_registrations
12704 .entry(server_id)
12705 .or_default()
12706 .diagnostics
12707 .insert(Some(reg.id.clone()), caps.clone());
12708
12709 let supports_workspace_diagnostics =
12710 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12711 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12712 diagnostic_options.workspace_diagnostics
12713 }
12714 DiagnosticServerCapabilities::RegistrationOptions(
12715 diagnostic_registration_options,
12716 ) => {
12717 diagnostic_registration_options
12718 .diagnostic_options
12719 .workspace_diagnostics
12720 }
12721 };
12722
12723 if supports_workspace_diagnostics(&caps) {
12724 if let LanguageServerState::Running {
12725 workspace_diagnostics_refresh_tasks,
12726 ..
12727 } = state
12728 && let Some(task) = lsp_workspace_diagnostics_refresh(
12729 Some(reg.id.clone()),
12730 caps.clone(),
12731 server.clone(),
12732 cx,
12733 )
12734 {
12735 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12736 }
12737 }
12738
12739 server.update_capabilities(|capabilities| {
12740 capabilities.diagnostic_provider = Some(caps);
12741 });
12742
12743 notify_server_capabilities_updated(&server, cx);
12744
12745 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12746 }
12747 }
12748 "textDocument/documentColor" => {
12749 let options = parse_register_capabilities(reg)?;
12750 let provider = match options {
12751 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12752 OneOf::Right(caps) => caps,
12753 };
12754 server.update_capabilities(|capabilities| {
12755 capabilities.color_provider = Some(provider);
12756 });
12757 notify_server_capabilities_updated(&server, cx);
12758 }
12759 "textDocument/foldingRange" => {
12760 let options = parse_register_capabilities(reg)?;
12761 let provider = match options {
12762 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12763 OneOf::Right(caps) => caps,
12764 };
12765 server.update_capabilities(|capabilities| {
12766 capabilities.folding_range_provider = Some(provider);
12767 });
12768 notify_server_capabilities_updated(&server, cx);
12769 }
12770 _ => log::warn!("unhandled capability registration: {reg:?}"),
12771 }
12772 }
12773
12774 Ok(())
12775 }
12776
12777 fn unregister_server_capabilities(
12778 &mut self,
12779 server_id: LanguageServerId,
12780 params: lsp::UnregistrationParams,
12781 cx: &mut Context<Self>,
12782 ) -> anyhow::Result<()> {
12783 let server = self
12784 .language_server_for_id(server_id)
12785 .with_context(|| format!("no server {server_id} found"))?;
12786 for unreg in params.unregisterations.iter() {
12787 match unreg.method.as_str() {
12788 "workspace/didChangeWatchedFiles" => {
12789 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12790 local_lsp_store
12791 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12792 true
12793 } else {
12794 false
12795 };
12796 if notify {
12797 notify_server_capabilities_updated(&server, cx);
12798 }
12799 }
12800 "workspace/didChangeConfiguration" => {
12801 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12802 }
12803 "workspace/didChangeWorkspaceFolders" => {
12804 server.update_capabilities(|capabilities| {
12805 capabilities
12806 .workspace
12807 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12808 workspace_folders: None,
12809 file_operations: None,
12810 })
12811 .workspace_folders = None;
12812 });
12813 notify_server_capabilities_updated(&server, cx);
12814 }
12815 "workspace/symbol" => {
12816 server.update_capabilities(|capabilities| {
12817 capabilities.workspace_symbol_provider = None
12818 });
12819 notify_server_capabilities_updated(&server, cx);
12820 }
12821 "workspace/fileOperations" => {
12822 server.update_capabilities(|capabilities| {
12823 capabilities
12824 .workspace
12825 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12826 workspace_folders: None,
12827 file_operations: None,
12828 })
12829 .file_operations = None;
12830 });
12831 notify_server_capabilities_updated(&server, cx);
12832 }
12833 "workspace/executeCommand" => {
12834 server.update_capabilities(|capabilities| {
12835 capabilities.execute_command_provider = None;
12836 });
12837 notify_server_capabilities_updated(&server, cx);
12838 }
12839 "textDocument/rangeFormatting" => {
12840 server.update_capabilities(|capabilities| {
12841 capabilities.document_range_formatting_provider = None
12842 });
12843 notify_server_capabilities_updated(&server, cx);
12844 }
12845 "textDocument/onTypeFormatting" => {
12846 server.update_capabilities(|capabilities| {
12847 capabilities.document_on_type_formatting_provider = None;
12848 });
12849 notify_server_capabilities_updated(&server, cx);
12850 }
12851 "textDocument/formatting" => {
12852 server.update_capabilities(|capabilities| {
12853 capabilities.document_formatting_provider = None;
12854 });
12855 notify_server_capabilities_updated(&server, cx);
12856 }
12857 "textDocument/rename" => {
12858 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12859 notify_server_capabilities_updated(&server, cx);
12860 }
12861 "textDocument/codeAction" => {
12862 server.update_capabilities(|capabilities| {
12863 capabilities.code_action_provider = None;
12864 });
12865 notify_server_capabilities_updated(&server, cx);
12866 }
12867 "textDocument/definition" => {
12868 server.update_capabilities(|capabilities| {
12869 capabilities.definition_provider = None;
12870 });
12871 notify_server_capabilities_updated(&server, cx);
12872 }
12873 "textDocument/completion" => {
12874 server.update_capabilities(|capabilities| {
12875 capabilities.completion_provider = None;
12876 });
12877 notify_server_capabilities_updated(&server, cx);
12878 }
12879 "textDocument/hover" => {
12880 server.update_capabilities(|capabilities| {
12881 capabilities.hover_provider = None;
12882 });
12883 notify_server_capabilities_updated(&server, cx);
12884 }
12885 "textDocument/signatureHelp" => {
12886 server.update_capabilities(|capabilities| {
12887 capabilities.signature_help_provider = None;
12888 });
12889 notify_server_capabilities_updated(&server, cx);
12890 }
12891 "textDocument/didChange" => {
12892 server.update_capabilities(|capabilities| {
12893 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12894 sync_options.change = None;
12895 capabilities.text_document_sync =
12896 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12897 });
12898 notify_server_capabilities_updated(&server, cx);
12899 }
12900 "textDocument/didSave" => {
12901 server.update_capabilities(|capabilities| {
12902 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12903 sync_options.save = None;
12904 capabilities.text_document_sync =
12905 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12906 });
12907 notify_server_capabilities_updated(&server, cx);
12908 }
12909 "textDocument/codeLens" => {
12910 server.update_capabilities(|capabilities| {
12911 capabilities.code_lens_provider = None;
12912 });
12913 notify_server_capabilities_updated(&server, cx);
12914 }
12915 "textDocument/diagnostic" => {
12916 let local = self
12917 .as_local_mut()
12918 .context("Expected LSP Store to be local")?;
12919
12920 let state = local
12921 .language_servers
12922 .get_mut(&server_id)
12923 .context("Could not obtain Language Servers state")?;
12924 let registrations = local
12925 .language_server_dynamic_registrations
12926 .get_mut(&server_id)
12927 .with_context(|| {
12928 format!("Expected dynamic registration to exist for server {server_id}")
12929 })?;
12930 registrations.diagnostics
12931 .remove(&Some(unreg.id.clone()))
12932 .with_context(|| format!(
12933 "Attempted to unregister non-existent diagnostic registration with ID {}",
12934 unreg.id)
12935 )?;
12936 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12937
12938 if let LanguageServerState::Running {
12939 workspace_diagnostics_refresh_tasks,
12940 ..
12941 } = state
12942 {
12943 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12944 }
12945
12946 self.clear_unregistered_diagnostics(
12947 server_id,
12948 SharedString::from(unreg.id.clone()),
12949 cx,
12950 )?;
12951
12952 if removed_last_diagnostic_provider {
12953 server.update_capabilities(|capabilities| {
12954 debug_assert!(capabilities.diagnostic_provider.is_some());
12955 capabilities.diagnostic_provider = None;
12956 });
12957 }
12958
12959 notify_server_capabilities_updated(&server, cx);
12960 }
12961 "textDocument/documentColor" => {
12962 server.update_capabilities(|capabilities| {
12963 capabilities.color_provider = None;
12964 });
12965 notify_server_capabilities_updated(&server, cx);
12966 }
12967 "textDocument/foldingRange" => {
12968 server.update_capabilities(|capabilities| {
12969 capabilities.folding_range_provider = None;
12970 });
12971 notify_server_capabilities_updated(&server, cx);
12972 }
12973 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12974 }
12975 }
12976
12977 Ok(())
12978 }
12979
12980 fn clear_unregistered_diagnostics(
12981 &mut self,
12982 server_id: LanguageServerId,
12983 cleared_registration_id: SharedString,
12984 cx: &mut Context<Self>,
12985 ) -> anyhow::Result<()> {
12986 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12987
12988 self.buffer_store.update(cx, |buffer_store, cx| {
12989 for buffer_handle in buffer_store.buffers() {
12990 let buffer = buffer_handle.read(cx);
12991 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12992 let Some(abs_path) = abs_path else {
12993 continue;
12994 };
12995 affected_abs_paths.insert(abs_path);
12996 }
12997 });
12998
12999 let local = self.as_local().context("Expected LSP Store to be local")?;
13000 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13001 let Some(worktree) = self
13002 .worktree_store
13003 .read(cx)
13004 .worktree_for_id(*worktree_id, cx)
13005 else {
13006 continue;
13007 };
13008
13009 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13010 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13011 let has_matching_registration =
13012 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13013 entry.diagnostic.registration_id.as_ref()
13014 == Some(&cleared_registration_id)
13015 });
13016 if has_matching_registration {
13017 let abs_path = worktree.read(cx).absolutize(rel_path);
13018 affected_abs_paths.insert(abs_path);
13019 }
13020 }
13021 }
13022 }
13023
13024 if affected_abs_paths.is_empty() {
13025 return Ok(());
13026 }
13027
13028 // Send a fake diagnostic update which clears the state for the registration ID
13029 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13030 affected_abs_paths
13031 .into_iter()
13032 .map(|abs_path| DocumentDiagnosticsUpdate {
13033 diagnostics: DocumentDiagnostics {
13034 diagnostics: Vec::new(),
13035 document_abs_path: abs_path,
13036 version: None,
13037 },
13038 result_id: None,
13039 registration_id: Some(cleared_registration_id.clone()),
13040 server_id,
13041 disk_based_sources: Cow::Borrowed(&[]),
13042 })
13043 .collect();
13044
13045 let merge_registration_id = cleared_registration_id.clone();
13046 self.merge_diagnostic_entries(
13047 clears,
13048 move |_, diagnostic, _| {
13049 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13050 diagnostic.registration_id != Some(merge_registration_id.clone())
13051 } else {
13052 true
13053 }
13054 },
13055 cx,
13056 )?;
13057
13058 Ok(())
13059 }
13060
13061 async fn deduplicate_range_based_lsp_requests<T>(
13062 lsp_store: &Entity<Self>,
13063 server_id: Option<LanguageServerId>,
13064 lsp_request_id: LspRequestId,
13065 proto_request: &T::ProtoRequest,
13066 range: Range<Anchor>,
13067 cx: &mut AsyncApp,
13068 ) -> Result<()>
13069 where
13070 T: LspCommand,
13071 T::ProtoRequest: proto::LspRequestMessage,
13072 {
13073 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13074 let version = deserialize_version(proto_request.buffer_version());
13075 let buffer = lsp_store.update(cx, |this, cx| {
13076 this.buffer_store.read(cx).get_existing(buffer_id)
13077 })?;
13078 buffer
13079 .update(cx, |buffer, _| buffer.wait_for_version(version))
13080 .await?;
13081 lsp_store.update(cx, |lsp_store, cx| {
13082 let buffer_snapshot = buffer.read(cx).snapshot();
13083 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13084 let chunks_queried_for = lsp_data
13085 .inlay_hints
13086 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13087 .collect::<Vec<_>>();
13088 match chunks_queried_for.as_slice() {
13089 &[chunk] => {
13090 let key = LspKey {
13091 request_type: TypeId::of::<T>(),
13092 server_queried: server_id,
13093 };
13094 let previous_request = lsp_data
13095 .chunk_lsp_requests
13096 .entry(key)
13097 .or_default()
13098 .insert(chunk, lsp_request_id);
13099 if let Some((previous_request, running_requests)) =
13100 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13101 {
13102 running_requests.remove(&previous_request);
13103 }
13104 }
13105 _ambiguous_chunks => {
13106 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13107 // there, a buffer version-based check will be performed and outdated requests discarded.
13108 }
13109 }
13110 anyhow::Ok(())
13111 })?;
13112
13113 Ok(())
13114 }
13115
13116 async fn query_lsp_locally<T>(
13117 lsp_store: Entity<Self>,
13118 for_server_id: Option<LanguageServerId>,
13119 sender_id: proto::PeerId,
13120 lsp_request_id: LspRequestId,
13121 proto_request: T::ProtoRequest,
13122 position: Option<Anchor>,
13123 cx: &mut AsyncApp,
13124 ) -> Result<()>
13125 where
13126 T: LspCommand + Clone,
13127 T::ProtoRequest: proto::LspRequestMessage,
13128 <T::ProtoRequest as proto::RequestMessage>::Response:
13129 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13130 {
13131 let (buffer_version, buffer) =
13132 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13133 let request =
13134 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13135 let key = LspKey {
13136 request_type: TypeId::of::<T>(),
13137 server_queried: for_server_id,
13138 };
13139 lsp_store.update(cx, |lsp_store, cx| {
13140 let request_task = match for_server_id {
13141 Some(server_id) => {
13142 let server_task = lsp_store.request_lsp(
13143 buffer.clone(),
13144 LanguageServerToQuery::Other(server_id),
13145 request.clone(),
13146 cx,
13147 );
13148 cx.background_spawn(async move {
13149 let mut responses = Vec::new();
13150 match server_task.await {
13151 Ok(response) => responses.push((server_id, response)),
13152 // rust-analyzer likes to error with this when its still loading up
13153 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13154 Err(e) => log::error!(
13155 "Error handling response for request {request:?}: {e:#}"
13156 ),
13157 }
13158 responses
13159 })
13160 }
13161 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13162 };
13163 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13164 if T::ProtoRequest::stop_previous_requests() {
13165 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13166 lsp_requests.clear();
13167 }
13168 }
13169 lsp_data.lsp_requests.entry(key).or_default().insert(
13170 lsp_request_id,
13171 cx.spawn(async move |lsp_store, cx| {
13172 let response = request_task.await;
13173 lsp_store
13174 .update(cx, |lsp_store, cx| {
13175 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13176 {
13177 let response = response
13178 .into_iter()
13179 .map(|(server_id, response)| {
13180 (
13181 server_id.to_proto(),
13182 T::response_to_proto(
13183 response,
13184 lsp_store,
13185 sender_id,
13186 &buffer_version,
13187 cx,
13188 )
13189 .into(),
13190 )
13191 })
13192 .collect::<HashMap<_, _>>();
13193 match client.send_lsp_response::<T::ProtoRequest>(
13194 project_id,
13195 lsp_request_id,
13196 response,
13197 ) {
13198 Ok(()) => {}
13199 Err(e) => {
13200 log::error!("Failed to send LSP response: {e:#}",)
13201 }
13202 }
13203 }
13204 })
13205 .ok();
13206 }),
13207 );
13208 });
13209 Ok(())
13210 }
13211
13212 async fn wait_for_buffer_version<T>(
13213 lsp_store: &Entity<Self>,
13214 proto_request: &T::ProtoRequest,
13215 cx: &mut AsyncApp,
13216 ) -> Result<(Global, Entity<Buffer>)>
13217 where
13218 T: LspCommand,
13219 T::ProtoRequest: proto::LspRequestMessage,
13220 {
13221 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13222 let version = deserialize_version(proto_request.buffer_version());
13223 let buffer = lsp_store.update(cx, |this, cx| {
13224 this.buffer_store.read(cx).get_existing(buffer_id)
13225 })?;
13226 buffer
13227 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13228 .await?;
13229 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13230 Ok((buffer_version, buffer))
13231 }
13232
13233 fn take_text_document_sync_options(
13234 capabilities: &mut lsp::ServerCapabilities,
13235 ) -> lsp::TextDocumentSyncOptions {
13236 match capabilities.text_document_sync.take() {
13237 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13238 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13239 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13240 sync_options.change = Some(sync_kind);
13241 sync_options
13242 }
13243 None => lsp::TextDocumentSyncOptions::default(),
13244 }
13245 }
13246
13247 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13248 self.downstream_client.clone()
13249 }
13250
13251 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13252 self.worktree_store.clone()
13253 }
13254
13255 /// Gets what's stored in the LSP data for the given buffer.
13256 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13257 self.lsp_data.get_mut(&buffer_id)
13258 }
13259
13260 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13261 /// new [`BufferLspData`] will be created to replace the previous state.
13262 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13263 let (buffer_id, buffer_version) =
13264 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13265 let lsp_data = self
13266 .lsp_data
13267 .entry(buffer_id)
13268 .or_insert_with(|| BufferLspData::new(buffer, cx));
13269 if buffer_version.changed_since(&lsp_data.buffer_version) {
13270 // To send delta requests for semantic tokens, the previous tokens
13271 // need to be kept between buffer changes.
13272 let semantic_tokens = lsp_data.semantic_tokens.take();
13273 *lsp_data = BufferLspData::new(buffer, cx);
13274 lsp_data.semantic_tokens = semantic_tokens;
13275 }
13276 lsp_data
13277 }
13278}
13279
13280// Registration with registerOptions as null, should fallback to true.
13281// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13282fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13283 reg: lsp::Registration,
13284) -> Result<OneOf<bool, T>> {
13285 Ok(match reg.register_options {
13286 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13287 None => OneOf::Left(true),
13288 })
13289}
13290
13291fn subscribe_to_binary_statuses(
13292 languages: &Arc<LanguageRegistry>,
13293 cx: &mut Context<'_, LspStore>,
13294) -> Task<()> {
13295 let mut server_statuses = languages.language_server_binary_statuses();
13296 cx.spawn(async move |lsp_store, cx| {
13297 while let Some((server_name, binary_status)) = server_statuses.next().await {
13298 if lsp_store
13299 .update(cx, |_, cx| {
13300 let mut message = None;
13301 let binary_status = match binary_status {
13302 BinaryStatus::None => proto::ServerBinaryStatus::None,
13303 BinaryStatus::CheckingForUpdate => {
13304 proto::ServerBinaryStatus::CheckingForUpdate
13305 }
13306 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13307 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13308 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13309 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13310 BinaryStatus::Failed { error } => {
13311 message = Some(error);
13312 proto::ServerBinaryStatus::Failed
13313 }
13314 };
13315 cx.emit(LspStoreEvent::LanguageServerUpdate {
13316 // Binary updates are about the binary that might not have any language server id at that point.
13317 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13318 language_server_id: LanguageServerId(0),
13319 name: Some(server_name),
13320 message: proto::update_language_server::Variant::StatusUpdate(
13321 proto::StatusUpdate {
13322 message,
13323 status: Some(proto::status_update::Status::Binary(
13324 binary_status as i32,
13325 )),
13326 },
13327 ),
13328 });
13329 })
13330 .is_err()
13331 {
13332 break;
13333 }
13334 }
13335 })
13336}
13337
13338fn lsp_workspace_diagnostics_refresh(
13339 registration_id: Option<String>,
13340 options: DiagnosticServerCapabilities,
13341 server: Arc<LanguageServer>,
13342 cx: &mut Context<'_, LspStore>,
13343) -> Option<WorkspaceRefreshTask> {
13344 let identifier = workspace_diagnostic_identifier(&options)?;
13345 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13346
13347 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13348 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13349 refresh_tx.try_send(()).ok();
13350
13351 let request_timeout = ProjectSettings::get_global(cx)
13352 .global_lsp_settings
13353 .get_request_timeout();
13354
13355 // Clamp timeout duration at a minimum of [`DEFAULT_LSP_REQUEST_TIMEOUT`] to mitigate useless loops from re-trying connections with smaller timeouts from project settings.
13356 // This allows users to increase the duration if need be
13357 let timeout = if request_timeout != Duration::ZERO {
13358 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13359 } else {
13360 request_timeout
13361 };
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 = server.request_timer(timeout).fuse();
13414 let progress = pin!(progress_rx.recv().fuse());
13415 let response_result = server
13416 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13417 lsp::WorkspaceDiagnosticParams {
13418 previous_result_ids,
13419 identifier: identifier.clone(),
13420 work_done_progress_params: Default::default(),
13421 partial_result_params: lsp::PartialResultParams {
13422 partial_result_token: Some(lsp::ProgressToken::String(token)),
13423 },
13424 },
13425 select(timer, progress).then(|either| match either {
13426 Either::Left((message, ..)) => ready(message).left_future(),
13427 Either::Right(..) => pending::<String>().right_future(),
13428 }),
13429 )
13430 .await;
13431
13432 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13433 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13434 match response_result {
13435 ConnectionResult::Timeout => {
13436 log::error!("Timeout during workspace diagnostics pull");
13437 continue 'request;
13438 }
13439 ConnectionResult::ConnectionReset => {
13440 log::error!("Server closed a workspace diagnostics pull request");
13441 continue 'request;
13442 }
13443 ConnectionResult::Result(Err(e)) => {
13444 log::error!("Error during workspace diagnostics pull: {e:#}");
13445 break 'request;
13446 }
13447 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13448 attempts = 0;
13449 if lsp_store
13450 .update(cx, |lsp_store, cx| {
13451 lsp_store.apply_workspace_diagnostic_report(
13452 server.server_id(),
13453 pulled_diagnostics,
13454 registration_id_shared.clone(),
13455 cx,
13456 )
13457 })
13458 .is_err()
13459 {
13460 return;
13461 }
13462 break 'request;
13463 }
13464 }
13465 }
13466 }
13467 });
13468
13469 Some(WorkspaceRefreshTask {
13470 refresh_tx,
13471 progress_tx,
13472 task: workspace_query_language_server,
13473 })
13474}
13475
13476fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13477 match &options {
13478 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13479 .identifier
13480 .as_deref()
13481 .map(SharedString::new),
13482 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13483 let diagnostic_options = ®istration_options.diagnostic_options;
13484 diagnostic_options
13485 .identifier
13486 .as_deref()
13487 .map(SharedString::new)
13488 }
13489 }
13490}
13491
13492fn workspace_diagnostic_identifier(
13493 options: &DiagnosticServerCapabilities,
13494) -> Option<Option<String>> {
13495 match &options {
13496 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13497 if !diagnostic_options.workspace_diagnostics {
13498 return None;
13499 }
13500 Some(diagnostic_options.identifier.clone())
13501 }
13502 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13503 let diagnostic_options = ®istration_options.diagnostic_options;
13504 if !diagnostic_options.workspace_diagnostics {
13505 return None;
13506 }
13507 Some(diagnostic_options.identifier.clone())
13508 }
13509 }
13510}
13511
13512fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13513 let CompletionSource::BufferWord {
13514 word_range,
13515 resolved,
13516 } = &mut completion.source
13517 else {
13518 return;
13519 };
13520 if *resolved {
13521 return;
13522 }
13523
13524 if completion.new_text
13525 != snapshot
13526 .text_for_range(word_range.clone())
13527 .collect::<String>()
13528 {
13529 return;
13530 }
13531
13532 let mut offset = 0;
13533 for chunk in snapshot.chunks(word_range.clone(), true) {
13534 let end_offset = offset + chunk.text.len();
13535 if let Some(highlight_id) = chunk.syntax_highlight_id {
13536 completion
13537 .label
13538 .runs
13539 .push((offset..end_offset, highlight_id));
13540 }
13541 offset = end_offset;
13542 }
13543 *resolved = true;
13544}
13545
13546impl EventEmitter<LspStoreEvent> for LspStore {}
13547
13548fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13549 hover
13550 .contents
13551 .retain(|hover_block| !hover_block.text.trim().is_empty());
13552 if hover.contents.is_empty() {
13553 None
13554 } else {
13555 Some(hover)
13556 }
13557}
13558
13559async fn populate_labels_for_completions(
13560 new_completions: Vec<CoreCompletion>,
13561 language: Option<Arc<Language>>,
13562 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13563) -> Vec<Completion> {
13564 let lsp_completions = new_completions
13565 .iter()
13566 .filter_map(|new_completion| {
13567 new_completion
13568 .source
13569 .lsp_completion(true)
13570 .map(|lsp_completion| lsp_completion.into_owned())
13571 })
13572 .collect::<Vec<_>>();
13573
13574 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13575 lsp_adapter
13576 .labels_for_completions(&lsp_completions, language)
13577 .await
13578 .log_err()
13579 .unwrap_or_default()
13580 } else {
13581 Vec::new()
13582 }
13583 .into_iter()
13584 .fuse();
13585
13586 let mut completions = Vec::new();
13587 for completion in new_completions {
13588 match completion.source.lsp_completion(true) {
13589 Some(lsp_completion) => {
13590 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13591
13592 let mut label = labels.next().flatten().unwrap_or_else(|| {
13593 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13594 });
13595 ensure_uniform_list_compatible_label(&mut label);
13596 completions.push(Completion {
13597 label,
13598 documentation,
13599 replace_range: completion.replace_range,
13600 new_text: completion.new_text,
13601 insert_text_mode: lsp_completion.insert_text_mode,
13602 source: completion.source,
13603 icon_path: None,
13604 confirm: None,
13605 match_start: None,
13606 snippet_deduplication_key: None,
13607 });
13608 }
13609 None => {
13610 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13611 ensure_uniform_list_compatible_label(&mut label);
13612 completions.push(Completion {
13613 label,
13614 documentation: None,
13615 replace_range: completion.replace_range,
13616 new_text: completion.new_text,
13617 source: completion.source,
13618 insert_text_mode: None,
13619 icon_path: None,
13620 confirm: None,
13621 match_start: None,
13622 snippet_deduplication_key: None,
13623 });
13624 }
13625 }
13626 }
13627 completions
13628}
13629
13630#[derive(Debug)]
13631pub enum LanguageServerToQuery {
13632 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13633 FirstCapable,
13634 /// Query a specific language server.
13635 Other(LanguageServerId),
13636}
13637
13638#[derive(Default)]
13639struct RenamePathsWatchedForServer {
13640 did_rename: Vec<RenameActionPredicate>,
13641 will_rename: Vec<RenameActionPredicate>,
13642}
13643
13644impl RenamePathsWatchedForServer {
13645 fn with_did_rename_patterns(
13646 mut self,
13647 did_rename: Option<&FileOperationRegistrationOptions>,
13648 ) -> Self {
13649 if let Some(did_rename) = did_rename {
13650 self.did_rename = did_rename
13651 .filters
13652 .iter()
13653 .filter_map(|filter| filter.try_into().log_err())
13654 .collect();
13655 }
13656 self
13657 }
13658 fn with_will_rename_patterns(
13659 mut self,
13660 will_rename: Option<&FileOperationRegistrationOptions>,
13661 ) -> Self {
13662 if let Some(will_rename) = will_rename {
13663 self.will_rename = will_rename
13664 .filters
13665 .iter()
13666 .filter_map(|filter| filter.try_into().log_err())
13667 .collect();
13668 }
13669 self
13670 }
13671
13672 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13673 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13674 }
13675 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13676 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13677 }
13678}
13679
13680impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13681 type Error = globset::Error;
13682 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13683 Ok(Self {
13684 kind: ops.pattern.matches.clone(),
13685 glob: GlobBuilder::new(&ops.pattern.glob)
13686 .case_insensitive(
13687 ops.pattern
13688 .options
13689 .as_ref()
13690 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13691 )
13692 .build()?
13693 .compile_matcher(),
13694 })
13695 }
13696}
13697struct RenameActionPredicate {
13698 glob: GlobMatcher,
13699 kind: Option<FileOperationPatternKind>,
13700}
13701
13702impl RenameActionPredicate {
13703 // Returns true if language server should be notified
13704 fn eval(&self, path: &str, is_dir: bool) -> bool {
13705 self.kind.as_ref().is_none_or(|kind| {
13706 let expected_kind = if is_dir {
13707 FileOperationPatternKind::Folder
13708 } else {
13709 FileOperationPatternKind::File
13710 };
13711 kind == &expected_kind
13712 }) && self.glob.is_match(path)
13713 }
13714}
13715
13716#[derive(Default)]
13717struct LanguageServerWatchedPaths {
13718 worktree_paths: HashMap<WorktreeId, GlobSet>,
13719 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13720}
13721
13722#[derive(Default)]
13723struct LanguageServerWatchedPathsBuilder {
13724 worktree_paths: HashMap<WorktreeId, GlobSet>,
13725 abs_paths: HashMap<Arc<Path>, GlobSet>,
13726}
13727
13728impl LanguageServerWatchedPathsBuilder {
13729 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13730 self.worktree_paths.insert(worktree_id, glob_set);
13731 }
13732 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13733 self.abs_paths.insert(path, glob_set);
13734 }
13735 fn build(
13736 self,
13737 fs: Arc<dyn Fs>,
13738 language_server_id: LanguageServerId,
13739 cx: &mut Context<LspStore>,
13740 ) -> LanguageServerWatchedPaths {
13741 let lsp_store = cx.weak_entity();
13742
13743 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13744 let abs_paths = self
13745 .abs_paths
13746 .into_iter()
13747 .map(|(abs_path, globset)| {
13748 let task = cx.spawn({
13749 let abs_path = abs_path.clone();
13750 let fs = fs.clone();
13751
13752 let lsp_store = lsp_store.clone();
13753 async move |_, cx| {
13754 maybe!(async move {
13755 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13756 while let Some(update) = push_updates.0.next().await {
13757 let action = lsp_store
13758 .update(cx, |this, _| {
13759 let Some(local) = this.as_local() else {
13760 return ControlFlow::Break(());
13761 };
13762 let Some(watcher) = local
13763 .language_server_watched_paths
13764 .get(&language_server_id)
13765 else {
13766 return ControlFlow::Break(());
13767 };
13768 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13769 "Watched abs path is not registered with a watcher",
13770 );
13771 let matching_entries = update
13772 .into_iter()
13773 .filter(|event| globs.is_match(&event.path))
13774 .collect::<Vec<_>>();
13775 this.lsp_notify_abs_paths_changed(
13776 language_server_id,
13777 matching_entries,
13778 );
13779 ControlFlow::Continue(())
13780 })
13781 .ok()?;
13782
13783 if action.is_break() {
13784 break;
13785 }
13786 }
13787 Some(())
13788 })
13789 .await;
13790 }
13791 });
13792 (abs_path, (globset, task))
13793 })
13794 .collect();
13795 LanguageServerWatchedPaths {
13796 worktree_paths: self.worktree_paths,
13797 abs_paths,
13798 }
13799 }
13800}
13801
13802struct LspBufferSnapshot {
13803 version: i32,
13804 snapshot: TextBufferSnapshot,
13805}
13806
13807/// A prompt requested by LSP server.
13808#[derive(Clone, Debug)]
13809pub struct LanguageServerPromptRequest {
13810 pub id: usize,
13811 pub level: PromptLevel,
13812 pub message: String,
13813 pub actions: Vec<MessageActionItem>,
13814 pub lsp_name: String,
13815 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13816}
13817
13818impl LanguageServerPromptRequest {
13819 pub fn new(
13820 level: PromptLevel,
13821 message: String,
13822 actions: Vec<MessageActionItem>,
13823 lsp_name: String,
13824 response_channel: smol::channel::Sender<MessageActionItem>,
13825 ) -> Self {
13826 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13827 LanguageServerPromptRequest {
13828 id,
13829 level,
13830 message,
13831 actions,
13832 lsp_name,
13833 response_channel,
13834 }
13835 }
13836 pub async fn respond(self, index: usize) -> Option<()> {
13837 if let Some(response) = self.actions.into_iter().nth(index) {
13838 self.response_channel.send(response).await.ok()
13839 } else {
13840 None
13841 }
13842 }
13843
13844 #[cfg(any(test, feature = "test-support"))]
13845 pub fn test(
13846 level: PromptLevel,
13847 message: String,
13848 actions: Vec<MessageActionItem>,
13849 lsp_name: String,
13850 ) -> Self {
13851 let (tx, _rx) = smol::channel::unbounded();
13852 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13853 }
13854}
13855impl PartialEq for LanguageServerPromptRequest {
13856 fn eq(&self, other: &Self) -> bool {
13857 self.message == other.message && self.actions == other.actions
13858 }
13859}
13860
13861#[derive(Clone, Debug, PartialEq)]
13862pub enum LanguageServerLogType {
13863 Log(MessageType),
13864 Trace { verbose_info: Option<String> },
13865 Rpc { received: bool },
13866}
13867
13868impl LanguageServerLogType {
13869 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13870 match self {
13871 Self::Log(log_type) => {
13872 use proto::log_message::LogLevel;
13873 let level = match *log_type {
13874 MessageType::ERROR => LogLevel::Error,
13875 MessageType::WARNING => LogLevel::Warning,
13876 MessageType::INFO => LogLevel::Info,
13877 MessageType::LOG => LogLevel::Log,
13878 other => {
13879 log::warn!("Unknown lsp log message type: {other:?}");
13880 LogLevel::Log
13881 }
13882 };
13883 proto::language_server_log::LogType::Log(proto::LogMessage {
13884 level: level as i32,
13885 })
13886 }
13887 Self::Trace { verbose_info } => {
13888 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13889 verbose_info: verbose_info.to_owned(),
13890 })
13891 }
13892 Self::Rpc { received } => {
13893 let kind = if *received {
13894 proto::rpc_message::Kind::Received
13895 } else {
13896 proto::rpc_message::Kind::Sent
13897 };
13898 let kind = kind as i32;
13899 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13900 }
13901 }
13902 }
13903
13904 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13905 use proto::log_message::LogLevel;
13906 use proto::rpc_message;
13907 match log_type {
13908 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13909 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13910 LogLevel::Error => MessageType::ERROR,
13911 LogLevel::Warning => MessageType::WARNING,
13912 LogLevel::Info => MessageType::INFO,
13913 LogLevel::Log => MessageType::LOG,
13914 },
13915 ),
13916 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13917 verbose_info: trace_message.verbose_info,
13918 },
13919 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13920 received: match rpc_message::Kind::from_i32(message.kind)
13921 .unwrap_or(rpc_message::Kind::Received)
13922 {
13923 rpc_message::Kind::Received => true,
13924 rpc_message::Kind::Sent => false,
13925 },
13926 },
13927 }
13928 }
13929}
13930
13931pub struct WorkspaceRefreshTask {
13932 refresh_tx: mpsc::Sender<()>,
13933 progress_tx: mpsc::Sender<()>,
13934 #[allow(dead_code)]
13935 task: Task<()>,
13936}
13937
13938pub enum LanguageServerState {
13939 Starting {
13940 startup: Task<Option<Arc<LanguageServer>>>,
13941 /// List of language servers that will be added to the workspace once it's initialization completes.
13942 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13943 },
13944
13945 Running {
13946 adapter: Arc<CachedLspAdapter>,
13947 server: Arc<LanguageServer>,
13948 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13949 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13950 },
13951}
13952
13953impl LanguageServerState {
13954 fn add_workspace_folder(&self, uri: Uri) {
13955 match self {
13956 LanguageServerState::Starting {
13957 pending_workspace_folders,
13958 ..
13959 } => {
13960 pending_workspace_folders.lock().insert(uri);
13961 }
13962 LanguageServerState::Running { server, .. } => {
13963 server.add_workspace_folder(uri);
13964 }
13965 }
13966 }
13967 fn _remove_workspace_folder(&self, uri: Uri) {
13968 match self {
13969 LanguageServerState::Starting {
13970 pending_workspace_folders,
13971 ..
13972 } => {
13973 pending_workspace_folders.lock().remove(&uri);
13974 }
13975 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13976 }
13977 }
13978}
13979
13980impl std::fmt::Debug for LanguageServerState {
13981 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13982 match self {
13983 LanguageServerState::Starting { .. } => {
13984 f.debug_struct("LanguageServerState::Starting").finish()
13985 }
13986 LanguageServerState::Running { .. } => {
13987 f.debug_struct("LanguageServerState::Running").finish()
13988 }
13989 }
13990 }
13991}
13992
13993#[derive(Clone, Debug, Serialize)]
13994pub struct LanguageServerProgress {
13995 pub is_disk_based_diagnostics_progress: bool,
13996 pub is_cancellable: bool,
13997 pub title: Option<String>,
13998 pub message: Option<String>,
13999 pub percentage: Option<usize>,
14000 #[serde(skip_serializing)]
14001 pub last_update_at: Instant,
14002}
14003
14004#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14005pub struct DiagnosticSummary {
14006 pub error_count: usize,
14007 pub warning_count: usize,
14008}
14009
14010impl DiagnosticSummary {
14011 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14012 let mut this = Self {
14013 error_count: 0,
14014 warning_count: 0,
14015 };
14016
14017 for entry in diagnostics {
14018 if entry.diagnostic.is_primary {
14019 match entry.diagnostic.severity {
14020 DiagnosticSeverity::ERROR => this.error_count += 1,
14021 DiagnosticSeverity::WARNING => this.warning_count += 1,
14022 _ => {}
14023 }
14024 }
14025 }
14026
14027 this
14028 }
14029
14030 pub fn is_empty(&self) -> bool {
14031 self.error_count == 0 && self.warning_count == 0
14032 }
14033
14034 pub fn to_proto(
14035 self,
14036 language_server_id: LanguageServerId,
14037 path: &RelPath,
14038 ) -> proto::DiagnosticSummary {
14039 proto::DiagnosticSummary {
14040 path: path.to_proto(),
14041 language_server_id: language_server_id.0 as u64,
14042 error_count: self.error_count as u32,
14043 warning_count: self.warning_count as u32,
14044 }
14045 }
14046}
14047
14048#[derive(Clone, Debug)]
14049pub enum CompletionDocumentation {
14050 /// There is no documentation for this completion.
14051 Undocumented,
14052 /// A single line of documentation.
14053 SingleLine(SharedString),
14054 /// Multiple lines of plain text documentation.
14055 MultiLinePlainText(SharedString),
14056 /// Markdown documentation.
14057 MultiLineMarkdown(SharedString),
14058 /// Both single line and multiple lines of plain text documentation.
14059 SingleLineAndMultiLinePlainText {
14060 single_line: SharedString,
14061 plain_text: Option<SharedString>,
14062 },
14063}
14064
14065impl CompletionDocumentation {
14066 #[cfg(any(test, feature = "test-support"))]
14067 pub fn text(&self) -> SharedString {
14068 match self {
14069 CompletionDocumentation::Undocumented => "".into(),
14070 CompletionDocumentation::SingleLine(s) => s.clone(),
14071 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14072 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14073 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14074 single_line.clone()
14075 }
14076 }
14077 }
14078}
14079
14080impl From<lsp::Documentation> for CompletionDocumentation {
14081 fn from(docs: lsp::Documentation) -> Self {
14082 match docs {
14083 lsp::Documentation::String(text) => {
14084 if text.lines().count() <= 1 {
14085 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14086 } else {
14087 CompletionDocumentation::MultiLinePlainText(text.into())
14088 }
14089 }
14090
14091 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14092 lsp::MarkupKind::PlainText => {
14093 if value.lines().count() <= 1 {
14094 CompletionDocumentation::SingleLine(value.into())
14095 } else {
14096 CompletionDocumentation::MultiLinePlainText(value.into())
14097 }
14098 }
14099
14100 lsp::MarkupKind::Markdown => {
14101 CompletionDocumentation::MultiLineMarkdown(value.into())
14102 }
14103 },
14104 }
14105 }
14106}
14107
14108pub enum ResolvedHint {
14109 Resolved(InlayHint),
14110 Resolving(Shared<Task<()>>),
14111}
14112
14113pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14114 glob.components()
14115 .take_while(|component| match component {
14116 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14117 _ => true,
14118 })
14119 .collect()
14120}
14121
14122pub struct SshLspAdapter {
14123 name: LanguageServerName,
14124 binary: LanguageServerBinary,
14125 initialization_options: Option<String>,
14126 code_action_kinds: Option<Vec<CodeActionKind>>,
14127}
14128
14129impl SshLspAdapter {
14130 pub fn new(
14131 name: LanguageServerName,
14132 binary: LanguageServerBinary,
14133 initialization_options: Option<String>,
14134 code_action_kinds: Option<String>,
14135 ) -> Self {
14136 Self {
14137 name,
14138 binary,
14139 initialization_options,
14140 code_action_kinds: code_action_kinds
14141 .as_ref()
14142 .and_then(|c| serde_json::from_str(c).ok()),
14143 }
14144 }
14145}
14146
14147impl LspInstaller for SshLspAdapter {
14148 type BinaryVersion = ();
14149 async fn check_if_user_installed(
14150 &self,
14151 _: &dyn LspAdapterDelegate,
14152 _: Option<Toolchain>,
14153 _: &AsyncApp,
14154 ) -> Option<LanguageServerBinary> {
14155 Some(self.binary.clone())
14156 }
14157
14158 async fn cached_server_binary(
14159 &self,
14160 _: PathBuf,
14161 _: &dyn LspAdapterDelegate,
14162 ) -> Option<LanguageServerBinary> {
14163 None
14164 }
14165
14166 async fn fetch_latest_server_version(
14167 &self,
14168 _: &dyn LspAdapterDelegate,
14169 _: bool,
14170 _: &mut AsyncApp,
14171 ) -> Result<()> {
14172 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14173 }
14174
14175 async fn fetch_server_binary(
14176 &self,
14177 _: (),
14178 _: PathBuf,
14179 _: &dyn LspAdapterDelegate,
14180 ) -> Result<LanguageServerBinary> {
14181 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14182 }
14183}
14184
14185#[async_trait(?Send)]
14186impl LspAdapter for SshLspAdapter {
14187 fn name(&self) -> LanguageServerName {
14188 self.name.clone()
14189 }
14190
14191 async fn initialization_options(
14192 self: Arc<Self>,
14193 _: &Arc<dyn LspAdapterDelegate>,
14194 _: &mut AsyncApp,
14195 ) -> Result<Option<serde_json::Value>> {
14196 let Some(options) = &self.initialization_options else {
14197 return Ok(None);
14198 };
14199 let result = serde_json::from_str(options)?;
14200 Ok(result)
14201 }
14202
14203 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14204 self.code_action_kinds.clone()
14205 }
14206}
14207
14208pub fn language_server_settings<'a>(
14209 delegate: &'a dyn LspAdapterDelegate,
14210 language: &LanguageServerName,
14211 cx: &'a App,
14212) -> Option<&'a LspSettings> {
14213 language_server_settings_for(
14214 SettingsLocation {
14215 worktree_id: delegate.worktree_id(),
14216 path: RelPath::empty(),
14217 },
14218 language,
14219 cx,
14220 )
14221}
14222
14223pub fn language_server_settings_for<'a>(
14224 location: SettingsLocation<'a>,
14225 language: &LanguageServerName,
14226 cx: &'a App,
14227) -> Option<&'a LspSettings> {
14228 ProjectSettings::get(Some(location), cx).lsp.get(language)
14229}
14230
14231pub struct LocalLspAdapterDelegate {
14232 lsp_store: WeakEntity<LspStore>,
14233 worktree: worktree::Snapshot,
14234 fs: Arc<dyn Fs>,
14235 http_client: Arc<dyn HttpClient>,
14236 language_registry: Arc<LanguageRegistry>,
14237 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14238}
14239
14240impl LocalLspAdapterDelegate {
14241 pub fn new(
14242 language_registry: Arc<LanguageRegistry>,
14243 environment: &Entity<ProjectEnvironment>,
14244 lsp_store: WeakEntity<LspStore>,
14245 worktree: &Entity<Worktree>,
14246 http_client: Arc<dyn HttpClient>,
14247 fs: Arc<dyn Fs>,
14248 cx: &mut App,
14249 ) -> Arc<Self> {
14250 let load_shell_env_task =
14251 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14252
14253 Arc::new(Self {
14254 lsp_store,
14255 worktree: worktree.read(cx).snapshot(),
14256 fs,
14257 http_client,
14258 language_registry,
14259 load_shell_env_task,
14260 })
14261 }
14262
14263 pub fn from_local_lsp(
14264 local: &LocalLspStore,
14265 worktree: &Entity<Worktree>,
14266 cx: &mut App,
14267 ) -> Arc<Self> {
14268 Self::new(
14269 local.languages.clone(),
14270 &local.environment,
14271 local.weak.clone(),
14272 worktree,
14273 local.http_client.clone(),
14274 local.fs.clone(),
14275 cx,
14276 )
14277 }
14278}
14279
14280#[async_trait]
14281impl LspAdapterDelegate for LocalLspAdapterDelegate {
14282 fn show_notification(&self, message: &str, cx: &mut App) {
14283 self.lsp_store
14284 .update(cx, |_, cx| {
14285 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14286 })
14287 .ok();
14288 }
14289
14290 fn http_client(&self) -> Arc<dyn HttpClient> {
14291 self.http_client.clone()
14292 }
14293
14294 fn worktree_id(&self) -> WorktreeId {
14295 self.worktree.id()
14296 }
14297
14298 fn worktree_root_path(&self) -> &Path {
14299 self.worktree.abs_path().as_ref()
14300 }
14301
14302 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14303 self.worktree.resolve_relative_path(path)
14304 }
14305
14306 async fn shell_env(&self) -> HashMap<String, String> {
14307 let task = self.load_shell_env_task.clone();
14308 task.await.unwrap_or_default()
14309 }
14310
14311 async fn npm_package_installed_version(
14312 &self,
14313 package_name: &str,
14314 ) -> Result<Option<(PathBuf, Version)>> {
14315 let local_package_directory = self.worktree_root_path();
14316 let node_modules_directory = local_package_directory.join("node_modules");
14317
14318 if let Some(version) =
14319 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14320 {
14321 return Ok(Some((node_modules_directory, version)));
14322 }
14323 let Some(npm) = self.which("npm".as_ref()).await else {
14324 log::warn!(
14325 "Failed to find npm executable for {:?}",
14326 local_package_directory
14327 );
14328 return Ok(None);
14329 };
14330
14331 let env = self.shell_env().await;
14332 let output = util::command::new_command(&npm)
14333 .args(["root", "-g"])
14334 .envs(env)
14335 .current_dir(local_package_directory)
14336 .output()
14337 .await?;
14338 let global_node_modules =
14339 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14340
14341 if let Some(version) =
14342 read_package_installed_version(global_node_modules.clone(), package_name).await?
14343 {
14344 return Ok(Some((global_node_modules, version)));
14345 }
14346 return Ok(None);
14347 }
14348
14349 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14350 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14351 if self.fs.is_file(&worktree_abs_path).await {
14352 worktree_abs_path.pop();
14353 }
14354
14355 let env = self.shell_env().await;
14356
14357 let shell_path = env.get("PATH").cloned();
14358
14359 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14360 }
14361
14362 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14363 let mut working_dir = self.worktree_root_path().to_path_buf();
14364 if self.fs.is_file(&working_dir).await {
14365 working_dir.pop();
14366 }
14367 let output = util::command::new_command(&command.path)
14368 .args(command.arguments)
14369 .envs(command.env.clone().unwrap_or_default())
14370 .current_dir(working_dir)
14371 .output()
14372 .await?;
14373
14374 anyhow::ensure!(
14375 output.status.success(),
14376 "{}, stdout: {:?}, stderr: {:?}",
14377 output.status,
14378 String::from_utf8_lossy(&output.stdout),
14379 String::from_utf8_lossy(&output.stderr)
14380 );
14381 Ok(())
14382 }
14383
14384 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14385 self.language_registry
14386 .update_lsp_binary_status(server_name, status);
14387 }
14388
14389 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14390 self.language_registry
14391 .all_lsp_adapters()
14392 .into_iter()
14393 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14394 .collect()
14395 }
14396
14397 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14398 let dir = self.language_registry.language_server_download_dir(name)?;
14399
14400 if !dir.exists() {
14401 smol::fs::create_dir_all(&dir)
14402 .await
14403 .context("failed to create container directory")
14404 .log_err()?;
14405 }
14406
14407 Some(dir)
14408 }
14409
14410 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14411 let entry = self
14412 .worktree
14413 .entry_for_path(path)
14414 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14415 let abs_path = self.worktree.absolutize(&entry.path);
14416 self.fs.load(&abs_path).await
14417 }
14418}
14419
14420async fn populate_labels_for_symbols(
14421 symbols: Vec<CoreSymbol>,
14422 language_registry: &Arc<LanguageRegistry>,
14423 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14424 output: &mut Vec<Symbol>,
14425) {
14426 #[allow(clippy::mutable_key_type)]
14427 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14428
14429 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14430 for symbol in symbols {
14431 let Some(file_name) = symbol.path.file_name() else {
14432 continue;
14433 };
14434 let language = language_registry
14435 .load_language_for_file_path(Path::new(file_name))
14436 .await
14437 .ok()
14438 .or_else(|| {
14439 unknown_paths.insert(file_name.into());
14440 None
14441 });
14442 symbols_by_language
14443 .entry(language)
14444 .or_default()
14445 .push(symbol);
14446 }
14447
14448 for unknown_path in unknown_paths {
14449 log::info!("no language found for symbol in file {unknown_path:?}");
14450 }
14451
14452 let mut label_params = Vec::new();
14453 for (language, mut symbols) in symbols_by_language {
14454 label_params.clear();
14455 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14456 name: mem::take(&mut symbol.name),
14457 kind: symbol.kind,
14458 container_name: symbol.container_name.take(),
14459 }));
14460
14461 let mut labels = Vec::new();
14462 if let Some(language) = language {
14463 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14464 language_registry
14465 .lsp_adapters(&language.name())
14466 .first()
14467 .cloned()
14468 });
14469 if let Some(lsp_adapter) = lsp_adapter {
14470 labels = lsp_adapter
14471 .labels_for_symbols(&label_params, &language)
14472 .await
14473 .log_err()
14474 .unwrap_or_default();
14475 }
14476 }
14477
14478 for (
14479 (
14480 symbol,
14481 language::Symbol {
14482 name,
14483 container_name,
14484 ..
14485 },
14486 ),
14487 label,
14488 ) in symbols
14489 .into_iter()
14490 .zip(label_params.drain(..))
14491 .zip(labels.into_iter().chain(iter::repeat(None)))
14492 {
14493 output.push(Symbol {
14494 language_server_name: symbol.language_server_name,
14495 source_worktree_id: symbol.source_worktree_id,
14496 source_language_server_id: symbol.source_language_server_id,
14497 path: symbol.path,
14498 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14499 name,
14500 kind: symbol.kind,
14501 range: symbol.range,
14502 container_name,
14503 });
14504 }
14505 }
14506}
14507
14508pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14509 text.lines()
14510 .map(|line| line.trim())
14511 .filter(|line| !line.is_empty())
14512 .join(separator)
14513}
14514
14515fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14516 match server.capabilities().text_document_sync.as_ref()? {
14517 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14518 // Server wants didSave but didn't specify includeText.
14519 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14520 // Server doesn't want didSave at all.
14521 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14522 // Server provided SaveOptions.
14523 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14524 Some(save_options.include_text.unwrap_or(false))
14525 }
14526 },
14527 // We do not have any save info. Kind affects didChange only.
14528 lsp::TextDocumentSyncCapability::Kind(_) => None,
14529 }
14530}
14531
14532/// Completion items are displayed in a `UniformList`.
14533/// Usually, those items are single-line strings, but in LSP responses,
14534/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14535/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14536/// 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,
14537/// breaking the completions menu presentation.
14538///
14539/// 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.
14540pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14541 let mut new_text = String::with_capacity(label.text.len());
14542 let mut offset_map = vec![0; label.text.len() + 1];
14543 let mut last_char_was_space = false;
14544 let mut new_idx = 0;
14545 let chars = label.text.char_indices().fuse();
14546 let mut newlines_removed = false;
14547
14548 for (idx, c) in chars {
14549 offset_map[idx] = new_idx;
14550
14551 match c {
14552 '\n' if last_char_was_space => {
14553 newlines_removed = true;
14554 }
14555 '\t' | ' ' if last_char_was_space => {}
14556 '\n' if !last_char_was_space => {
14557 new_text.push(' ');
14558 new_idx += 1;
14559 last_char_was_space = true;
14560 newlines_removed = true;
14561 }
14562 ' ' | '\t' => {
14563 new_text.push(' ');
14564 new_idx += 1;
14565 last_char_was_space = true;
14566 }
14567 _ => {
14568 new_text.push(c);
14569 new_idx += c.len_utf8();
14570 last_char_was_space = false;
14571 }
14572 }
14573 }
14574 offset_map[label.text.len()] = new_idx;
14575
14576 // Only modify the label if newlines were removed.
14577 if !newlines_removed {
14578 return;
14579 }
14580
14581 let last_index = new_idx;
14582 let mut run_ranges_errors = Vec::new();
14583 label.runs.retain_mut(|(range, _)| {
14584 match offset_map.get(range.start) {
14585 Some(&start) => range.start = start,
14586 None => {
14587 run_ranges_errors.push(range.clone());
14588 return false;
14589 }
14590 }
14591
14592 match offset_map.get(range.end) {
14593 Some(&end) => range.end = end,
14594 None => {
14595 run_ranges_errors.push(range.clone());
14596 range.end = last_index;
14597 }
14598 }
14599 true
14600 });
14601 if !run_ranges_errors.is_empty() {
14602 log::error!(
14603 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14604 label.text
14605 );
14606 }
14607
14608 let mut wrong_filter_range = None;
14609 if label.filter_range == (0..label.text.len()) {
14610 label.filter_range = 0..new_text.len();
14611 } else {
14612 let mut original_filter_range = Some(label.filter_range.clone());
14613 match offset_map.get(label.filter_range.start) {
14614 Some(&start) => label.filter_range.start = start,
14615 None => {
14616 wrong_filter_range = original_filter_range.take();
14617 label.filter_range.start = last_index;
14618 }
14619 }
14620
14621 match offset_map.get(label.filter_range.end) {
14622 Some(&end) => label.filter_range.end = end,
14623 None => {
14624 wrong_filter_range = original_filter_range.take();
14625 label.filter_range.end = last_index;
14626 }
14627 }
14628 }
14629 if let Some(wrong_filter_range) = wrong_filter_range {
14630 log::error!(
14631 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14632 label.text
14633 );
14634 }
14635
14636 label.text = new_text;
14637}
14638
14639/// Apply edits to the buffer that will become part of the formatting transaction.
14640/// Fails if the buffer has been edited since the start of that transaction.
14641fn extend_formatting_transaction(
14642 buffer: &FormattableBuffer,
14643 formatting_transaction_id: text::TransactionId,
14644 cx: &mut AsyncApp,
14645 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14646) -> anyhow::Result<()> {
14647 buffer.handle.update(cx, |buffer, cx| {
14648 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14649 if last_transaction_id != Some(formatting_transaction_id) {
14650 anyhow::bail!("Buffer edited while formatting. Aborting")
14651 }
14652 buffer.start_transaction();
14653 operation(buffer, cx);
14654 if let Some(transaction_id) = buffer.end_transaction(cx) {
14655 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14656 }
14657 Ok(())
14658 })
14659}