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