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, LanguageAwareStyling, LanguageName, LanguageRegistry, LocalFile,
76 LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate, ManifestName, ModelineSettings,
77 OffsetUtf16, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToOffsetUtf16, ToPointUtf16,
78 Toolchain, Transaction, Unclipped,
79 language_settings::{
80 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
81 },
82 modeline, point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153#[cfg(any(test, feature = "test-support"))]
154pub use prettier::RANGE_FORMAT_SUFFIX as TEST_PRETTIER_RANGE_FORMAT_SUFFIX;
155pub use semantic_tokens::{
156 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
157};
158
159pub use worktree::{
160 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
161 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
162};
163
164const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
165pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
166const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
167const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
168static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
169
170#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
171pub enum ProgressToken {
172 Number(i32),
173 String(SharedString),
174}
175
176impl std::fmt::Display for ProgressToken {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 match self {
179 Self::Number(number) => write!(f, "{number}"),
180 Self::String(string) => write!(f, "{string}"),
181 }
182 }
183}
184
185impl ProgressToken {
186 fn from_lsp(value: lsp::NumberOrString) -> Self {
187 match value {
188 lsp::NumberOrString::Number(number) => Self::Number(number),
189 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
190 }
191 }
192
193 fn to_lsp(&self) -> lsp::NumberOrString {
194 match self {
195 Self::Number(number) => lsp::NumberOrString::Number(*number),
196 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
197 }
198 }
199
200 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
201 Some(match value.value? {
202 proto::progress_token::Value::Number(number) => Self::Number(number),
203 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
204 })
205 }
206
207 fn to_proto(&self) -> proto::ProgressToken {
208 proto::ProgressToken {
209 value: Some(match self {
210 Self::Number(number) => proto::progress_token::Value::Number(*number),
211 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
212 }),
213 }
214 }
215}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum FormatTrigger {
219 Save,
220 Manual,
221}
222
223pub enum LspFormatTarget {
224 Buffers,
225 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
226}
227
228#[derive(Debug, Clone, PartialEq, Eq, Hash)]
229pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
230
231struct OpenLspBuffer(Entity<Buffer>);
232
233impl FormatTrigger {
234 fn from_proto(value: i32) -> FormatTrigger {
235 match value {
236 0 => FormatTrigger::Save,
237 1 => FormatTrigger::Manual,
238 _ => FormatTrigger::Save,
239 }
240 }
241}
242
243#[derive(Clone)]
244struct UnifiedLanguageServer {
245 id: LanguageServerId,
246 project_roots: HashSet<Arc<RelPath>>,
247}
248
249/// Settings that affect language server identity.
250///
251/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
252/// updated via `workspace/didChangeConfiguration` without restarting the server.
253#[derive(Clone, Debug, Hash, PartialEq, Eq)]
254struct LanguageServerSeedSettings {
255 binary: Option<BinarySettings>,
256 initialization_options: Option<serde_json::Value>,
257}
258
259#[derive(Clone, Debug, Hash, PartialEq, Eq)]
260struct LanguageServerSeed {
261 worktree_id: WorktreeId,
262 name: LanguageServerName,
263 toolchain: Option<Toolchain>,
264 settings: LanguageServerSeedSettings,
265}
266
267#[derive(Debug)]
268pub struct DocumentDiagnosticsUpdate<'a, D> {
269 pub diagnostics: D,
270 pub result_id: Option<SharedString>,
271 pub registration_id: Option<SharedString>,
272 pub server_id: LanguageServerId,
273 pub disk_based_sources: Cow<'a, [String]>,
274}
275
276pub struct DocumentDiagnostics {
277 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
278 document_abs_path: PathBuf,
279 version: Option<i32>,
280}
281
282#[derive(Default, Debug)]
283struct DynamicRegistrations {
284 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
285 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
286}
287
288pub struct LocalLspStore {
289 weak: WeakEntity<LspStore>,
290 pub worktree_store: Entity<WorktreeStore>,
291 toolchain_store: Entity<LocalToolchainStore>,
292 http_client: Arc<dyn HttpClient>,
293 environment: Entity<ProjectEnvironment>,
294 fs: Arc<dyn Fs>,
295 languages: Arc<LanguageRegistry>,
296 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
297 yarn: Entity<YarnPathStore>,
298 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
299 buffers_being_formatted: HashSet<BufferId>,
300 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
301 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
302 watched_manifest_filenames: HashSet<ManifestName>,
303 language_server_paths_watched_for_rename:
304 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
305 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
306 supplementary_language_servers:
307 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
308 prettier_store: Entity<PrettierStore>,
309 next_diagnostic_group_id: usize,
310 diagnostics: HashMap<
311 WorktreeId,
312 HashMap<
313 Arc<RelPath>,
314 Vec<(
315 LanguageServerId,
316 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
317 )>,
318 >,
319 >,
320 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
321 _subscription: gpui::Subscription,
322 lsp_tree: LanguageServerTree,
323 registered_buffers: HashMap<BufferId, usize>,
324 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
325 buffer_pull_diagnostics_result_ids: HashMap<
326 LanguageServerId,
327 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
328 >,
329 workspace_pull_diagnostics_result_ids: HashMap<
330 LanguageServerId,
331 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
332 >,
333 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
334
335 buffers_to_refresh_hash_set: HashSet<BufferId>,
336 buffers_to_refresh_queue: VecDeque<BufferId>,
337 _background_diagnostics_worker: Shared<Task<()>>,
338}
339
340impl LocalLspStore {
341 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
342 pub fn running_language_server_for_id(
343 &self,
344 id: LanguageServerId,
345 ) -> Option<&Arc<LanguageServer>> {
346 let language_server_state = self.language_servers.get(&id)?;
347
348 match language_server_state {
349 LanguageServerState::Running { server, .. } => Some(server),
350 LanguageServerState::Starting { .. } => None,
351 }
352 }
353
354 fn get_or_insert_language_server(
355 &mut self,
356 worktree_handle: &Entity<Worktree>,
357 delegate: Arc<LocalLspAdapterDelegate>,
358 disposition: &Arc<LaunchDisposition>,
359 language_name: &LanguageName,
360 cx: &mut App,
361 ) -> LanguageServerId {
362 let key = LanguageServerSeed {
363 worktree_id: worktree_handle.read(cx).id(),
364 name: disposition.server_name.clone(),
365 settings: LanguageServerSeedSettings {
366 binary: disposition.settings.binary.clone(),
367 initialization_options: disposition.settings.initialization_options.clone(),
368 },
369 toolchain: disposition.toolchain.clone(),
370 };
371 if let Some(state) = self.language_server_ids.get_mut(&key) {
372 state.project_roots.insert(disposition.path.path.clone());
373 state.id
374 } else {
375 let adapter = self
376 .languages
377 .lsp_adapters(language_name)
378 .into_iter()
379 .find(|adapter| adapter.name() == disposition.server_name)
380 .expect("To find LSP adapter");
381 let new_language_server_id = self.start_language_server(
382 worktree_handle,
383 delegate,
384 adapter,
385 disposition.settings.clone(),
386 key.clone(),
387 language_name.clone(),
388 cx,
389 );
390 if let Some(state) = self.language_server_ids.get_mut(&key) {
391 state.project_roots.insert(disposition.path.path.clone());
392 } else {
393 debug_assert!(
394 false,
395 "Expected `start_language_server` to ensure that `key` exists in a map"
396 );
397 }
398 new_language_server_id
399 }
400 }
401
402 fn start_language_server(
403 &mut self,
404 worktree_handle: &Entity<Worktree>,
405 delegate: Arc<LocalLspAdapterDelegate>,
406 adapter: Arc<CachedLspAdapter>,
407 settings: Arc<LspSettings>,
408 key: LanguageServerSeed,
409 language_name: LanguageName,
410 cx: &mut App,
411 ) -> LanguageServerId {
412 let worktree = worktree_handle.read(cx);
413
414 let worktree_id = worktree.id();
415 let worktree_abs_path = worktree.abs_path();
416 let toolchain = key.toolchain.clone();
417 let override_options = settings.initialization_options.clone();
418
419 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
420
421 let server_id = self.languages.next_language_server_id();
422 log::trace!(
423 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
424 adapter.name.0
425 );
426
427 let wait_until_worktree_trust =
428 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
429 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
430 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
431 });
432 if can_trust {
433 self.restricted_worktrees_tasks.remove(&worktree_id);
434 None
435 } else {
436 match self.restricted_worktrees_tasks.entry(worktree_id) {
437 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
438 hash_map::Entry::Vacant(v) => {
439 let (mut tx, rx) = watch::channel::<bool>();
440 let lsp_store = self.weak.clone();
441 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
442 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
443 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
444 tx.blocking_send(true).ok();
445 lsp_store
446 .update(cx, |lsp_store, _| {
447 if let Some(local_lsp_store) =
448 lsp_store.as_local_mut()
449 {
450 local_lsp_store
451 .restricted_worktrees_tasks
452 .remove(&worktree_id);
453 }
454 })
455 .ok();
456 }
457 }
458 });
459 v.insert((subscription, rx.clone()));
460 Some(rx)
461 }
462 }
463 }
464 });
465 let update_binary_status = wait_until_worktree_trust.is_none();
466
467 let binary = self.get_language_server_binary(
468 worktree_abs_path.clone(),
469 adapter.clone(),
470 settings,
471 toolchain.clone(),
472 delegate.clone(),
473 true,
474 wait_until_worktree_trust,
475 cx,
476 );
477 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
478
479 let pending_server = cx.spawn({
480 let adapter = adapter.clone();
481 let server_name = adapter.name.clone();
482 let stderr_capture = stderr_capture.clone();
483 #[cfg(any(test, feature = "test-support"))]
484 let lsp_store = self.weak.clone();
485 let pending_workspace_folders = pending_workspace_folders.clone();
486 async move |cx| {
487 let binary = binary.await?;
488 #[cfg(any(test, feature = "test-support"))]
489 if let Some(server) = lsp_store
490 .update(&mut cx.clone(), |this, cx| {
491 this.languages.create_fake_language_server(
492 server_id,
493 &server_name,
494 binary.clone(),
495 &mut cx.to_async(),
496 )
497 })
498 .ok()
499 .flatten()
500 {
501 return Ok(server);
502 }
503
504 let code_action_kinds = adapter.code_action_kinds();
505 lsp::LanguageServer::new(
506 stderr_capture,
507 server_id,
508 server_name,
509 binary,
510 &worktree_abs_path,
511 code_action_kinds,
512 Some(pending_workspace_folders),
513 cx,
514 )
515 }
516 });
517
518 let startup = {
519 let server_name = adapter.name.0.clone();
520 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
521 let key = key.clone();
522 let adapter = adapter.clone();
523 let lsp_store = self.weak.clone();
524 let pending_workspace_folders = pending_workspace_folders.clone();
525 let pull_diagnostics = ProjectSettings::get_global(cx)
526 .diagnostics
527 .lsp_pull_diagnostics
528 .enabled;
529 let settings_location = SettingsLocation {
530 worktree_id,
531 path: RelPath::empty(),
532 };
533 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
534 .language(Some(settings_location), Some(&language_name), cx)
535 .semantic_tokens
536 .use_tree_sitter();
537 cx.spawn(async move |cx| {
538 let result = async {
539 let language_server = pending_server.await?;
540
541 let workspace_config = Self::workspace_configuration_for_adapter(
542 adapter.adapter.clone(),
543 &delegate,
544 toolchain,
545 None,
546 cx,
547 )
548 .await?;
549
550 let mut initialization_options = Self::initialization_options_for_adapter(
551 adapter.adapter.clone(),
552 &delegate,
553 cx,
554 )
555 .await?;
556
557 match (&mut initialization_options, override_options) {
558 (Some(initialization_options), Some(override_options)) => {
559 merge_json_value_into(override_options, initialization_options);
560 }
561 (None, override_options) => initialization_options = override_options,
562 _ => {}
563 }
564
565 let initialization_params = cx.update(|cx| {
566 let mut params = language_server.default_initialize_params(
567 pull_diagnostics,
568 augments_syntax_tokens,
569 cx,
570 );
571 params.initialization_options = initialization_options;
572 adapter.adapter.prepare_initialize_params(params, cx)
573 })?;
574
575 Self::setup_lsp_messages(
576 lsp_store.clone(),
577 &language_server,
578 delegate.clone(),
579 adapter.clone(),
580 );
581
582 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
583 settings: workspace_config,
584 };
585 let language_server = cx
586 .update(|cx| {
587 let request_timeout = ProjectSettings::get_global(cx)
588 .global_lsp_settings
589 .get_request_timeout();
590
591 language_server.initialize(
592 initialization_params,
593 Arc::new(did_change_configuration_params.clone()),
594 request_timeout,
595 cx,
596 )
597 })
598 .await
599 .inspect_err(|_| {
600 if let Some(lsp_store) = lsp_store.upgrade() {
601 lsp_store.update(cx, |lsp_store, cx| {
602 lsp_store.cleanup_lsp_data(server_id);
603 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
604 });
605 }
606 })?;
607
608 language_server.notify::<lsp::notification::DidChangeConfiguration>(
609 did_change_configuration_params,
610 )?;
611
612 anyhow::Ok(language_server)
613 }
614 .await;
615
616 match result {
617 Ok(server) => {
618 lsp_store
619 .update(cx, |lsp_store, cx| {
620 lsp_store.insert_newly_running_language_server(
621 adapter,
622 server.clone(),
623 server_id,
624 key,
625 pending_workspace_folders,
626 cx,
627 );
628 })
629 .ok();
630 stderr_capture.lock().take();
631 Some(server)
632 }
633
634 Err(err) => {
635 let log = stderr_capture.lock().take().unwrap_or_default();
636 delegate.update_status(
637 adapter.name(),
638 BinaryStatus::Failed {
639 error: if log.is_empty() {
640 format!("{err:#}")
641 } else {
642 format!("{err:#}\n-- stderr --\n{log}")
643 },
644 },
645 );
646 log::error!(
647 "Failed to start language server {server_name:?}: {}",
648 redact_command(&format!("{err:?}"))
649 );
650 if !log.is_empty() {
651 log::error!("server stderr: {}", redact_command(&log));
652 }
653 None
654 }
655 }
656 })
657 };
658 let state = LanguageServerState::Starting {
659 startup,
660 pending_workspace_folders,
661 };
662
663 if update_binary_status {
664 self.languages
665 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
666 }
667
668 self.language_servers.insert(server_id, state);
669 self.language_server_ids
670 .entry(key)
671 .or_insert(UnifiedLanguageServer {
672 id: server_id,
673 project_roots: Default::default(),
674 });
675 server_id
676 }
677
678 fn get_language_server_binary(
679 &self,
680 worktree_abs_path: Arc<Path>,
681 adapter: Arc<CachedLspAdapter>,
682 settings: Arc<LspSettings>,
683 toolchain: Option<Toolchain>,
684 delegate: Arc<dyn LspAdapterDelegate>,
685 allow_binary_download: bool,
686 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
687 cx: &mut App,
688 ) -> Task<Result<LanguageServerBinary>> {
689 if let Some(settings) = &settings.binary
690 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
691 {
692 let settings = settings.clone();
693 let languages = self.languages.clone();
694 return cx.background_spawn(async move {
695 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
696 let already_trusted = *wait_until_worktree_trust.borrow();
697 if !already_trusted {
698 log::info!(
699 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
700 adapter.name(),
701 );
702 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
703 if worktree_trusted {
704 break;
705 }
706 }
707 log::info!(
708 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
709 adapter.name(),
710 );
711 }
712 languages
713 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
714 }
715 let mut env = delegate.shell_env().await;
716 env.extend(settings.env.unwrap_or_default());
717
718 Ok(LanguageServerBinary {
719 path: delegate.resolve_relative_path(path),
720 env: Some(env),
721 arguments: settings
722 .arguments
723 .unwrap_or_default()
724 .iter()
725 .map(Into::into)
726 .collect(),
727 })
728 });
729 }
730 let lsp_binary_options = LanguageServerBinaryOptions {
731 allow_path_lookup: !settings
732 .binary
733 .as_ref()
734 .and_then(|b| b.ignore_system_version)
735 .unwrap_or_default(),
736 allow_binary_download,
737 pre_release: settings
738 .fetch
739 .as_ref()
740 .and_then(|f| f.pre_release)
741 .unwrap_or(false),
742 };
743
744 cx.spawn(async move |cx| {
745 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
746 let already_trusted = *wait_until_worktree_trust.borrow();
747 if !already_trusted {
748 log::info!(
749 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
750 adapter.name(),
751 );
752 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
753 if worktree_trusted {
754 break;
755 }
756 }
757 log::info!(
758 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
759 adapter.name(),
760 );
761 }
762 }
763
764 let (existing_binary, maybe_download_binary) = adapter
765 .clone()
766 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
767 .await
768 .await;
769
770 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
771
772 let mut binary = match (existing_binary, maybe_download_binary) {
773 (binary, None) => binary?,
774 (Err(_), Some(downloader)) => downloader.await?,
775 (Ok(existing_binary), Some(downloader)) => {
776 let mut download_timeout = cx
777 .background_executor()
778 .timer(SERVER_DOWNLOAD_TIMEOUT)
779 .fuse();
780 let mut downloader = downloader.fuse();
781 futures::select! {
782 _ = download_timeout => {
783 // Return existing binary and kick the existing work to the background.
784 cx.spawn(async move |_| downloader.await).detach();
785 Ok(existing_binary)
786 },
787 downloaded_or_existing_binary = downloader => {
788 // If download fails, this results in the existing binary.
789 downloaded_or_existing_binary
790 }
791 }?
792 }
793 };
794 let mut shell_env = delegate.shell_env().await;
795
796 shell_env.extend(binary.env.unwrap_or_default());
797
798 if let Some(settings) = settings.binary.as_ref() {
799 if let Some(arguments) = &settings.arguments {
800 binary.arguments = arguments.iter().map(Into::into).collect();
801 }
802 if let Some(env) = &settings.env {
803 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
804 }
805 }
806
807 binary.env = Some(shell_env);
808 Ok(binary)
809 })
810 }
811
812 fn setup_lsp_messages(
813 lsp_store: WeakEntity<LspStore>,
814 language_server: &LanguageServer,
815 delegate: Arc<dyn LspAdapterDelegate>,
816 adapter: Arc<CachedLspAdapter>,
817 ) {
818 let name = language_server.name();
819 let server_id = language_server.server_id();
820 language_server
821 .on_notification::<lsp::notification::PublishDiagnostics, _>({
822 let adapter = adapter.clone();
823 let this = lsp_store.clone();
824 move |mut params, cx| {
825 let adapter = adapter.clone();
826 if let Some(this) = this.upgrade() {
827 this.update(cx, |this, cx| {
828 adapter.process_diagnostics(&mut params, server_id);
829
830 this.merge_lsp_diagnostics(
831 DiagnosticSourceKind::Pushed,
832 vec![DocumentDiagnosticsUpdate {
833 server_id,
834 diagnostics: params,
835 result_id: None,
836 disk_based_sources: Cow::Borrowed(
837 &adapter.disk_based_diagnostic_sources,
838 ),
839 registration_id: None,
840 }],
841 |_, diagnostic, _cx| match diagnostic.source_kind {
842 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
843 adapter.retain_old_diagnostic(diagnostic)
844 }
845 DiagnosticSourceKind::Pulled => true,
846 },
847 cx,
848 )
849 .log_err();
850 });
851 }
852 }
853 })
854 .detach();
855 language_server
856 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
857 let adapter = adapter.adapter.clone();
858 let delegate = delegate.clone();
859 let this = lsp_store.clone();
860 move |params, cx| {
861 let adapter = adapter.clone();
862 let delegate = delegate.clone();
863 let this = this.clone();
864 let mut cx = cx.clone();
865 async move {
866 let toolchain_for_id = this
867 .update(&mut cx, |this, _| {
868 this.as_local()?.language_server_ids.iter().find_map(
869 |(seed, value)| {
870 (value.id == server_id).then(|| seed.toolchain.clone())
871 },
872 )
873 })?
874 .context("Expected the LSP store to be in a local mode")?;
875
876 let mut scope_uri_to_workspace_config = BTreeMap::new();
877 for item in ¶ms.items {
878 let scope_uri = item.scope_uri.clone();
879 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
880 scope_uri_to_workspace_config.entry(scope_uri.clone())
881 else {
882 // We've already queried workspace configuration of this URI.
883 continue;
884 };
885 let workspace_config = Self::workspace_configuration_for_adapter(
886 adapter.clone(),
887 &delegate,
888 toolchain_for_id.clone(),
889 scope_uri,
890 &mut cx,
891 )
892 .await?;
893 new_scope_uri.insert(workspace_config);
894 }
895
896 Ok(params
897 .items
898 .into_iter()
899 .filter_map(|item| {
900 let workspace_config =
901 scope_uri_to_workspace_config.get(&item.scope_uri)?;
902 if let Some(section) = &item.section {
903 Some(
904 workspace_config
905 .get(section)
906 .cloned()
907 .unwrap_or(serde_json::Value::Null),
908 )
909 } else {
910 Some(workspace_config.clone())
911 }
912 })
913 .collect())
914 }
915 }
916 })
917 .detach();
918
919 language_server
920 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
921 let this = lsp_store.clone();
922 move |_, cx| {
923 let this = this.clone();
924 let cx = cx.clone();
925 async move {
926 let Some(server) =
927 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
928 else {
929 return Ok(None);
930 };
931 let root = server.workspace_folders();
932 Ok(Some(
933 root.into_iter()
934 .map(|uri| WorkspaceFolder {
935 uri,
936 name: Default::default(),
937 })
938 .collect(),
939 ))
940 }
941 }
942 })
943 .detach();
944 // Even though we don't have handling for these requests, respond to them to
945 // avoid stalling any language server like `gopls` which waits for a response
946 // to these requests when initializing.
947 language_server
948 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
949 let this = lsp_store.clone();
950 move |params, cx| {
951 let this = this.clone();
952 let mut cx = cx.clone();
953 async move {
954 this.update(&mut cx, |this, _| {
955 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
956 {
957 status
958 .progress_tokens
959 .insert(ProgressToken::from_lsp(params.token));
960 }
961 })?;
962
963 Ok(())
964 }
965 }
966 })
967 .detach();
968
969 language_server
970 .on_request::<lsp::request::RegisterCapability, _, _>({
971 let lsp_store = lsp_store.clone();
972 move |params, cx| {
973 let lsp_store = lsp_store.clone();
974 let mut cx = cx.clone();
975 async move {
976 lsp_store
977 .update(&mut cx, |lsp_store, cx| {
978 if lsp_store.as_local().is_some() {
979 match lsp_store
980 .register_server_capabilities(server_id, params, cx)
981 {
982 Ok(()) => {}
983 Err(e) => {
984 log::error!(
985 "Failed to register server capabilities: {e:#}"
986 );
987 }
988 };
989 }
990 })
991 .ok();
992 Ok(())
993 }
994 }
995 })
996 .detach();
997
998 language_server
999 .on_request::<lsp::request::UnregisterCapability, _, _>({
1000 let lsp_store = lsp_store.clone();
1001 move |params, cx| {
1002 let lsp_store = lsp_store.clone();
1003 let mut cx = cx.clone();
1004 async move {
1005 lsp_store
1006 .update(&mut cx, |lsp_store, cx| {
1007 if lsp_store.as_local().is_some() {
1008 match lsp_store
1009 .unregister_server_capabilities(server_id, params, cx)
1010 {
1011 Ok(()) => {}
1012 Err(e) => {
1013 log::error!(
1014 "Failed to unregister server capabilities: {e:#}"
1015 );
1016 }
1017 }
1018 }
1019 })
1020 .ok();
1021 Ok(())
1022 }
1023 }
1024 })
1025 .detach();
1026
1027 language_server
1028 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1029 let this = lsp_store.clone();
1030 move |params, cx| {
1031 let mut cx = cx.clone();
1032 let this = this.clone();
1033 async move {
1034 LocalLspStore::on_lsp_workspace_edit(
1035 this.clone(),
1036 params,
1037 server_id,
1038 &mut cx,
1039 )
1040 .await
1041 }
1042 }
1043 })
1044 .detach();
1045
1046 language_server
1047 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1048 let lsp_store = lsp_store.clone();
1049 let request_id = Arc::new(AtomicUsize::new(0));
1050 move |(), cx| {
1051 let lsp_store = lsp_store.clone();
1052 let request_id = request_id.clone();
1053 let mut cx = cx.clone();
1054 async move {
1055 lsp_store
1056 .update(&mut cx, |lsp_store, cx| {
1057 let request_id =
1058 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1059 cx.emit(LspStoreEvent::RefreshInlayHints {
1060 server_id,
1061 request_id,
1062 });
1063 lsp_store
1064 .downstream_client
1065 .as_ref()
1066 .map(|(client, project_id)| {
1067 client.send(proto::RefreshInlayHints {
1068 project_id: *project_id,
1069 server_id: server_id.to_proto(),
1070 request_id: request_id.map(|id| id as u64),
1071 })
1072 })
1073 })?
1074 .transpose()?;
1075 Ok(())
1076 }
1077 }
1078 })
1079 .detach();
1080
1081 language_server
1082 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1083 let this = lsp_store.clone();
1084 move |(), cx| {
1085 let this = this.clone();
1086 let mut cx = cx.clone();
1087 async move {
1088 this.update(&mut cx, |this, cx| {
1089 this.invalidate_code_lens();
1090 cx.emit(LspStoreEvent::RefreshCodeLens);
1091 this.downstream_client.as_ref().map(|(client, project_id)| {
1092 client.send(proto::RefreshCodeLens {
1093 project_id: *project_id,
1094 })
1095 })
1096 })?
1097 .transpose()?;
1098 Ok(())
1099 }
1100 }
1101 })
1102 .detach();
1103
1104 language_server
1105 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1106 let lsp_store = lsp_store.clone();
1107 let request_id = Arc::new(AtomicUsize::new(0));
1108 move |(), cx| {
1109 let lsp_store = lsp_store.clone();
1110 let request_id = request_id.clone();
1111 let mut cx = cx.clone();
1112 async move {
1113 lsp_store
1114 .update(&mut cx, |lsp_store, cx| {
1115 let request_id =
1116 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1117 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1118 server_id,
1119 request_id,
1120 });
1121 lsp_store
1122 .downstream_client
1123 .as_ref()
1124 .map(|(client, project_id)| {
1125 client.send(proto::RefreshSemanticTokens {
1126 project_id: *project_id,
1127 server_id: server_id.to_proto(),
1128 request_id: request_id.map(|id| id as u64),
1129 })
1130 })
1131 })?
1132 .transpose()?;
1133 Ok(())
1134 }
1135 }
1136 })
1137 .detach();
1138
1139 language_server
1140 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1141 let this = lsp_store.clone();
1142 move |(), cx| {
1143 let this = this.clone();
1144 let mut cx = cx.clone();
1145 async move {
1146 this.update(&mut cx, |lsp_store, cx| {
1147 lsp_store.pull_workspace_diagnostics(server_id);
1148 lsp_store
1149 .downstream_client
1150 .as_ref()
1151 .map(|(client, project_id)| {
1152 client.send(proto::PullWorkspaceDiagnostics {
1153 project_id: *project_id,
1154 server_id: server_id.to_proto(),
1155 })
1156 })
1157 .transpose()?;
1158 anyhow::Ok(
1159 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1160 )
1161 })??
1162 .await;
1163 Ok(())
1164 }
1165 }
1166 })
1167 .detach();
1168
1169 language_server
1170 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1171 let this = lsp_store.clone();
1172 let name = name.to_string();
1173 let adapter = adapter.clone();
1174 move |params, cx| {
1175 let this = this.clone();
1176 let name = name.to_string();
1177 let adapter = adapter.clone();
1178 let mut cx = cx.clone();
1179 async move {
1180 let actions = params.actions.unwrap_or_default();
1181 let message = params.message.clone();
1182 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1183 let level = match params.typ {
1184 lsp::MessageType::ERROR => PromptLevel::Critical,
1185 lsp::MessageType::WARNING => PromptLevel::Warning,
1186 _ => PromptLevel::Info,
1187 };
1188 let request = LanguageServerPromptRequest::new(
1189 level,
1190 params.message,
1191 actions,
1192 name.clone(),
1193 tx,
1194 );
1195
1196 let did_update = this
1197 .update(&mut cx, |_, cx| {
1198 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1199 })
1200 .is_ok();
1201 if did_update {
1202 let response = rx.recv().await.ok();
1203 if let Some(ref selected_action) = response {
1204 let context = language::PromptResponseContext {
1205 message,
1206 selected_action: selected_action.clone(),
1207 };
1208 adapter.process_prompt_response(&context, &mut cx)
1209 }
1210
1211 Ok(response)
1212 } else {
1213 Ok(None)
1214 }
1215 }
1216 }
1217 })
1218 .detach();
1219 language_server
1220 .on_notification::<lsp::notification::ShowMessage, _>({
1221 let this = lsp_store.clone();
1222 let name = name.to_string();
1223 move |params, cx| {
1224 let this = this.clone();
1225 let name = name.to_string();
1226 let mut cx = cx.clone();
1227
1228 let (tx, _) = smol::channel::bounded(1);
1229 let level = match params.typ {
1230 lsp::MessageType::ERROR => PromptLevel::Critical,
1231 lsp::MessageType::WARNING => PromptLevel::Warning,
1232 _ => PromptLevel::Info,
1233 };
1234 let request =
1235 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1236
1237 let _ = this.update(&mut cx, |_, cx| {
1238 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1239 });
1240 }
1241 })
1242 .detach();
1243
1244 let disk_based_diagnostics_progress_token =
1245 adapter.disk_based_diagnostics_progress_token.clone();
1246
1247 language_server
1248 .on_notification::<lsp::notification::Progress, _>({
1249 let this = lsp_store.clone();
1250 move |params, cx| {
1251 if let Some(this) = this.upgrade() {
1252 this.update(cx, |this, cx| {
1253 this.on_lsp_progress(
1254 params,
1255 server_id,
1256 disk_based_diagnostics_progress_token.clone(),
1257 cx,
1258 );
1259 });
1260 }
1261 }
1262 })
1263 .detach();
1264
1265 language_server
1266 .on_notification::<lsp::notification::LogMessage, _>({
1267 let this = lsp_store.clone();
1268 move |params, cx| {
1269 if let Some(this) = this.upgrade() {
1270 this.update(cx, |_, cx| {
1271 cx.emit(LspStoreEvent::LanguageServerLog(
1272 server_id,
1273 LanguageServerLogType::Log(params.typ),
1274 params.message,
1275 ));
1276 });
1277 }
1278 }
1279 })
1280 .detach();
1281
1282 language_server
1283 .on_notification::<lsp::notification::LogTrace, _>({
1284 let this = lsp_store.clone();
1285 move |params, cx| {
1286 let mut cx = cx.clone();
1287 if let Some(this) = this.upgrade() {
1288 this.update(&mut cx, |_, cx| {
1289 cx.emit(LspStoreEvent::LanguageServerLog(
1290 server_id,
1291 LanguageServerLogType::Trace {
1292 verbose_info: params.verbose,
1293 },
1294 params.message,
1295 ));
1296 });
1297 }
1298 }
1299 })
1300 .detach();
1301
1302 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1303 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1304 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1305 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1306 }
1307
1308 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1309 let shutdown_futures = self
1310 .language_servers
1311 .drain()
1312 .map(|(_, server_state)| Self::shutdown_server(server_state))
1313 .collect::<Vec<_>>();
1314
1315 async move {
1316 join_all(shutdown_futures).await;
1317 }
1318 }
1319
1320 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1321 match server_state {
1322 LanguageServerState::Running { server, .. } => {
1323 if let Some(shutdown) = server.shutdown() {
1324 shutdown.await;
1325 }
1326 }
1327 LanguageServerState::Starting { startup, .. } => {
1328 if let Some(server) = startup.await
1329 && let Some(shutdown) = server.shutdown()
1330 {
1331 shutdown.await;
1332 }
1333 }
1334 }
1335 Ok(())
1336 }
1337
1338 fn language_servers_for_worktree(
1339 &self,
1340 worktree_id: WorktreeId,
1341 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1342 self.language_server_ids
1343 .iter()
1344 .filter_map(move |(seed, state)| {
1345 if seed.worktree_id != worktree_id {
1346 return None;
1347 }
1348
1349 if let Some(LanguageServerState::Running { server, .. }) =
1350 self.language_servers.get(&state.id)
1351 {
1352 Some(server)
1353 } else {
1354 None
1355 }
1356 })
1357 }
1358
1359 fn language_server_ids_for_project_path(
1360 &self,
1361 project_path: ProjectPath,
1362 language: &Language,
1363 cx: &mut App,
1364 ) -> Vec<LanguageServerId> {
1365 let Some(worktree) = self
1366 .worktree_store
1367 .read(cx)
1368 .worktree_for_id(project_path.worktree_id, cx)
1369 else {
1370 return Vec::new();
1371 };
1372 let delegate: Arc<dyn ManifestDelegate> =
1373 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1374
1375 self.lsp_tree
1376 .get(
1377 project_path,
1378 language.name(),
1379 language.manifest(),
1380 &delegate,
1381 cx,
1382 )
1383 .collect::<Vec<_>>()
1384 }
1385
1386 fn language_server_ids_for_buffer(
1387 &self,
1388 buffer: &Buffer,
1389 cx: &mut App,
1390 ) -> Vec<LanguageServerId> {
1391 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1392 let worktree_id = file.worktree_id(cx);
1393
1394 let path: Arc<RelPath> = file
1395 .path()
1396 .parent()
1397 .map(Arc::from)
1398 .unwrap_or_else(|| file.path().clone());
1399 let worktree_path = ProjectPath { worktree_id, path };
1400 self.language_server_ids_for_project_path(worktree_path, language, cx)
1401 } else {
1402 Vec::new()
1403 }
1404 }
1405
1406 fn language_servers_for_buffer<'a>(
1407 &'a self,
1408 buffer: &'a Buffer,
1409 cx: &'a mut App,
1410 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1411 self.language_server_ids_for_buffer(buffer, cx)
1412 .into_iter()
1413 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1414 LanguageServerState::Running {
1415 adapter, server, ..
1416 } => Some((adapter, server)),
1417 _ => None,
1418 })
1419 }
1420
1421 async fn execute_code_action_kind_locally(
1422 lsp_store: WeakEntity<LspStore>,
1423 mut buffers: Vec<Entity<Buffer>>,
1424 kind: CodeActionKind,
1425 push_to_history: bool,
1426 cx: &mut AsyncApp,
1427 ) -> anyhow::Result<ProjectTransaction> {
1428 // Do not allow multiple concurrent code actions requests for the
1429 // same buffer.
1430 lsp_store.update(cx, |this, cx| {
1431 let this = this.as_local_mut().unwrap();
1432 buffers.retain(|buffer| {
1433 this.buffers_being_formatted
1434 .insert(buffer.read(cx).remote_id())
1435 });
1436 })?;
1437 let _cleanup = defer({
1438 let this = lsp_store.clone();
1439 let mut cx = cx.clone();
1440 let buffers = &buffers;
1441 move || {
1442 this.update(&mut cx, |this, cx| {
1443 let this = this.as_local_mut().unwrap();
1444 for buffer in buffers {
1445 this.buffers_being_formatted
1446 .remove(&buffer.read(cx).remote_id());
1447 }
1448 })
1449 .ok();
1450 }
1451 });
1452 let mut project_transaction = ProjectTransaction::default();
1453
1454 for buffer in &buffers {
1455 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1456 buffer.update(cx, |buffer, cx| {
1457 lsp_store
1458 .as_local()
1459 .unwrap()
1460 .language_servers_for_buffer(buffer, cx)
1461 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1462 .collect::<Vec<_>>()
1463 })
1464 })?;
1465 for (_, language_server) in adapters_and_servers.iter() {
1466 let actions = Self::get_server_code_actions_from_action_kinds(
1467 &lsp_store,
1468 language_server.server_id(),
1469 vec![kind.clone()],
1470 buffer,
1471 cx,
1472 )
1473 .await?;
1474 Self::execute_code_actions_on_server(
1475 &lsp_store,
1476 language_server,
1477 actions,
1478 push_to_history,
1479 &mut project_transaction,
1480 cx,
1481 )
1482 .await?;
1483 }
1484 }
1485 Ok(project_transaction)
1486 }
1487
1488 async fn format_locally(
1489 lsp_store: WeakEntity<LspStore>,
1490 mut buffers: Vec<FormattableBuffer>,
1491 push_to_history: bool,
1492 trigger: FormatTrigger,
1493 logger: zlog::Logger,
1494 cx: &mut AsyncApp,
1495 ) -> anyhow::Result<ProjectTransaction> {
1496 // Do not allow multiple concurrent formatting requests for the
1497 // same buffer.
1498 lsp_store.update(cx, |this, cx| {
1499 let this = this.as_local_mut().unwrap();
1500 buffers.retain(|buffer| {
1501 this.buffers_being_formatted
1502 .insert(buffer.handle.read(cx).remote_id())
1503 });
1504 })?;
1505
1506 let _cleanup = defer({
1507 let this = lsp_store.clone();
1508 let mut cx = cx.clone();
1509 let buffers = &buffers;
1510 move || {
1511 this.update(&mut cx, |this, cx| {
1512 let this = this.as_local_mut().unwrap();
1513 for buffer in buffers {
1514 this.buffers_being_formatted
1515 .remove(&buffer.handle.read(cx).remote_id());
1516 }
1517 })
1518 .ok();
1519 }
1520 });
1521
1522 let mut project_transaction = ProjectTransaction::default();
1523
1524 for buffer in &buffers {
1525 zlog::debug!(
1526 logger =>
1527 "formatting buffer '{:?}'",
1528 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1529 );
1530 // Create an empty transaction to hold all of the formatting edits.
1531 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1532 // ensure no transactions created while formatting are
1533 // grouped with the previous transaction in the history
1534 // based on the transaction group interval
1535 buffer.finalize_last_transaction();
1536 buffer
1537 .start_transaction()
1538 .context("transaction already open")?;
1539 buffer.end_transaction(cx);
1540 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1541 buffer.finalize_last_transaction();
1542 anyhow::Ok(transaction_id)
1543 })?;
1544
1545 let result = Self::format_buffer_locally(
1546 lsp_store.clone(),
1547 buffer,
1548 formatting_transaction_id,
1549 trigger,
1550 logger,
1551 cx,
1552 )
1553 .await;
1554
1555 buffer.handle.update(cx, |buffer, cx| {
1556 let Some(formatting_transaction) =
1557 buffer.get_transaction(formatting_transaction_id).cloned()
1558 else {
1559 zlog::warn!(logger => "no formatting transaction");
1560 return;
1561 };
1562 if formatting_transaction.edit_ids.is_empty() {
1563 zlog::debug!(logger => "no changes made while formatting");
1564 buffer.forget_transaction(formatting_transaction_id);
1565 return;
1566 }
1567 if !push_to_history {
1568 zlog::trace!(logger => "forgetting format transaction");
1569 buffer.forget_transaction(formatting_transaction.id);
1570 }
1571 project_transaction
1572 .0
1573 .insert(cx.entity(), formatting_transaction);
1574 });
1575
1576 result?;
1577 }
1578
1579 Ok(project_transaction)
1580 }
1581
1582 async fn format_buffer_locally(
1583 lsp_store: WeakEntity<LspStore>,
1584 buffer: &FormattableBuffer,
1585 formatting_transaction_id: clock::Lamport,
1586 trigger: FormatTrigger,
1587 logger: zlog::Logger,
1588 cx: &mut AsyncApp,
1589 ) -> Result<()> {
1590 let (adapters_and_servers, settings, request_timeout) =
1591 lsp_store.update(cx, |lsp_store, cx| {
1592 buffer.handle.update(cx, |buffer, cx| {
1593 let adapters_and_servers = lsp_store
1594 .as_local()
1595 .unwrap()
1596 .language_servers_for_buffer(buffer, cx)
1597 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1598 .collect::<Vec<_>>();
1599 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1600 let request_timeout = ProjectSettings::get_global(cx)
1601 .global_lsp_settings
1602 .get_request_timeout();
1603 (adapters_and_servers, settings, request_timeout)
1604 })
1605 })?;
1606
1607 // handle whitespace formatting
1608 if settings.remove_trailing_whitespace_on_save {
1609 zlog::trace!(logger => "removing trailing whitespace");
1610 let diff = buffer
1611 .handle
1612 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1613 .await;
1614 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1615 buffer.apply_diff(diff, cx);
1616 })?;
1617 }
1618
1619 if settings.ensure_final_newline_on_save {
1620 zlog::trace!(logger => "ensuring final newline");
1621 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1622 buffer.ensure_final_newline(cx);
1623 })?;
1624 }
1625
1626 // Formatter for `code_actions_on_format` that runs before
1627 // the rest of the formatters
1628 let mut code_actions_on_format_formatters = None;
1629 let should_run_code_actions_on_format = !matches!(
1630 (trigger, &settings.format_on_save),
1631 (FormatTrigger::Save, &FormatOnSave::Off)
1632 );
1633 if should_run_code_actions_on_format {
1634 let have_code_actions_to_run_on_format = settings
1635 .code_actions_on_format
1636 .values()
1637 .any(|enabled| *enabled);
1638 if have_code_actions_to_run_on_format {
1639 zlog::trace!(logger => "going to run code actions on format");
1640 code_actions_on_format_formatters = Some(
1641 settings
1642 .code_actions_on_format
1643 .iter()
1644 .filter_map(|(action, enabled)| enabled.then_some(action))
1645 .cloned()
1646 .map(Formatter::CodeAction)
1647 .collect::<Vec<_>>(),
1648 );
1649 }
1650 }
1651
1652 let formatters = match (trigger, &settings.format_on_save) {
1653 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1654 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1655 settings.formatter.as_ref()
1656 }
1657 };
1658
1659 let formatters = code_actions_on_format_formatters
1660 .iter()
1661 .flatten()
1662 .chain(formatters);
1663
1664 for formatter in formatters {
1665 let formatter = if formatter == &Formatter::Auto {
1666 if settings.prettier.allowed {
1667 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1668 &Formatter::Prettier
1669 } else {
1670 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1671 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1672 }
1673 } else {
1674 formatter
1675 };
1676 if let Err(err) = Self::apply_formatter(
1677 formatter,
1678 &lsp_store,
1679 buffer,
1680 formatting_transaction_id,
1681 &adapters_and_servers,
1682 &settings,
1683 request_timeout,
1684 logger,
1685 cx,
1686 )
1687 .await
1688 {
1689 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1690 }
1691 }
1692
1693 Ok(())
1694 }
1695
1696 async fn apply_formatter(
1697 formatter: &Formatter,
1698 lsp_store: &WeakEntity<LspStore>,
1699 buffer: &FormattableBuffer,
1700 formatting_transaction_id: clock::Lamport,
1701 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1702 settings: &LanguageSettings,
1703 request_timeout: Duration,
1704 logger: zlog::Logger,
1705 cx: &mut AsyncApp,
1706 ) -> anyhow::Result<()> {
1707 match formatter {
1708 Formatter::None => {
1709 zlog::trace!(logger => "skipping formatter 'none'");
1710 return Ok(());
1711 }
1712 Formatter::Auto => {
1713 debug_panic!("Auto resolved above");
1714 return Ok(());
1715 }
1716 Formatter::Prettier => {
1717 let logger = zlog::scoped!(logger => "prettier");
1718 zlog::trace!(logger => "formatting");
1719 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1720
1721 // When selection ranges are provided (via FormatSelections), we pass the
1722 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1723 // After diffing, we filter the resulting edits to only keep those that
1724 // overlap with the original byte-level selection ranges.
1725 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1726 Some(ranges) if !ranges.is_empty() => {
1727 let (utf16_range, byte_ranges) =
1728 buffer.handle.read_with(cx, |buffer, _cx| {
1729 let snapshot = buffer.snapshot();
1730 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1731 let mut max_end_utf16 = OffsetUtf16(0);
1732 let mut byte_ranges = Vec::with_capacity(ranges.len());
1733 for range in ranges {
1734 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1735 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1736 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1737 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1738
1739 let start_byte = range.start.to_offset(&snapshot);
1740 let end_byte = range.end.to_offset(&snapshot);
1741 byte_ranges.push(start_byte..end_byte);
1742 }
1743 (min_start_utf16..max_end_utf16, byte_ranges)
1744 });
1745 (Some(utf16_range), Some(byte_ranges))
1746 }
1747 _ => (None, None),
1748 };
1749
1750 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1751 lsp_store.prettier_store().unwrap().downgrade()
1752 })?;
1753 let diff = prettier_store::format_with_prettier(
1754 &prettier,
1755 &buffer.handle,
1756 range_utf16,
1757 cx,
1758 )
1759 .await
1760 .transpose()?;
1761 let Some(mut diff) = diff else {
1762 zlog::trace!(logger => "No changes");
1763 return Ok(());
1764 };
1765
1766 if let Some(byte_ranges) = byte_ranges {
1767 diff.edits.retain(|(edit_range, _)| {
1768 byte_ranges.iter().any(|selection_range| {
1769 edit_range.start < selection_range.end
1770 && edit_range.end > selection_range.start
1771 })
1772 });
1773 if diff.edits.is_empty() {
1774 zlog::trace!(logger => "No changes within selection");
1775 return Ok(());
1776 }
1777 }
1778
1779 extend_formatting_transaction(
1780 buffer,
1781 formatting_transaction_id,
1782 cx,
1783 |buffer, cx| {
1784 buffer.apply_diff(diff, cx);
1785 },
1786 )?;
1787 }
1788 Formatter::External { command, arguments } => {
1789 let logger = zlog::scoped!(logger => "command");
1790
1791 if buffer.ranges.is_some() {
1792 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1793 return Ok(());
1794 }
1795
1796 zlog::trace!(logger => "formatting");
1797 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1798
1799 let diff =
1800 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1801 .await
1802 .with_context(|| {
1803 format!("Failed to format buffer via external command: {}", command)
1804 })?;
1805 let Some(diff) = diff else {
1806 zlog::trace!(logger => "No changes");
1807 return Ok(());
1808 };
1809
1810 extend_formatting_transaction(
1811 buffer,
1812 formatting_transaction_id,
1813 cx,
1814 |buffer, cx| {
1815 buffer.apply_diff(diff, cx);
1816 },
1817 )?;
1818 }
1819 Formatter::LanguageServer(specifier) => {
1820 let logger = zlog::scoped!(logger => "language-server");
1821 zlog::trace!(logger => "formatting");
1822 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1823
1824 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1825 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1826 return Ok(());
1827 };
1828
1829 let language_server = match specifier {
1830 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1831 adapters_and_servers.iter().find_map(|(adapter, server)| {
1832 if adapter.name.0.as_ref() == name {
1833 Some(server.clone())
1834 } else {
1835 None
1836 }
1837 })
1838 }
1839 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1840 .iter()
1841 .find(|(_, server)| Self::server_supports_formatting(server))
1842 .map(|(_, server)| server.clone()),
1843 };
1844
1845 let Some(language_server) = language_server else {
1846 log::debug!(
1847 "No language server found to format buffer '{:?}'. Skipping",
1848 buffer_path_abs.as_path().to_string_lossy()
1849 );
1850 return Ok(());
1851 };
1852
1853 zlog::trace!(
1854 logger =>
1855 "Formatting buffer '{:?}' using language server '{:?}'",
1856 buffer_path_abs.as_path().to_string_lossy(),
1857 language_server.name()
1858 );
1859
1860 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1861 zlog::trace!(logger => "formatting ranges");
1862 Self::format_ranges_via_lsp(
1863 &lsp_store,
1864 &buffer.handle,
1865 ranges,
1866 buffer_path_abs,
1867 &language_server,
1868 &settings,
1869 cx,
1870 )
1871 .await
1872 .context("Failed to format ranges via language server")?
1873 } else {
1874 zlog::trace!(logger => "formatting full");
1875 Self::format_via_lsp(
1876 &lsp_store,
1877 &buffer.handle,
1878 buffer_path_abs,
1879 &language_server,
1880 &settings,
1881 cx,
1882 )
1883 .await
1884 .context("failed to format via language server")?
1885 };
1886
1887 if edits.is_empty() {
1888 zlog::trace!(logger => "No changes");
1889 return Ok(());
1890 }
1891 extend_formatting_transaction(
1892 buffer,
1893 formatting_transaction_id,
1894 cx,
1895 |buffer, cx| {
1896 buffer.edit(edits, None, cx);
1897 },
1898 )?;
1899 }
1900 Formatter::CodeAction(code_action_name) => {
1901 let logger = zlog::scoped!(logger => "code-actions");
1902 zlog::trace!(logger => "formatting");
1903 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1904
1905 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1906 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1907 return Ok(());
1908 };
1909
1910 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1911 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1912
1913 let mut actions_and_servers = Vec::new();
1914
1915 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1916 let actions_result = Self::get_server_code_actions_from_action_kinds(
1917 &lsp_store,
1918 language_server.server_id(),
1919 vec![code_action_kind.clone()],
1920 &buffer.handle,
1921 cx,
1922 )
1923 .await
1924 .with_context(|| {
1925 format!(
1926 "Failed to resolve code action {:?} with language server {}",
1927 code_action_kind,
1928 language_server.name()
1929 )
1930 });
1931 let Ok(actions) = actions_result else {
1932 // note: it may be better to set result to the error and break formatters here
1933 // but for now we try to execute the actions that we can resolve and skip the rest
1934 zlog::error!(
1935 logger =>
1936 "Failed to resolve code action {:?} with language server {}",
1937 code_action_kind,
1938 language_server.name()
1939 );
1940 continue;
1941 };
1942 for action in actions {
1943 actions_and_servers.push((action, index));
1944 }
1945 }
1946
1947 if actions_and_servers.is_empty() {
1948 zlog::warn!(logger => "No code actions were resolved, continuing");
1949 return Ok(());
1950 }
1951
1952 'actions: for (mut action, server_index) in actions_and_servers {
1953 let server = &adapters_and_servers[server_index].1;
1954
1955 let describe_code_action = |action: &CodeAction| {
1956 format!(
1957 "code action '{}' with title \"{}\" on server {}",
1958 action
1959 .lsp_action
1960 .action_kind()
1961 .unwrap_or("unknown".into())
1962 .as_str(),
1963 action.lsp_action.title(),
1964 server.name(),
1965 )
1966 };
1967
1968 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1969
1970 if let Err(err) =
1971 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1972 {
1973 zlog::error!(
1974 logger =>
1975 "Failed to resolve {}. Error: {}",
1976 describe_code_action(&action),
1977 err
1978 );
1979 continue;
1980 }
1981
1982 if let Some(edit) = action.lsp_action.edit().cloned() {
1983 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1984 // but filters out and logs warnings for code actions that require unreasonably
1985 // difficult handling on our part, such as:
1986 // - applying edits that call commands
1987 // which can result in arbitrary workspace edits being sent from the server that
1988 // have no way of being tied back to the command that initiated them (i.e. we
1989 // can't know which edits are part of the format request, or if the server is done sending
1990 // actions in response to the command)
1991 // - actions that create/delete/modify/rename files other than the one we are formatting
1992 // as we then would need to handle such changes correctly in the local history as well
1993 // as the remote history through the ProjectTransaction
1994 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1995 // Supporting these actions is not impossible, but not supported as of yet.
1996 if edit.changes.is_none() && edit.document_changes.is_none() {
1997 zlog::trace!(
1998 logger =>
1999 "No changes for code action. Skipping {}",
2000 describe_code_action(&action),
2001 );
2002 continue;
2003 }
2004
2005 let mut operations = Vec::new();
2006 if let Some(document_changes) = edit.document_changes {
2007 match document_changes {
2008 lsp::DocumentChanges::Edits(edits) => operations.extend(
2009 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2010 ),
2011 lsp::DocumentChanges::Operations(ops) => operations = ops,
2012 }
2013 } else if let Some(changes) = edit.changes {
2014 operations.extend(changes.into_iter().map(|(uri, edits)| {
2015 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2016 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2017 uri,
2018 version: None,
2019 },
2020 edits: edits.into_iter().map(Edit::Plain).collect(),
2021 })
2022 }));
2023 }
2024
2025 let mut edits = Vec::with_capacity(operations.len());
2026
2027 if operations.is_empty() {
2028 zlog::trace!(
2029 logger =>
2030 "No changes for code action. Skipping {}",
2031 describe_code_action(&action),
2032 );
2033 continue;
2034 }
2035 for operation in operations {
2036 let op = match operation {
2037 lsp::DocumentChangeOperation::Edit(op) => op,
2038 lsp::DocumentChangeOperation::Op(_) => {
2039 zlog::warn!(
2040 logger =>
2041 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2042 describe_code_action(&action),
2043 );
2044 continue 'actions;
2045 }
2046 };
2047 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2048 zlog::warn!(
2049 logger =>
2050 "Failed to convert URI '{:?}' to file path. Skipping {}",
2051 &op.text_document.uri,
2052 describe_code_action(&action),
2053 );
2054 continue 'actions;
2055 };
2056 if &file_path != buffer_path_abs {
2057 zlog::warn!(
2058 logger =>
2059 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2060 file_path,
2061 buffer_path_abs,
2062 describe_code_action(&action),
2063 );
2064 continue 'actions;
2065 }
2066
2067 let mut lsp_edits = Vec::new();
2068 for edit in op.edits {
2069 match edit {
2070 Edit::Plain(edit) => {
2071 if !lsp_edits.contains(&edit) {
2072 lsp_edits.push(edit);
2073 }
2074 }
2075 Edit::Annotated(edit) => {
2076 if !lsp_edits.contains(&edit.text_edit) {
2077 lsp_edits.push(edit.text_edit);
2078 }
2079 }
2080 Edit::Snippet(_) => {
2081 zlog::warn!(
2082 logger =>
2083 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2084 describe_code_action(&action),
2085 );
2086 continue 'actions;
2087 }
2088 }
2089 }
2090 let edits_result = lsp_store
2091 .update(cx, |lsp_store, cx| {
2092 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2093 &buffer.handle,
2094 lsp_edits,
2095 server.server_id(),
2096 op.text_document.version,
2097 cx,
2098 )
2099 })?
2100 .await;
2101 let Ok(resolved_edits) = edits_result else {
2102 zlog::warn!(
2103 logger =>
2104 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2105 buffer_path_abs.as_path(),
2106 describe_code_action(&action),
2107 );
2108 continue 'actions;
2109 };
2110 edits.extend(resolved_edits);
2111 }
2112
2113 if edits.is_empty() {
2114 zlog::warn!(logger => "No edits resolved from LSP");
2115 continue;
2116 }
2117
2118 extend_formatting_transaction(
2119 buffer,
2120 formatting_transaction_id,
2121 cx,
2122 |buffer, cx| {
2123 zlog::info!(
2124 "Applying edits {edits:?}. Content: {:?}",
2125 buffer.text()
2126 );
2127 buffer.edit(edits, None, cx);
2128 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2129 },
2130 )?;
2131 }
2132
2133 let Some(command) = action.lsp_action.command() else {
2134 continue;
2135 };
2136
2137 zlog::warn!(
2138 logger =>
2139 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2140 &command.command,
2141 );
2142
2143 let server_capabilities = server.capabilities();
2144 let available_commands = server_capabilities
2145 .execute_command_provider
2146 .as_ref()
2147 .map(|options| options.commands.as_slice())
2148 .unwrap_or_default();
2149 if !available_commands.contains(&command.command) {
2150 zlog::warn!(
2151 logger =>
2152 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2153 command.command,
2154 server.name(),
2155 );
2156 continue;
2157 }
2158
2159 extend_formatting_transaction(
2160 buffer,
2161 formatting_transaction_id,
2162 cx,
2163 |_, _| {},
2164 )?;
2165 zlog::info!(logger => "Executing command {}", &command.command);
2166
2167 lsp_store.update(cx, |this, _| {
2168 this.as_local_mut()
2169 .unwrap()
2170 .last_workspace_edits_by_language_server
2171 .remove(&server.server_id());
2172 })?;
2173
2174 let execute_command_result = server
2175 .request::<lsp::request::ExecuteCommand>(
2176 lsp::ExecuteCommandParams {
2177 command: command.command.clone(),
2178 arguments: command.arguments.clone().unwrap_or_default(),
2179 ..Default::default()
2180 },
2181 request_timeout,
2182 )
2183 .await
2184 .into_response();
2185
2186 if execute_command_result.is_err() {
2187 zlog::error!(
2188 logger =>
2189 "Failed to execute command '{}' as part of {}",
2190 &command.command,
2191 describe_code_action(&action),
2192 );
2193 continue 'actions;
2194 }
2195
2196 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2197 this.as_local_mut()
2198 .unwrap()
2199 .last_workspace_edits_by_language_server
2200 .remove(&server.server_id())
2201 .unwrap_or_default()
2202 })?;
2203
2204 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2205 {
2206 zlog::trace!(
2207 logger =>
2208 "Successfully captured {} edits that resulted from command {}",
2209 transaction.edit_ids.len(),
2210 &command.command,
2211 );
2212 let transaction_id_project_transaction = transaction.id;
2213 buffer.handle.update(cx, |buffer, _| {
2214 // it may have been removed from history if push_to_history was
2215 // false in deserialize_workspace_edit. If so push it so we
2216 // can merge it with the format transaction
2217 // and pop the combined transaction off the history stack
2218 // later if push_to_history is false
2219 if buffer.get_transaction(transaction.id).is_none() {
2220 buffer.push_transaction(transaction, Instant::now());
2221 }
2222 buffer.merge_transactions(
2223 transaction_id_project_transaction,
2224 formatting_transaction_id,
2225 );
2226 });
2227 }
2228
2229 if project_transaction_command.0.is_empty() {
2230 continue;
2231 }
2232
2233 let mut extra_buffers = String::new();
2234 for buffer in project_transaction_command.0.keys() {
2235 buffer.read_with(cx, |b, cx| {
2236 let Some(path) = b.project_path(cx) else {
2237 return;
2238 };
2239
2240 if !extra_buffers.is_empty() {
2241 extra_buffers.push_str(", ");
2242 }
2243 extra_buffers.push_str(path.path.as_unix_str());
2244 });
2245 }
2246 zlog::warn!(
2247 logger =>
2248 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2249 &command.command,
2250 extra_buffers,
2251 );
2252 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2253 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2254 // add it so it's included, and merge it into the format transaction when its created later
2255 }
2256 }
2257 }
2258
2259 Ok(())
2260 }
2261
2262 pub async fn format_ranges_via_lsp(
2263 this: &WeakEntity<LspStore>,
2264 buffer_handle: &Entity<Buffer>,
2265 ranges: &[Range<Anchor>],
2266 abs_path: &Path,
2267 language_server: &Arc<LanguageServer>,
2268 settings: &LanguageSettings,
2269 cx: &mut AsyncApp,
2270 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2271 let capabilities = &language_server.capabilities();
2272 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2273 if range_formatting_provider == Some(&OneOf::Left(false)) {
2274 anyhow::bail!(
2275 "{} language server does not support range formatting",
2276 language_server.name()
2277 );
2278 }
2279
2280 let uri = file_path_to_lsp_url(abs_path)?;
2281 let text_document = lsp::TextDocumentIdentifier::new(uri);
2282
2283 let request_timeout = cx.update(|app| {
2284 ProjectSettings::get_global(app)
2285 .global_lsp_settings
2286 .get_request_timeout()
2287 });
2288 let lsp_edits = {
2289 let mut lsp_ranges = Vec::new();
2290 this.update(cx, |_this, cx| {
2291 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2292 // not have been sent to the language server. This seems like a fairly systemic
2293 // issue, though, the resolution probably is not specific to formatting.
2294 //
2295 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2296 // LSP.
2297 let snapshot = buffer_handle.read(cx).snapshot();
2298 for range in ranges {
2299 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2300 }
2301 anyhow::Ok(())
2302 })??;
2303
2304 let mut edits = None;
2305 for range in lsp_ranges {
2306 if let Some(mut edit) = language_server
2307 .request::<lsp::request::RangeFormatting>(
2308 lsp::DocumentRangeFormattingParams {
2309 text_document: text_document.clone(),
2310 range,
2311 options: lsp_command::lsp_formatting_options(settings),
2312 work_done_progress_params: Default::default(),
2313 },
2314 request_timeout,
2315 )
2316 .await
2317 .into_response()?
2318 {
2319 edits.get_or_insert_with(Vec::new).append(&mut edit);
2320 }
2321 }
2322 edits
2323 };
2324
2325 if let Some(lsp_edits) = lsp_edits {
2326 this.update(cx, |this, cx| {
2327 this.as_local_mut().unwrap().edits_from_lsp(
2328 buffer_handle,
2329 lsp_edits,
2330 language_server.server_id(),
2331 None,
2332 cx,
2333 )
2334 })?
2335 .await
2336 } else {
2337 Ok(Vec::with_capacity(0))
2338 }
2339 }
2340
2341 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2342 let capabilities = server.capabilities();
2343 let formatting = capabilities.document_formatting_provider.as_ref();
2344 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2345 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2346 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2347 }
2348
2349 async fn format_via_lsp(
2350 this: &WeakEntity<LspStore>,
2351 buffer: &Entity<Buffer>,
2352 abs_path: &Path,
2353 language_server: &Arc<LanguageServer>,
2354 settings: &LanguageSettings,
2355 cx: &mut AsyncApp,
2356 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2357 let logger = zlog::scoped!("lsp_format");
2358 zlog::debug!(logger => "Formatting via LSP");
2359
2360 let uri = file_path_to_lsp_url(abs_path)?;
2361 let text_document = lsp::TextDocumentIdentifier::new(uri);
2362 let capabilities = &language_server.capabilities();
2363
2364 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2365 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2366
2367 let request_timeout = cx.update(|app| {
2368 ProjectSettings::get_global(app)
2369 .global_lsp_settings
2370 .get_request_timeout()
2371 });
2372
2373 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2374 let _timer = zlog::time!(logger => "format-full");
2375 language_server
2376 .request::<lsp::request::Formatting>(
2377 lsp::DocumentFormattingParams {
2378 text_document,
2379 options: lsp_command::lsp_formatting_options(settings),
2380 work_done_progress_params: Default::default(),
2381 },
2382 request_timeout,
2383 )
2384 .await
2385 .into_response()?
2386 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2387 let _timer = zlog::time!(logger => "format-range");
2388 let buffer_start = lsp::Position::new(0, 0);
2389 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2390 language_server
2391 .request::<lsp::request::RangeFormatting>(
2392 lsp::DocumentRangeFormattingParams {
2393 text_document: text_document.clone(),
2394 range: lsp::Range::new(buffer_start, buffer_end),
2395 options: lsp_command::lsp_formatting_options(settings),
2396 work_done_progress_params: Default::default(),
2397 },
2398 request_timeout,
2399 )
2400 .await
2401 .into_response()?
2402 } else {
2403 None
2404 };
2405
2406 if let Some(lsp_edits) = lsp_edits {
2407 this.update(cx, |this, cx| {
2408 this.as_local_mut().unwrap().edits_from_lsp(
2409 buffer,
2410 lsp_edits,
2411 language_server.server_id(),
2412 None,
2413 cx,
2414 )
2415 })?
2416 .await
2417 } else {
2418 Ok(Vec::with_capacity(0))
2419 }
2420 }
2421
2422 async fn format_via_external_command(
2423 buffer: &FormattableBuffer,
2424 command: &str,
2425 arguments: Option<&[String]>,
2426 cx: &mut AsyncApp,
2427 ) -> Result<Option<Diff>> {
2428 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2429 let file = File::from_dyn(buffer.file())?;
2430 let worktree = file.worktree.read(cx);
2431 let mut worktree_path = worktree.abs_path().to_path_buf();
2432 if worktree.root_entry()?.is_file() {
2433 worktree_path.pop();
2434 }
2435 Some(worktree_path)
2436 });
2437
2438 use util::command::Stdio;
2439 let mut child = util::command::new_command(command);
2440
2441 if let Some(buffer_env) = buffer.env.as_ref() {
2442 child.envs(buffer_env);
2443 }
2444
2445 if let Some(working_dir_path) = working_dir_path {
2446 child.current_dir(working_dir_path);
2447 }
2448
2449 if let Some(arguments) = arguments {
2450 child.args(arguments.iter().map(|arg| {
2451 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2452 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2453 } else {
2454 arg.replace("{buffer_path}", "Untitled")
2455 }
2456 }));
2457 }
2458
2459 let mut child = child
2460 .stdin(Stdio::piped())
2461 .stdout(Stdio::piped())
2462 .stderr(Stdio::piped())
2463 .spawn()?;
2464
2465 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2466 let text = buffer
2467 .handle
2468 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2469 for chunk in text.chunks() {
2470 stdin.write_all(chunk.as_bytes()).await?;
2471 }
2472 stdin.flush().await?;
2473
2474 let output = child.output().await?;
2475 anyhow::ensure!(
2476 output.status.success(),
2477 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2478 output.status.code(),
2479 String::from_utf8_lossy(&output.stdout),
2480 String::from_utf8_lossy(&output.stderr),
2481 );
2482
2483 let stdout = String::from_utf8(output.stdout)?;
2484 Ok(Some(
2485 buffer
2486 .handle
2487 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2488 .await,
2489 ))
2490 }
2491
2492 async fn try_resolve_code_action(
2493 lang_server: &LanguageServer,
2494 action: &mut CodeAction,
2495 request_timeout: Duration,
2496 ) -> anyhow::Result<()> {
2497 match &mut action.lsp_action {
2498 LspAction::Action(lsp_action) => {
2499 if !action.resolved
2500 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2501 && lsp_action.data.is_some()
2502 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2503 {
2504 **lsp_action = lang_server
2505 .request::<lsp::request::CodeActionResolveRequest>(
2506 *lsp_action.clone(),
2507 request_timeout,
2508 )
2509 .await
2510 .into_response()?;
2511 }
2512 }
2513 LspAction::CodeLens(lens) => {
2514 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2515 *lens = lang_server
2516 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2517 .await
2518 .into_response()?;
2519 }
2520 }
2521 LspAction::Command(_) => {}
2522 }
2523
2524 action.resolved = true;
2525 anyhow::Ok(())
2526 }
2527
2528 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2529 let buffer = buffer_handle.read(cx);
2530
2531 let file = buffer.file().cloned();
2532
2533 let Some(file) = File::from_dyn(file.as_ref()) else {
2534 return;
2535 };
2536 if !file.is_local() {
2537 return;
2538 }
2539 let path = ProjectPath::from_file(file, cx);
2540 let worktree_id = file.worktree_id(cx);
2541 let language = buffer.language().cloned();
2542
2543 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2544 for (server_id, diagnostics) in
2545 diagnostics.get(file.path()).cloned().unwrap_or_default()
2546 {
2547 self.update_buffer_diagnostics(
2548 buffer_handle,
2549 server_id,
2550 None,
2551 None,
2552 None,
2553 Vec::new(),
2554 diagnostics,
2555 cx,
2556 )
2557 .log_err();
2558 }
2559 }
2560 let Some(language) = language else {
2561 return;
2562 };
2563 let Some(snapshot) = self
2564 .worktree_store
2565 .read(cx)
2566 .worktree_for_id(worktree_id, cx)
2567 .map(|worktree| worktree.read(cx).snapshot())
2568 else {
2569 return;
2570 };
2571 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2572
2573 for server_id in
2574 self.lsp_tree
2575 .get(path, language.name(), language.manifest(), &delegate, cx)
2576 {
2577 let server = self
2578 .language_servers
2579 .get(&server_id)
2580 .and_then(|server_state| {
2581 if let LanguageServerState::Running { server, .. } = server_state {
2582 Some(server.clone())
2583 } else {
2584 None
2585 }
2586 });
2587 let server = match server {
2588 Some(server) => server,
2589 None => continue,
2590 };
2591
2592 buffer_handle.update(cx, |buffer, cx| {
2593 buffer.set_completion_triggers(
2594 server.server_id(),
2595 server
2596 .capabilities()
2597 .completion_provider
2598 .as_ref()
2599 .and_then(|provider| {
2600 provider
2601 .trigger_characters
2602 .as_ref()
2603 .map(|characters| characters.iter().cloned().collect())
2604 })
2605 .unwrap_or_default(),
2606 cx,
2607 );
2608 });
2609 }
2610 }
2611
2612 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2613 buffer.update(cx, |buffer, cx| {
2614 let Some(language) = buffer.language() else {
2615 return;
2616 };
2617 let path = ProjectPath {
2618 worktree_id: old_file.worktree_id(cx),
2619 path: old_file.path.clone(),
2620 };
2621 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2622 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2623 buffer.set_completion_triggers(server_id, Default::default(), cx);
2624 }
2625 });
2626 }
2627
2628 fn update_buffer_diagnostics(
2629 &mut self,
2630 buffer: &Entity<Buffer>,
2631 server_id: LanguageServerId,
2632 registration_id: Option<Option<SharedString>>,
2633 result_id: Option<SharedString>,
2634 version: Option<i32>,
2635 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2636 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2637 cx: &mut Context<LspStore>,
2638 ) -> Result<()> {
2639 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2640 Ordering::Equal
2641 .then_with(|| b.is_primary.cmp(&a.is_primary))
2642 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2643 .then_with(|| a.severity.cmp(&b.severity))
2644 .then_with(|| a.message.cmp(&b.message))
2645 }
2646
2647 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2648 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2649 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2650
2651 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2652 Ordering::Equal
2653 .then_with(|| a.range.start.cmp(&b.range.start))
2654 .then_with(|| b.range.end.cmp(&a.range.end))
2655 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2656 });
2657
2658 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2659
2660 let edits_since_save = std::cell::LazyCell::new(|| {
2661 let saved_version = buffer.read(cx).saved_version();
2662 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2663 });
2664
2665 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2666
2667 for (new_diagnostic, entry) in diagnostics {
2668 let start;
2669 let end;
2670 if new_diagnostic && entry.diagnostic.is_disk_based {
2671 // Some diagnostics are based on files on disk instead of buffers'
2672 // current contents. Adjust these diagnostics' ranges to reflect
2673 // any unsaved edits.
2674 // Do not alter the reused ones though, as their coordinates were stored as anchors
2675 // and were properly adjusted on reuse.
2676 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2677 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2678 } else {
2679 start = entry.range.start;
2680 end = entry.range.end;
2681 }
2682
2683 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2684 ..snapshot.clip_point_utf16(end, Bias::Right);
2685
2686 // Expand empty ranges by one codepoint
2687 if range.start == range.end {
2688 // This will be go to the next boundary when being clipped
2689 range.end.column += 1;
2690 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2691 if range.start == range.end && range.end.column > 0 {
2692 range.start.column -= 1;
2693 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2694 }
2695 }
2696
2697 sanitized_diagnostics.push(DiagnosticEntry {
2698 range,
2699 diagnostic: entry.diagnostic,
2700 });
2701 }
2702 drop(edits_since_save);
2703
2704 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2705 buffer.update(cx, |buffer, cx| {
2706 if let Some(registration_id) = registration_id {
2707 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2708 self.buffer_pull_diagnostics_result_ids
2709 .entry(server_id)
2710 .or_default()
2711 .entry(registration_id)
2712 .or_default()
2713 .insert(abs_path, result_id);
2714 }
2715 }
2716
2717 buffer.update_diagnostics(server_id, set, cx)
2718 });
2719
2720 Ok(())
2721 }
2722
2723 fn register_language_server_for_invisible_worktree(
2724 &mut self,
2725 worktree: &Entity<Worktree>,
2726 language_server_id: LanguageServerId,
2727 cx: &mut App,
2728 ) {
2729 let worktree = worktree.read(cx);
2730 let worktree_id = worktree.id();
2731 debug_assert!(!worktree.is_visible());
2732 let Some(mut origin_seed) = self
2733 .language_server_ids
2734 .iter()
2735 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2736 else {
2737 return;
2738 };
2739 origin_seed.worktree_id = worktree_id;
2740 self.language_server_ids
2741 .entry(origin_seed)
2742 .or_insert_with(|| UnifiedLanguageServer {
2743 id: language_server_id,
2744 project_roots: Default::default(),
2745 });
2746 }
2747
2748 fn register_buffer_with_language_servers(
2749 &mut self,
2750 buffer_handle: &Entity<Buffer>,
2751 only_register_servers: HashSet<LanguageServerSelector>,
2752 cx: &mut Context<LspStore>,
2753 ) {
2754 let buffer = buffer_handle.read(cx);
2755 let buffer_id = buffer.remote_id();
2756
2757 let Some(file) = File::from_dyn(buffer.file()) else {
2758 return;
2759 };
2760 if !file.is_local() {
2761 return;
2762 }
2763
2764 let abs_path = file.abs_path(cx);
2765 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2766 return;
2767 };
2768 let initial_snapshot = buffer.text_snapshot();
2769 let worktree_id = file.worktree_id(cx);
2770
2771 let Some(language) = buffer.language().cloned() else {
2772 return;
2773 };
2774 let path: Arc<RelPath> = file
2775 .path()
2776 .parent()
2777 .map(Arc::from)
2778 .unwrap_or_else(|| file.path().clone());
2779 let Some(worktree) = self
2780 .worktree_store
2781 .read(cx)
2782 .worktree_for_id(worktree_id, cx)
2783 else {
2784 return;
2785 };
2786 let language_name = language.name();
2787 let (reused, delegate, servers) = self
2788 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2789 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2790 .unwrap_or_else(|| {
2791 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2792 let delegate: Arc<dyn ManifestDelegate> =
2793 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2794
2795 let servers = self
2796 .lsp_tree
2797 .walk(
2798 ProjectPath { worktree_id, path },
2799 language.name(),
2800 language.manifest(),
2801 &delegate,
2802 cx,
2803 )
2804 .collect::<Vec<_>>();
2805 (false, lsp_delegate, servers)
2806 });
2807 let servers_and_adapters = servers
2808 .into_iter()
2809 .filter_map(|server_node| {
2810 if reused && server_node.server_id().is_none() {
2811 return None;
2812 }
2813 if !only_register_servers.is_empty() {
2814 if let Some(server_id) = server_node.server_id()
2815 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2816 {
2817 return None;
2818 }
2819 if let Some(name) = server_node.name()
2820 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2821 {
2822 return None;
2823 }
2824 }
2825
2826 let server_id = server_node.server_id_or_init(|disposition| {
2827 let path = &disposition.path;
2828
2829 {
2830 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2831
2832 let server_id = self.get_or_insert_language_server(
2833 &worktree,
2834 delegate.clone(),
2835 disposition,
2836 &language_name,
2837 cx,
2838 );
2839
2840 if let Some(state) = self.language_servers.get(&server_id)
2841 && let Ok(uri) = uri
2842 {
2843 state.add_workspace_folder(uri);
2844 };
2845 server_id
2846 }
2847 })?;
2848 let server_state = self.language_servers.get(&server_id)?;
2849 if let LanguageServerState::Running {
2850 server, adapter, ..
2851 } = server_state
2852 {
2853 Some((server.clone(), adapter.clone()))
2854 } else {
2855 None
2856 }
2857 })
2858 .collect::<Vec<_>>();
2859 for (server, adapter) in servers_and_adapters {
2860 buffer_handle.update(cx, |buffer, cx| {
2861 buffer.set_completion_triggers(
2862 server.server_id(),
2863 server
2864 .capabilities()
2865 .completion_provider
2866 .as_ref()
2867 .and_then(|provider| {
2868 provider
2869 .trigger_characters
2870 .as_ref()
2871 .map(|characters| characters.iter().cloned().collect())
2872 })
2873 .unwrap_or_default(),
2874 cx,
2875 );
2876 });
2877
2878 let snapshot = LspBufferSnapshot {
2879 version: 0,
2880 snapshot: initial_snapshot.clone(),
2881 };
2882
2883 let mut registered = false;
2884 self.buffer_snapshots
2885 .entry(buffer_id)
2886 .or_default()
2887 .entry(server.server_id())
2888 .or_insert_with(|| {
2889 registered = true;
2890 server.register_buffer(
2891 uri.clone(),
2892 adapter.language_id(&language.name()),
2893 0,
2894 initial_snapshot.text(),
2895 );
2896
2897 vec![snapshot]
2898 });
2899
2900 self.buffers_opened_in_servers
2901 .entry(buffer_id)
2902 .or_default()
2903 .insert(server.server_id());
2904 if registered {
2905 cx.emit(LspStoreEvent::LanguageServerUpdate {
2906 language_server_id: server.server_id(),
2907 name: None,
2908 message: proto::update_language_server::Variant::RegisteredForBuffer(
2909 proto::RegisteredForBuffer {
2910 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2911 buffer_id: buffer_id.to_proto(),
2912 },
2913 ),
2914 });
2915 }
2916 }
2917 }
2918
2919 fn reuse_existing_language_server<'lang_name>(
2920 &self,
2921 server_tree: &LanguageServerTree,
2922 worktree: &Entity<Worktree>,
2923 language_name: &'lang_name LanguageName,
2924 cx: &mut App,
2925 ) -> Option<(
2926 Arc<LocalLspAdapterDelegate>,
2927 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2928 )> {
2929 if worktree.read(cx).is_visible() {
2930 return None;
2931 }
2932
2933 let worktree_store = self.worktree_store.read(cx);
2934 let servers = server_tree
2935 .instances
2936 .iter()
2937 .filter(|(worktree_id, _)| {
2938 worktree_store
2939 .worktree_for_id(**worktree_id, cx)
2940 .is_some_and(|worktree| worktree.read(cx).is_visible())
2941 })
2942 .flat_map(|(worktree_id, servers)| {
2943 servers
2944 .roots
2945 .iter()
2946 .flat_map(|(_, language_servers)| language_servers)
2947 .map(move |(_, (server_node, server_languages))| {
2948 (worktree_id, server_node, server_languages)
2949 })
2950 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2951 .map(|(worktree_id, server_node, _)| {
2952 (
2953 *worktree_id,
2954 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2955 )
2956 })
2957 })
2958 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2959 acc.entry(worktree_id)
2960 .or_insert_with(Vec::new)
2961 .push(server_node);
2962 acc
2963 })
2964 .into_values()
2965 .max_by_key(|servers| servers.len())?;
2966
2967 let worktree_id = worktree.read(cx).id();
2968 let apply = move |tree: &mut LanguageServerTree| {
2969 for server_node in &servers {
2970 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2971 }
2972 servers
2973 };
2974
2975 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2976 Some((delegate, apply))
2977 }
2978
2979 pub(crate) fn unregister_old_buffer_from_language_servers(
2980 &mut self,
2981 buffer: &Entity<Buffer>,
2982 old_file: &File,
2983 cx: &mut App,
2984 ) {
2985 let old_path = match old_file.as_local() {
2986 Some(local) => local.abs_path(cx),
2987 None => return,
2988 };
2989
2990 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2991 debug_panic!("{old_path:?} is not parseable as an URI");
2992 return;
2993 };
2994 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2995 }
2996
2997 pub(crate) fn unregister_buffer_from_language_servers(
2998 &mut self,
2999 buffer: &Entity<Buffer>,
3000 file_url: &lsp::Uri,
3001 cx: &mut App,
3002 ) {
3003 buffer.update(cx, |buffer, cx| {
3004 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3005
3006 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3007 if snapshots
3008 .as_mut()
3009 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3010 {
3011 language_server.unregister_buffer(file_url.clone());
3012 }
3013 }
3014 });
3015 }
3016
3017 fn buffer_snapshot_for_lsp_version(
3018 &mut self,
3019 buffer: &Entity<Buffer>,
3020 server_id: LanguageServerId,
3021 version: Option<i32>,
3022 cx: &App,
3023 ) -> Result<TextBufferSnapshot> {
3024 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3025
3026 if let Some(version) = version {
3027 let buffer_id = buffer.read(cx).remote_id();
3028 let snapshots = if let Some(snapshots) = self
3029 .buffer_snapshots
3030 .get_mut(&buffer_id)
3031 .and_then(|m| m.get_mut(&server_id))
3032 {
3033 snapshots
3034 } else if version == 0 {
3035 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3036 // We detect this case and treat it as if the version was `None`.
3037 return Ok(buffer.read(cx).text_snapshot());
3038 } else {
3039 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3040 };
3041
3042 let found_snapshot = snapshots
3043 .binary_search_by_key(&version, |e| e.version)
3044 .map(|ix| snapshots[ix].snapshot.clone())
3045 .map_err(|_| {
3046 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3047 })?;
3048
3049 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3050 Ok(found_snapshot)
3051 } else {
3052 Ok((buffer.read(cx)).text_snapshot())
3053 }
3054 }
3055
3056 async fn get_server_code_actions_from_action_kinds(
3057 lsp_store: &WeakEntity<LspStore>,
3058 language_server_id: LanguageServerId,
3059 code_action_kinds: Vec<lsp::CodeActionKind>,
3060 buffer: &Entity<Buffer>,
3061 cx: &mut AsyncApp,
3062 ) -> Result<Vec<CodeAction>> {
3063 let actions = lsp_store
3064 .update(cx, move |this, cx| {
3065 let request = GetCodeActions {
3066 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3067 kinds: Some(code_action_kinds),
3068 };
3069 let server = LanguageServerToQuery::Other(language_server_id);
3070 this.request_lsp(buffer.clone(), server, request, cx)
3071 })?
3072 .await?;
3073 Ok(actions)
3074 }
3075
3076 pub async fn execute_code_actions_on_server(
3077 lsp_store: &WeakEntity<LspStore>,
3078 language_server: &Arc<LanguageServer>,
3079 actions: Vec<CodeAction>,
3080 push_to_history: bool,
3081 project_transaction: &mut ProjectTransaction,
3082 cx: &mut AsyncApp,
3083 ) -> anyhow::Result<()> {
3084 let request_timeout = cx.update(|app| {
3085 ProjectSettings::get_global(app)
3086 .global_lsp_settings
3087 .get_request_timeout()
3088 });
3089
3090 for mut action in actions {
3091 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3092 .await
3093 .context("resolving a formatting code action")?;
3094
3095 if let Some(edit) = action.lsp_action.edit() {
3096 if edit.changes.is_none() && edit.document_changes.is_none() {
3097 continue;
3098 }
3099
3100 let new = Self::deserialize_workspace_edit(
3101 lsp_store.upgrade().context("project dropped")?,
3102 edit.clone(),
3103 push_to_history,
3104 language_server.clone(),
3105 cx,
3106 )
3107 .await?;
3108 project_transaction.0.extend(new.0);
3109 }
3110
3111 let Some(command) = action.lsp_action.command() else {
3112 continue;
3113 };
3114
3115 let server_capabilities = language_server.capabilities();
3116 let available_commands = server_capabilities
3117 .execute_command_provider
3118 .as_ref()
3119 .map(|options| options.commands.as_slice())
3120 .unwrap_or_default();
3121 if !available_commands.contains(&command.command) {
3122 log::warn!(
3123 "Cannot execute a command {} not listed in the language server capabilities",
3124 command.command
3125 );
3126 continue;
3127 }
3128
3129 lsp_store.update(cx, |lsp_store, _| {
3130 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3131 mode.last_workspace_edits_by_language_server
3132 .remove(&language_server.server_id());
3133 }
3134 })?;
3135
3136 language_server
3137 .request::<lsp::request::ExecuteCommand>(
3138 lsp::ExecuteCommandParams {
3139 command: command.command.clone(),
3140 arguments: command.arguments.clone().unwrap_or_default(),
3141 ..Default::default()
3142 },
3143 request_timeout,
3144 )
3145 .await
3146 .into_response()
3147 .context("execute command")?;
3148
3149 lsp_store.update(cx, |this, _| {
3150 if let LspStoreMode::Local(mode) = &mut this.mode {
3151 project_transaction.0.extend(
3152 mode.last_workspace_edits_by_language_server
3153 .remove(&language_server.server_id())
3154 .unwrap_or_default()
3155 .0,
3156 )
3157 }
3158 })?;
3159 }
3160 Ok(())
3161 }
3162
3163 pub async fn deserialize_text_edits(
3164 this: Entity<LspStore>,
3165 buffer_to_edit: Entity<Buffer>,
3166 edits: Vec<lsp::TextEdit>,
3167 push_to_history: bool,
3168 _: Arc<CachedLspAdapter>,
3169 language_server: Arc<LanguageServer>,
3170 cx: &mut AsyncApp,
3171 ) -> Result<Option<Transaction>> {
3172 let edits = this
3173 .update(cx, |this, cx| {
3174 this.as_local_mut().unwrap().edits_from_lsp(
3175 &buffer_to_edit,
3176 edits,
3177 language_server.server_id(),
3178 None,
3179 cx,
3180 )
3181 })
3182 .await?;
3183
3184 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3185 buffer.finalize_last_transaction();
3186 buffer.start_transaction();
3187 for (range, text) in edits {
3188 buffer.edit([(range, text)], None, cx);
3189 }
3190
3191 if buffer.end_transaction(cx).is_some() {
3192 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3193 if !push_to_history {
3194 buffer.forget_transaction(transaction.id);
3195 }
3196 Some(transaction)
3197 } else {
3198 None
3199 }
3200 });
3201
3202 Ok(transaction)
3203 }
3204
3205 #[allow(clippy::type_complexity)]
3206 pub fn edits_from_lsp(
3207 &mut self,
3208 buffer: &Entity<Buffer>,
3209 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3210 server_id: LanguageServerId,
3211 version: Option<i32>,
3212 cx: &mut Context<LspStore>,
3213 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3214 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3215 cx.background_spawn(async move {
3216 let snapshot = snapshot?;
3217 let mut lsp_edits = lsp_edits
3218 .into_iter()
3219 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3220 .collect::<Vec<_>>();
3221
3222 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3223
3224 let mut lsp_edits = lsp_edits.into_iter().peekable();
3225 let mut edits = Vec::new();
3226 while let Some((range, mut new_text)) = lsp_edits.next() {
3227 // Clip invalid ranges provided by the language server.
3228 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3229 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3230
3231 // Combine any LSP edits that are adjacent.
3232 //
3233 // Also, combine LSP edits that are separated from each other by only
3234 // a newline. This is important because for some code actions,
3235 // Rust-analyzer rewrites the entire buffer via a series of edits that
3236 // are separated by unchanged newline characters.
3237 //
3238 // In order for the diffing logic below to work properly, any edits that
3239 // cancel each other out must be combined into one.
3240 while let Some((next_range, next_text)) = lsp_edits.peek() {
3241 if next_range.start.0 > range.end {
3242 if next_range.start.0.row > range.end.row + 1
3243 || next_range.start.0.column > 0
3244 || snapshot.clip_point_utf16(
3245 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3246 Bias::Left,
3247 ) > range.end
3248 {
3249 break;
3250 }
3251 new_text.push('\n');
3252 }
3253 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3254 new_text.push_str(next_text);
3255 lsp_edits.next();
3256 }
3257
3258 // For multiline edits, perform a diff of the old and new text so that
3259 // we can identify the changes more precisely, preserving the locations
3260 // of any anchors positioned in the unchanged regions.
3261 if range.end.row > range.start.row {
3262 let offset = range.start.to_offset(&snapshot);
3263 let old_text = snapshot.text_for_range(range).collect::<String>();
3264 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3265 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3266 (
3267 snapshot.anchor_after(offset + range.start)
3268 ..snapshot.anchor_before(offset + range.end),
3269 replacement,
3270 )
3271 }));
3272 } else if range.end == range.start {
3273 let anchor = snapshot.anchor_after(range.start);
3274 edits.push((anchor..anchor, new_text.into()));
3275 } else {
3276 let edit_start = snapshot.anchor_after(range.start);
3277 let edit_end = snapshot.anchor_before(range.end);
3278 edits.push((edit_start..edit_end, new_text.into()));
3279 }
3280 }
3281
3282 Ok(edits)
3283 })
3284 }
3285
3286 pub(crate) async fn deserialize_workspace_edit(
3287 this: Entity<LspStore>,
3288 edit: lsp::WorkspaceEdit,
3289 push_to_history: bool,
3290 language_server: Arc<LanguageServer>,
3291 cx: &mut AsyncApp,
3292 ) -> Result<ProjectTransaction> {
3293 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3294
3295 let mut operations = Vec::new();
3296 if let Some(document_changes) = edit.document_changes {
3297 match document_changes {
3298 lsp::DocumentChanges::Edits(edits) => {
3299 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3300 }
3301 lsp::DocumentChanges::Operations(ops) => operations = ops,
3302 }
3303 } else if let Some(changes) = edit.changes {
3304 operations.extend(changes.into_iter().map(|(uri, edits)| {
3305 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3306 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3307 uri,
3308 version: None,
3309 },
3310 edits: edits.into_iter().map(Edit::Plain).collect(),
3311 })
3312 }));
3313 }
3314
3315 let mut project_transaction = ProjectTransaction::default();
3316 for operation in operations {
3317 match operation {
3318 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3319 let abs_path = op
3320 .uri
3321 .to_file_path()
3322 .map_err(|()| anyhow!("can't convert URI to path"))?;
3323
3324 if let Some(parent_path) = abs_path.parent() {
3325 fs.create_dir(parent_path).await?;
3326 }
3327 if abs_path.ends_with("/") {
3328 fs.create_dir(&abs_path).await?;
3329 } else {
3330 fs.create_file(
3331 &abs_path,
3332 op.options
3333 .map(|options| fs::CreateOptions {
3334 overwrite: options.overwrite.unwrap_or(false),
3335 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3336 })
3337 .unwrap_or_default(),
3338 )
3339 .await?;
3340 }
3341 }
3342
3343 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3344 let source_abs_path = op
3345 .old_uri
3346 .to_file_path()
3347 .map_err(|()| anyhow!("can't convert URI to path"))?;
3348 let target_abs_path = op
3349 .new_uri
3350 .to_file_path()
3351 .map_err(|()| anyhow!("can't convert URI to path"))?;
3352
3353 let options = fs::RenameOptions {
3354 overwrite: op
3355 .options
3356 .as_ref()
3357 .and_then(|options| options.overwrite)
3358 .unwrap_or(false),
3359 ignore_if_exists: op
3360 .options
3361 .as_ref()
3362 .and_then(|options| options.ignore_if_exists)
3363 .unwrap_or(false),
3364 create_parents: true,
3365 };
3366
3367 fs.rename(&source_abs_path, &target_abs_path, options)
3368 .await?;
3369 }
3370
3371 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3372 let abs_path = op
3373 .uri
3374 .to_file_path()
3375 .map_err(|()| anyhow!("can't convert URI to path"))?;
3376 let options = op
3377 .options
3378 .map(|options| fs::RemoveOptions {
3379 recursive: options.recursive.unwrap_or(false),
3380 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3381 })
3382 .unwrap_or_default();
3383 if abs_path.ends_with("/") {
3384 fs.remove_dir(&abs_path, options).await?;
3385 } else {
3386 fs.remove_file(&abs_path, options).await?;
3387 }
3388 }
3389
3390 lsp::DocumentChangeOperation::Edit(op) => {
3391 let buffer_to_edit = this
3392 .update(cx, |this, cx| {
3393 this.open_local_buffer_via_lsp(
3394 op.text_document.uri.clone(),
3395 language_server.server_id(),
3396 cx,
3397 )
3398 })
3399 .await?;
3400
3401 let edits = this
3402 .update(cx, |this, cx| {
3403 let path = buffer_to_edit.read(cx).project_path(cx);
3404 let active_entry = this.active_entry;
3405 let is_active_entry = path.is_some_and(|project_path| {
3406 this.worktree_store
3407 .read(cx)
3408 .entry_for_path(&project_path, cx)
3409 .is_some_and(|entry| Some(entry.id) == active_entry)
3410 });
3411 let local = this.as_local_mut().unwrap();
3412
3413 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3414 for edit in op.edits {
3415 match edit {
3416 Edit::Plain(edit) => {
3417 if !edits.contains(&edit) {
3418 edits.push(edit)
3419 }
3420 }
3421 Edit::Annotated(edit) => {
3422 if !edits.contains(&edit.text_edit) {
3423 edits.push(edit.text_edit)
3424 }
3425 }
3426 Edit::Snippet(edit) => {
3427 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3428 else {
3429 continue;
3430 };
3431
3432 if is_active_entry {
3433 snippet_edits.push((edit.range, snippet));
3434 } else {
3435 // Since this buffer is not focused, apply a normal edit.
3436 let new_edit = TextEdit {
3437 range: edit.range,
3438 new_text: snippet.text,
3439 };
3440 if !edits.contains(&new_edit) {
3441 edits.push(new_edit);
3442 }
3443 }
3444 }
3445 }
3446 }
3447 if !snippet_edits.is_empty() {
3448 let buffer_id = buffer_to_edit.read(cx).remote_id();
3449 let version = if let Some(buffer_version) = op.text_document.version
3450 {
3451 local
3452 .buffer_snapshot_for_lsp_version(
3453 &buffer_to_edit,
3454 language_server.server_id(),
3455 Some(buffer_version),
3456 cx,
3457 )
3458 .ok()
3459 .map(|snapshot| snapshot.version)
3460 } else {
3461 Some(buffer_to_edit.read(cx).saved_version().clone())
3462 };
3463
3464 let most_recent_edit =
3465 version.and_then(|version| version.most_recent());
3466 // Check if the edit that triggered that edit has been made by this participant.
3467
3468 if let Some(most_recent_edit) = most_recent_edit {
3469 cx.emit(LspStoreEvent::SnippetEdit {
3470 buffer_id,
3471 edits: snippet_edits,
3472 most_recent_edit,
3473 });
3474 }
3475 }
3476
3477 local.edits_from_lsp(
3478 &buffer_to_edit,
3479 edits,
3480 language_server.server_id(),
3481 op.text_document.version,
3482 cx,
3483 )
3484 })
3485 .await?;
3486
3487 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3488 buffer.finalize_last_transaction();
3489 buffer.start_transaction();
3490 for (range, text) in edits {
3491 buffer.edit([(range, text)], None, cx);
3492 }
3493
3494 buffer.end_transaction(cx).and_then(|transaction_id| {
3495 if push_to_history {
3496 buffer.finalize_last_transaction();
3497 buffer.get_transaction(transaction_id).cloned()
3498 } else {
3499 buffer.forget_transaction(transaction_id)
3500 }
3501 })
3502 });
3503 if let Some(transaction) = transaction {
3504 project_transaction.0.insert(buffer_to_edit, transaction);
3505 }
3506 }
3507 }
3508 }
3509
3510 Ok(project_transaction)
3511 }
3512
3513 async fn on_lsp_workspace_edit(
3514 this: WeakEntity<LspStore>,
3515 params: lsp::ApplyWorkspaceEditParams,
3516 server_id: LanguageServerId,
3517 cx: &mut AsyncApp,
3518 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3519 let this = this.upgrade().context("project project closed")?;
3520 let language_server = this
3521 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3522 .context("language server not found")?;
3523 let transaction = Self::deserialize_workspace_edit(
3524 this.clone(),
3525 params.edit,
3526 true,
3527 language_server.clone(),
3528 cx,
3529 )
3530 .await
3531 .log_err();
3532 this.update(cx, |this, cx| {
3533 if let Some(transaction) = transaction {
3534 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3535
3536 this.as_local_mut()
3537 .unwrap()
3538 .last_workspace_edits_by_language_server
3539 .insert(server_id, transaction);
3540 }
3541 });
3542 Ok(lsp::ApplyWorkspaceEditResponse {
3543 applied: true,
3544 failed_change: None,
3545 failure_reason: None,
3546 })
3547 }
3548
3549 fn remove_worktree(
3550 &mut self,
3551 id_to_remove: WorktreeId,
3552 cx: &mut Context<LspStore>,
3553 ) -> Vec<LanguageServerId> {
3554 self.restricted_worktrees_tasks.remove(&id_to_remove);
3555 self.diagnostics.remove(&id_to_remove);
3556 self.prettier_store.update(cx, |prettier_store, cx| {
3557 prettier_store.remove_worktree(id_to_remove, cx);
3558 });
3559
3560 let mut servers_to_remove = BTreeSet::default();
3561 let mut servers_to_preserve = HashSet::default();
3562 for (seed, state) in &self.language_server_ids {
3563 if seed.worktree_id == id_to_remove {
3564 servers_to_remove.insert(state.id);
3565 } else {
3566 servers_to_preserve.insert(state.id);
3567 }
3568 }
3569 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3570 self.language_server_ids
3571 .retain(|_, state| !servers_to_remove.contains(&state.id));
3572 for server_id_to_remove in &servers_to_remove {
3573 self.language_server_watched_paths
3574 .remove(server_id_to_remove);
3575 self.language_server_paths_watched_for_rename
3576 .remove(server_id_to_remove);
3577 self.last_workspace_edits_by_language_server
3578 .remove(server_id_to_remove);
3579 self.language_servers.remove(server_id_to_remove);
3580 self.buffer_pull_diagnostics_result_ids
3581 .remove(server_id_to_remove);
3582 self.workspace_pull_diagnostics_result_ids
3583 .remove(server_id_to_remove);
3584 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3585 buffer_servers.remove(server_id_to_remove);
3586 }
3587 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3588 }
3589 servers_to_remove.into_iter().collect()
3590 }
3591
3592 fn rebuild_watched_paths_inner<'a>(
3593 &'a self,
3594 language_server_id: LanguageServerId,
3595 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3596 cx: &mut Context<LspStore>,
3597 ) -> LanguageServerWatchedPathsBuilder {
3598 let worktrees = self
3599 .worktree_store
3600 .read(cx)
3601 .worktrees()
3602 .filter_map(|worktree| {
3603 self.language_servers_for_worktree(worktree.read(cx).id())
3604 .find(|server| server.server_id() == language_server_id)
3605 .map(|_| worktree)
3606 })
3607 .collect::<Vec<_>>();
3608
3609 let mut worktree_globs = HashMap::default();
3610 let mut abs_globs = HashMap::default();
3611 log::trace!(
3612 "Processing new watcher paths for language server with id {}",
3613 language_server_id
3614 );
3615
3616 for watcher in watchers {
3617 if let Some((worktree, literal_prefix, pattern)) =
3618 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3619 {
3620 worktree.update(cx, |worktree, _| {
3621 if let Some((tree, glob)) =
3622 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3623 {
3624 tree.add_path_prefix_to_scan(literal_prefix);
3625 worktree_globs
3626 .entry(tree.id())
3627 .or_insert_with(GlobSetBuilder::new)
3628 .add(glob);
3629 }
3630 });
3631 } else {
3632 let (path, pattern) = match &watcher.glob_pattern {
3633 lsp::GlobPattern::String(s) => {
3634 let watcher_path = SanitizedPath::new(s);
3635 let path = glob_literal_prefix(watcher_path.as_path());
3636 let pattern = watcher_path
3637 .as_path()
3638 .strip_prefix(&path)
3639 .map(|p| p.to_string_lossy().into_owned())
3640 .unwrap_or_else(|e| {
3641 debug_panic!(
3642 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3643 s,
3644 path.display(),
3645 e
3646 );
3647 watcher_path.as_path().to_string_lossy().into_owned()
3648 });
3649 (path, pattern)
3650 }
3651 lsp::GlobPattern::Relative(rp) => {
3652 let Ok(mut base_uri) = match &rp.base_uri {
3653 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3654 lsp::OneOf::Right(base_uri) => base_uri,
3655 }
3656 .to_file_path() else {
3657 continue;
3658 };
3659
3660 let path = glob_literal_prefix(Path::new(&rp.pattern));
3661 let pattern = Path::new(&rp.pattern)
3662 .strip_prefix(&path)
3663 .map(|p| p.to_string_lossy().into_owned())
3664 .unwrap_or_else(|e| {
3665 debug_panic!(
3666 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3667 rp.pattern,
3668 path.display(),
3669 e
3670 );
3671 rp.pattern.clone()
3672 });
3673 base_uri.push(path);
3674 (base_uri, pattern)
3675 }
3676 };
3677
3678 if let Some(glob) = Glob::new(&pattern).log_err() {
3679 if !path
3680 .components()
3681 .any(|c| matches!(c, path::Component::Normal(_)))
3682 {
3683 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3684 // rather than adding a new watcher for `/`.
3685 for worktree in &worktrees {
3686 worktree_globs
3687 .entry(worktree.read(cx).id())
3688 .or_insert_with(GlobSetBuilder::new)
3689 .add(glob.clone());
3690 }
3691 } else {
3692 abs_globs
3693 .entry(path.into())
3694 .or_insert_with(GlobSetBuilder::new)
3695 .add(glob);
3696 }
3697 }
3698 }
3699 }
3700
3701 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3702 for (worktree_id, builder) in worktree_globs {
3703 if let Ok(globset) = builder.build() {
3704 watch_builder.watch_worktree(worktree_id, globset);
3705 }
3706 }
3707 for (abs_path, builder) in abs_globs {
3708 if let Ok(globset) = builder.build() {
3709 watch_builder.watch_abs_path(abs_path, globset);
3710 }
3711 }
3712 watch_builder
3713 }
3714
3715 fn worktree_and_path_for_file_watcher(
3716 worktrees: &[Entity<Worktree>],
3717 watcher: &FileSystemWatcher,
3718 cx: &App,
3719 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3720 worktrees.iter().find_map(|worktree| {
3721 let tree = worktree.read(cx);
3722 let worktree_root_path = tree.abs_path();
3723 let path_style = tree.path_style();
3724 match &watcher.glob_pattern {
3725 lsp::GlobPattern::String(s) => {
3726 let watcher_path = SanitizedPath::new(s);
3727 let relative = watcher_path
3728 .as_path()
3729 .strip_prefix(&worktree_root_path)
3730 .ok()?;
3731 let literal_prefix = glob_literal_prefix(relative);
3732 Some((
3733 worktree.clone(),
3734 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3735 relative.to_string_lossy().into_owned(),
3736 ))
3737 }
3738 lsp::GlobPattern::Relative(rp) => {
3739 let base_uri = match &rp.base_uri {
3740 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3741 lsp::OneOf::Right(base_uri) => base_uri,
3742 }
3743 .to_file_path()
3744 .ok()?;
3745 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3746 let mut literal_prefix = relative.to_owned();
3747 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3748 Some((
3749 worktree.clone(),
3750 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3751 rp.pattern.clone(),
3752 ))
3753 }
3754 }
3755 })
3756 }
3757
3758 fn rebuild_watched_paths(
3759 &mut self,
3760 language_server_id: LanguageServerId,
3761 cx: &mut Context<LspStore>,
3762 ) {
3763 let Some(registrations) = self
3764 .language_server_dynamic_registrations
3765 .get(&language_server_id)
3766 else {
3767 return;
3768 };
3769
3770 let watch_builder = self.rebuild_watched_paths_inner(
3771 language_server_id,
3772 registrations.did_change_watched_files.values().flatten(),
3773 cx,
3774 );
3775 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3776 self.language_server_watched_paths
3777 .insert(language_server_id, watcher);
3778
3779 cx.notify();
3780 }
3781
3782 fn on_lsp_did_change_watched_files(
3783 &mut self,
3784 language_server_id: LanguageServerId,
3785 registration_id: &str,
3786 params: DidChangeWatchedFilesRegistrationOptions,
3787 cx: &mut Context<LspStore>,
3788 ) {
3789 let registrations = self
3790 .language_server_dynamic_registrations
3791 .entry(language_server_id)
3792 .or_default();
3793
3794 registrations
3795 .did_change_watched_files
3796 .insert(registration_id.to_string(), params.watchers);
3797
3798 self.rebuild_watched_paths(language_server_id, cx);
3799 }
3800
3801 fn on_lsp_unregister_did_change_watched_files(
3802 &mut self,
3803 language_server_id: LanguageServerId,
3804 registration_id: &str,
3805 cx: &mut Context<LspStore>,
3806 ) {
3807 let registrations = self
3808 .language_server_dynamic_registrations
3809 .entry(language_server_id)
3810 .or_default();
3811
3812 if registrations
3813 .did_change_watched_files
3814 .remove(registration_id)
3815 .is_some()
3816 {
3817 log::info!(
3818 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3819 language_server_id,
3820 registration_id
3821 );
3822 } else {
3823 log::warn!(
3824 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3825 language_server_id,
3826 registration_id
3827 );
3828 }
3829
3830 self.rebuild_watched_paths(language_server_id, cx);
3831 }
3832
3833 async fn initialization_options_for_adapter(
3834 adapter: Arc<dyn LspAdapter>,
3835 delegate: &Arc<dyn LspAdapterDelegate>,
3836 cx: &mut AsyncApp,
3837 ) -> Result<Option<serde_json::Value>> {
3838 let Some(mut initialization_config) =
3839 adapter.clone().initialization_options(delegate, cx).await?
3840 else {
3841 return Ok(None);
3842 };
3843
3844 for other_adapter in delegate.registered_lsp_adapters() {
3845 if other_adapter.name() == adapter.name() {
3846 continue;
3847 }
3848 if let Ok(Some(target_config)) = other_adapter
3849 .clone()
3850 .additional_initialization_options(adapter.name(), delegate)
3851 .await
3852 {
3853 merge_json_value_into(target_config.clone(), &mut initialization_config);
3854 }
3855 }
3856
3857 Ok(Some(initialization_config))
3858 }
3859
3860 async fn workspace_configuration_for_adapter(
3861 adapter: Arc<dyn LspAdapter>,
3862 delegate: &Arc<dyn LspAdapterDelegate>,
3863 toolchain: Option<Toolchain>,
3864 requested_uri: Option<Uri>,
3865 cx: &mut AsyncApp,
3866 ) -> Result<serde_json::Value> {
3867 let mut workspace_config = adapter
3868 .clone()
3869 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3870 .await?;
3871
3872 for other_adapter in delegate.registered_lsp_adapters() {
3873 if other_adapter.name() == adapter.name() {
3874 continue;
3875 }
3876 if let Ok(Some(target_config)) = other_adapter
3877 .clone()
3878 .additional_workspace_configuration(adapter.name(), delegate, cx)
3879 .await
3880 {
3881 merge_json_value_into(target_config.clone(), &mut workspace_config);
3882 }
3883 }
3884
3885 Ok(workspace_config)
3886 }
3887
3888 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3889 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3890 Some(server.clone())
3891 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3892 Some(Arc::clone(server))
3893 } else {
3894 None
3895 }
3896 }
3897}
3898
3899fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3900 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3901 cx.emit(LspStoreEvent::LanguageServerUpdate {
3902 language_server_id: server.server_id(),
3903 name: Some(server.name()),
3904 message: proto::update_language_server::Variant::MetadataUpdated(
3905 proto::ServerMetadataUpdated {
3906 capabilities: Some(capabilities),
3907 binary: Some(proto::LanguageServerBinaryInfo {
3908 path: server.binary().path.to_string_lossy().into_owned(),
3909 arguments: server
3910 .binary()
3911 .arguments
3912 .iter()
3913 .map(|arg| arg.to_string_lossy().into_owned())
3914 .collect(),
3915 }),
3916 configuration: serde_json::to_string(server.configuration()).ok(),
3917 workspace_folders: server
3918 .workspace_folders()
3919 .iter()
3920 .map(|uri| uri.to_string())
3921 .collect(),
3922 },
3923 ),
3924 });
3925 }
3926}
3927
3928#[derive(Debug)]
3929pub struct FormattableBuffer {
3930 handle: Entity<Buffer>,
3931 abs_path: Option<PathBuf>,
3932 env: Option<HashMap<String, String>>,
3933 ranges: Option<Vec<Range<Anchor>>>,
3934}
3935
3936pub struct RemoteLspStore {
3937 upstream_client: Option<AnyProtoClient>,
3938 upstream_project_id: u64,
3939}
3940
3941pub(crate) enum LspStoreMode {
3942 Local(LocalLspStore), // ssh host and collab host
3943 Remote(RemoteLspStore), // collab guest
3944}
3945
3946impl LspStoreMode {
3947 fn is_local(&self) -> bool {
3948 matches!(self, LspStoreMode::Local(_))
3949 }
3950}
3951
3952pub struct LspStore {
3953 mode: LspStoreMode,
3954 last_formatting_failure: Option<String>,
3955 downstream_client: Option<(AnyProtoClient, u64)>,
3956 nonce: u128,
3957 buffer_store: Entity<BufferStore>,
3958 worktree_store: Entity<WorktreeStore>,
3959 pub languages: Arc<LanguageRegistry>,
3960 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3961 active_entry: Option<ProjectEntryId>,
3962 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3963 _maintain_buffer_languages: Task<()>,
3964 diagnostic_summaries:
3965 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3966 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3967 semantic_token_config: SemanticTokenConfig,
3968 lsp_data: HashMap<BufferId, BufferLspData>,
3969 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3970 next_hint_id: Arc<AtomicUsize>,
3971}
3972
3973#[derive(Debug)]
3974pub struct BufferLspData {
3975 buffer_version: Global,
3976 document_colors: Option<DocumentColorData>,
3977 code_lens: Option<CodeLensData>,
3978 semantic_tokens: Option<SemanticTokensData>,
3979 folding_ranges: Option<FoldingRangeData>,
3980 document_symbols: Option<DocumentSymbolsData>,
3981 inlay_hints: BufferInlayHints,
3982 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3983 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3984}
3985
3986#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3987struct LspKey {
3988 request_type: TypeId,
3989 server_queried: Option<LanguageServerId>,
3990}
3991
3992impl BufferLspData {
3993 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3994 Self {
3995 buffer_version: buffer.read(cx).version(),
3996 document_colors: None,
3997 code_lens: None,
3998 semantic_tokens: None,
3999 folding_ranges: None,
4000 document_symbols: None,
4001 inlay_hints: BufferInlayHints::new(buffer, cx),
4002 lsp_requests: HashMap::default(),
4003 chunk_lsp_requests: HashMap::default(),
4004 }
4005 }
4006
4007 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4008 if let Some(document_colors) = &mut self.document_colors {
4009 document_colors.remove_server_data(for_server);
4010 }
4011
4012 if let Some(code_lens) = &mut self.code_lens {
4013 code_lens.remove_server_data(for_server);
4014 }
4015
4016 self.inlay_hints.remove_server_data(for_server);
4017
4018 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4019 semantic_tokens.remove_server_data(for_server);
4020 }
4021
4022 if let Some(folding_ranges) = &mut self.folding_ranges {
4023 folding_ranges.ranges.remove(&for_server);
4024 }
4025
4026 if let Some(document_symbols) = &mut self.document_symbols {
4027 document_symbols.remove_server_data(for_server);
4028 }
4029 }
4030
4031 #[cfg(any(test, feature = "test-support"))]
4032 pub fn inlay_hints(&self) -> &BufferInlayHints {
4033 &self.inlay_hints
4034 }
4035}
4036
4037#[derive(Debug)]
4038pub enum LspStoreEvent {
4039 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4040 LanguageServerRemoved(LanguageServerId),
4041 LanguageServerUpdate {
4042 language_server_id: LanguageServerId,
4043 name: Option<LanguageServerName>,
4044 message: proto::update_language_server::Variant,
4045 },
4046 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4047 LanguageServerPrompt(LanguageServerPromptRequest),
4048 LanguageDetected {
4049 buffer: Entity<Buffer>,
4050 new_language: Option<Arc<Language>>,
4051 },
4052 Notification(String),
4053 RefreshInlayHints {
4054 server_id: LanguageServerId,
4055 request_id: Option<usize>,
4056 },
4057 RefreshSemanticTokens {
4058 server_id: LanguageServerId,
4059 request_id: Option<usize>,
4060 },
4061 RefreshCodeLens,
4062 DiagnosticsUpdated {
4063 server_id: LanguageServerId,
4064 paths: Vec<ProjectPath>,
4065 },
4066 DiskBasedDiagnosticsStarted {
4067 language_server_id: LanguageServerId,
4068 },
4069 DiskBasedDiagnosticsFinished {
4070 language_server_id: LanguageServerId,
4071 },
4072 SnippetEdit {
4073 buffer_id: BufferId,
4074 edits: Vec<(lsp::Range, Snippet)>,
4075 most_recent_edit: clock::Lamport,
4076 },
4077 WorkspaceEditApplied(ProjectTransaction),
4078}
4079
4080#[derive(Clone, Debug, Serialize)]
4081pub struct LanguageServerStatus {
4082 pub name: LanguageServerName,
4083 pub server_version: Option<SharedString>,
4084 pub server_readable_version: Option<SharedString>,
4085 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4086 pub has_pending_diagnostic_updates: bool,
4087 pub progress_tokens: HashSet<ProgressToken>,
4088 pub worktree: Option<WorktreeId>,
4089 pub binary: Option<LanguageServerBinary>,
4090 pub configuration: Option<Value>,
4091 pub workspace_folders: BTreeSet<Uri>,
4092 pub process_id: Option<u32>,
4093}
4094
4095#[derive(Clone, Debug)]
4096struct CoreSymbol {
4097 pub language_server_name: LanguageServerName,
4098 pub source_worktree_id: WorktreeId,
4099 pub source_language_server_id: LanguageServerId,
4100 pub path: SymbolLocation,
4101 pub name: String,
4102 pub kind: lsp::SymbolKind,
4103 pub range: Range<Unclipped<PointUtf16>>,
4104 pub container_name: Option<String>,
4105}
4106
4107#[derive(Clone, Debug, PartialEq, Eq)]
4108pub enum SymbolLocation {
4109 InProject(ProjectPath),
4110 OutsideProject {
4111 abs_path: Arc<Path>,
4112 signature: [u8; 32],
4113 },
4114}
4115
4116impl SymbolLocation {
4117 fn file_name(&self) -> Option<&str> {
4118 match self {
4119 Self::InProject(path) => path.path.file_name(),
4120 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4121 }
4122 }
4123}
4124
4125impl LspStore {
4126 pub fn init(client: &AnyProtoClient) {
4127 client.add_entity_request_handler(Self::handle_lsp_query);
4128 client.add_entity_message_handler(Self::handle_lsp_query_response);
4129 client.add_entity_request_handler(Self::handle_restart_language_servers);
4130 client.add_entity_request_handler(Self::handle_stop_language_servers);
4131 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4132 client.add_entity_message_handler(Self::handle_start_language_server);
4133 client.add_entity_message_handler(Self::handle_update_language_server);
4134 client.add_entity_message_handler(Self::handle_language_server_log);
4135 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4136 client.add_entity_request_handler(Self::handle_format_buffers);
4137 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4138 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4139 client.add_entity_request_handler(Self::handle_apply_code_action);
4140 client.add_entity_request_handler(Self::handle_get_project_symbols);
4141 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4142 client.add_entity_request_handler(Self::handle_get_color_presentation);
4143 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4144 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4145 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4146 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4147 client.add_entity_request_handler(Self::handle_on_type_formatting);
4148 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4149 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4150 client.add_entity_request_handler(Self::handle_rename_project_entry);
4151 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4152 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4153 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4154 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4155 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4156 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4157 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4158
4159 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4160 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4161 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4162 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4163 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4164 client.add_entity_request_handler(
4165 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4166 );
4167 client.add_entity_request_handler(
4168 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4169 );
4170 client.add_entity_request_handler(
4171 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4172 );
4173 }
4174
4175 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4176 match &self.mode {
4177 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4178 _ => None,
4179 }
4180 }
4181
4182 pub fn as_local(&self) -> Option<&LocalLspStore> {
4183 match &self.mode {
4184 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4185 _ => None,
4186 }
4187 }
4188
4189 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4190 match &mut self.mode {
4191 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4192 _ => None,
4193 }
4194 }
4195
4196 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4197 match &self.mode {
4198 LspStoreMode::Remote(RemoteLspStore {
4199 upstream_client: Some(upstream_client),
4200 upstream_project_id,
4201 ..
4202 }) => Some((upstream_client.clone(), *upstream_project_id)),
4203
4204 LspStoreMode::Remote(RemoteLspStore {
4205 upstream_client: None,
4206 ..
4207 }) => None,
4208 LspStoreMode::Local(_) => None,
4209 }
4210 }
4211
4212 pub fn new_local(
4213 buffer_store: Entity<BufferStore>,
4214 worktree_store: Entity<WorktreeStore>,
4215 prettier_store: Entity<PrettierStore>,
4216 toolchain_store: Entity<LocalToolchainStore>,
4217 environment: Entity<ProjectEnvironment>,
4218 manifest_tree: Entity<ManifestTree>,
4219 languages: Arc<LanguageRegistry>,
4220 http_client: Arc<dyn HttpClient>,
4221 fs: Arc<dyn Fs>,
4222 cx: &mut Context<Self>,
4223 ) -> Self {
4224 let yarn = YarnPathStore::new(fs.clone(), cx);
4225 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4226 .detach();
4227 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4228 .detach();
4229 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4230 .detach();
4231 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4232 .detach();
4233 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4234 .detach();
4235 subscribe_to_binary_statuses(&languages, cx).detach();
4236
4237 let _maintain_workspace_config = {
4238 let (sender, receiver) = watch::channel();
4239 (Self::maintain_workspace_config(receiver, cx), sender)
4240 };
4241
4242 Self {
4243 mode: LspStoreMode::Local(LocalLspStore {
4244 weak: cx.weak_entity(),
4245 worktree_store: worktree_store.clone(),
4246
4247 supplementary_language_servers: Default::default(),
4248 languages: languages.clone(),
4249 language_server_ids: Default::default(),
4250 language_servers: Default::default(),
4251 last_workspace_edits_by_language_server: Default::default(),
4252 language_server_watched_paths: Default::default(),
4253 language_server_paths_watched_for_rename: Default::default(),
4254 language_server_dynamic_registrations: Default::default(),
4255 buffers_being_formatted: Default::default(),
4256 buffers_to_refresh_hash_set: HashSet::default(),
4257 buffers_to_refresh_queue: VecDeque::new(),
4258 _background_diagnostics_worker: Task::ready(()).shared(),
4259 buffer_snapshots: Default::default(),
4260 prettier_store,
4261 environment,
4262 http_client,
4263 fs,
4264 yarn,
4265 next_diagnostic_group_id: Default::default(),
4266 diagnostics: Default::default(),
4267 _subscription: cx.on_app_quit(|this, _| {
4268 this.as_local_mut()
4269 .unwrap()
4270 .shutdown_language_servers_on_quit()
4271 }),
4272 lsp_tree: LanguageServerTree::new(
4273 manifest_tree,
4274 languages.clone(),
4275 toolchain_store.clone(),
4276 ),
4277 toolchain_store,
4278 registered_buffers: HashMap::default(),
4279 buffers_opened_in_servers: HashMap::default(),
4280 buffer_pull_diagnostics_result_ids: HashMap::default(),
4281 workspace_pull_diagnostics_result_ids: HashMap::default(),
4282 restricted_worktrees_tasks: HashMap::default(),
4283 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4284 .manifest_file_names(),
4285 }),
4286 last_formatting_failure: None,
4287 downstream_client: None,
4288 buffer_store,
4289 worktree_store,
4290 languages: languages.clone(),
4291 language_server_statuses: Default::default(),
4292 nonce: StdRng::from_os_rng().random(),
4293 diagnostic_summaries: HashMap::default(),
4294 lsp_server_capabilities: HashMap::default(),
4295 semantic_token_config: SemanticTokenConfig::new(cx),
4296 lsp_data: HashMap::default(),
4297 buffer_reload_tasks: HashMap::default(),
4298 next_hint_id: Arc::default(),
4299 active_entry: None,
4300 _maintain_workspace_config,
4301 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4302 }
4303 }
4304
4305 fn send_lsp_proto_request<R: LspCommand>(
4306 &self,
4307 buffer: Entity<Buffer>,
4308 client: AnyProtoClient,
4309 upstream_project_id: u64,
4310 request: R,
4311 cx: &mut Context<LspStore>,
4312 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4313 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4314 return Task::ready(Ok(R::Response::default()));
4315 }
4316 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4317 cx.spawn(async move |this, cx| {
4318 let response = client.request(message).await?;
4319 let this = this.upgrade().context("project dropped")?;
4320 request
4321 .response_from_proto(response, this, buffer, cx.clone())
4322 .await
4323 })
4324 }
4325
4326 pub(super) fn new_remote(
4327 buffer_store: Entity<BufferStore>,
4328 worktree_store: Entity<WorktreeStore>,
4329 languages: Arc<LanguageRegistry>,
4330 upstream_client: AnyProtoClient,
4331 project_id: u64,
4332 cx: &mut Context<Self>,
4333 ) -> Self {
4334 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4335 .detach();
4336 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4337 .detach();
4338 subscribe_to_binary_statuses(&languages, cx).detach();
4339 let _maintain_workspace_config = {
4340 let (sender, receiver) = watch::channel();
4341 (Self::maintain_workspace_config(receiver, cx), sender)
4342 };
4343 Self {
4344 mode: LspStoreMode::Remote(RemoteLspStore {
4345 upstream_client: Some(upstream_client),
4346 upstream_project_id: project_id,
4347 }),
4348 downstream_client: None,
4349 last_formatting_failure: None,
4350 buffer_store,
4351 worktree_store,
4352 languages: languages.clone(),
4353 language_server_statuses: Default::default(),
4354 nonce: StdRng::from_os_rng().random(),
4355 diagnostic_summaries: HashMap::default(),
4356 lsp_server_capabilities: HashMap::default(),
4357 semantic_token_config: SemanticTokenConfig::new(cx),
4358 next_hint_id: Arc::default(),
4359 lsp_data: HashMap::default(),
4360 buffer_reload_tasks: HashMap::default(),
4361 active_entry: None,
4362
4363 _maintain_workspace_config,
4364 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4365 }
4366 }
4367
4368 fn on_buffer_store_event(
4369 &mut self,
4370 _: Entity<BufferStore>,
4371 event: &BufferStoreEvent,
4372 cx: &mut Context<Self>,
4373 ) {
4374 match event {
4375 BufferStoreEvent::BufferAdded(buffer) => {
4376 self.on_buffer_added(buffer, cx).log_err();
4377 }
4378 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4379 let buffer_id = buffer.read(cx).remote_id();
4380 if let Some(local) = self.as_local_mut()
4381 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4382 {
4383 local.reset_buffer(buffer, old_file, cx);
4384
4385 if local.registered_buffers.contains_key(&buffer_id) {
4386 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4387 }
4388 }
4389
4390 self.detect_language_for_buffer(buffer, cx);
4391 if let Some(local) = self.as_local_mut() {
4392 local.initialize_buffer(buffer, cx);
4393 if local.registered_buffers.contains_key(&buffer_id) {
4394 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4395 }
4396 }
4397 }
4398 _ => {}
4399 }
4400 }
4401
4402 fn on_worktree_store_event(
4403 &mut self,
4404 _: Entity<WorktreeStore>,
4405 event: &WorktreeStoreEvent,
4406 cx: &mut Context<Self>,
4407 ) {
4408 match event {
4409 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4410 if !worktree.read(cx).is_local() {
4411 return;
4412 }
4413 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4414 worktree::Event::UpdatedEntries(changes) => {
4415 this.update_local_worktree_language_servers(&worktree, changes, cx);
4416 }
4417 worktree::Event::UpdatedGitRepositories(_)
4418 | worktree::Event::DeletedEntry(_)
4419 | worktree::Event::Deleted
4420 | worktree::Event::UpdatedRootRepoCommonDir { .. } => {}
4421 })
4422 .detach()
4423 }
4424 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4425 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4426 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4427 }
4428 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4429 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4430 }
4431 WorktreeStoreEvent::WorktreeReleased(..)
4432 | WorktreeStoreEvent::WorktreeOrderChanged
4433 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4434 | WorktreeStoreEvent::WorktreeDeletedEntry(..)
4435 | WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir(..) => {}
4436 }
4437 }
4438
4439 fn on_prettier_store_event(
4440 &mut self,
4441 _: Entity<PrettierStore>,
4442 event: &PrettierStoreEvent,
4443 cx: &mut Context<Self>,
4444 ) {
4445 match event {
4446 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4447 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4448 }
4449 PrettierStoreEvent::LanguageServerAdded {
4450 new_server_id,
4451 name,
4452 prettier_server,
4453 } => {
4454 self.register_supplementary_language_server(
4455 *new_server_id,
4456 name.clone(),
4457 prettier_server.clone(),
4458 cx,
4459 );
4460 }
4461 }
4462 }
4463
4464 fn on_toolchain_store_event(
4465 &mut self,
4466 _: Entity<LocalToolchainStore>,
4467 event: &ToolchainStoreEvent,
4468 _: &mut Context<Self>,
4469 ) {
4470 if let ToolchainStoreEvent::ToolchainActivated = event {
4471 self.request_workspace_config_refresh()
4472 }
4473 }
4474
4475 fn request_workspace_config_refresh(&mut self) {
4476 *self._maintain_workspace_config.1.borrow_mut() = ();
4477 }
4478
4479 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4480 self.as_local().map(|local| local.prettier_store.clone())
4481 }
4482
4483 fn on_buffer_event(
4484 &mut self,
4485 buffer: Entity<Buffer>,
4486 event: &language::BufferEvent,
4487 cx: &mut Context<Self>,
4488 ) {
4489 match event {
4490 language::BufferEvent::Edited { .. } => {
4491 self.on_buffer_edited(buffer, cx);
4492 }
4493
4494 language::BufferEvent::Saved => {
4495 self.on_buffer_saved(buffer, cx);
4496 }
4497
4498 language::BufferEvent::Reloaded => {
4499 self.on_buffer_reloaded(buffer, cx);
4500 }
4501
4502 _ => {}
4503 }
4504 }
4505
4506 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4507 buffer
4508 .read(cx)
4509 .set_language_registry(self.languages.clone());
4510
4511 cx.subscribe(buffer, |this, buffer, event, cx| {
4512 this.on_buffer_event(buffer, event, cx);
4513 })
4514 .detach();
4515
4516 self.parse_modeline(buffer, cx);
4517 self.detect_language_for_buffer(buffer, cx);
4518 if let Some(local) = self.as_local_mut() {
4519 local.initialize_buffer(buffer, cx);
4520 }
4521
4522 Ok(())
4523 }
4524
4525 pub fn refresh_background_diagnostics_for_buffers(
4526 &mut self,
4527 buffers: HashSet<BufferId>,
4528 cx: &mut Context<Self>,
4529 ) -> Shared<Task<()>> {
4530 let Some(local) = self.as_local_mut() else {
4531 return Task::ready(()).shared();
4532 };
4533 for buffer in buffers {
4534 if local.buffers_to_refresh_hash_set.insert(buffer) {
4535 local.buffers_to_refresh_queue.push_back(buffer);
4536 if local.buffers_to_refresh_queue.len() == 1 {
4537 local._background_diagnostics_worker =
4538 Self::background_diagnostics_worker(cx).shared();
4539 }
4540 }
4541 }
4542
4543 local._background_diagnostics_worker.clone()
4544 }
4545
4546 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4547 let buffer_store = self.buffer_store.clone();
4548 let local = self.as_local_mut()?;
4549 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4550 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4551 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4552 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4553 }
4554 }
4555 None
4556 }
4557
4558 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4559 cx.spawn(async move |this, cx| {
4560 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4561 task.await.log_err();
4562 }
4563 })
4564 }
4565
4566 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4567 if self.parse_modeline(&buffer, cx) {
4568 self.detect_language_for_buffer(&buffer, cx);
4569 }
4570
4571 let buffer_id = buffer.read(cx).remote_id();
4572 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4573 self.buffer_reload_tasks.insert(buffer_id, task);
4574 }
4575
4576 pub(crate) fn register_buffer_with_language_servers(
4577 &mut self,
4578 buffer: &Entity<Buffer>,
4579 only_register_servers: HashSet<LanguageServerSelector>,
4580 ignore_refcounts: bool,
4581 cx: &mut Context<Self>,
4582 ) -> OpenLspBufferHandle {
4583 let buffer_id = buffer.read(cx).remote_id();
4584 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4585 if let Some(local) = self.as_local_mut() {
4586 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4587 if !ignore_refcounts {
4588 *refcount += 1;
4589 }
4590
4591 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4592 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4593 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4594 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4595 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4596 return handle;
4597 };
4598 if !file.is_local() {
4599 return handle;
4600 }
4601
4602 if ignore_refcounts || *refcount == 1 {
4603 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4604 }
4605 if !ignore_refcounts {
4606 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4607 let refcount = {
4608 let local = lsp_store.as_local_mut().unwrap();
4609 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4610 debug_panic!("bad refcounting");
4611 return;
4612 };
4613
4614 *refcount -= 1;
4615 *refcount
4616 };
4617 if refcount == 0 {
4618 lsp_store.lsp_data.remove(&buffer_id);
4619 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4620 let local = lsp_store.as_local_mut().unwrap();
4621 local.registered_buffers.remove(&buffer_id);
4622
4623 local.buffers_opened_in_servers.remove(&buffer_id);
4624 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4625 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4626
4627 let buffer_abs_path = file.abs_path(cx);
4628 for (_, buffer_pull_diagnostics_result_ids) in
4629 &mut local.buffer_pull_diagnostics_result_ids
4630 {
4631 buffer_pull_diagnostics_result_ids.retain(
4632 |_, buffer_result_ids| {
4633 buffer_result_ids.remove(&buffer_abs_path);
4634 !buffer_result_ids.is_empty()
4635 },
4636 );
4637 }
4638
4639 let diagnostic_updates = local
4640 .language_servers
4641 .keys()
4642 .cloned()
4643 .map(|server_id| DocumentDiagnosticsUpdate {
4644 diagnostics: DocumentDiagnostics {
4645 document_abs_path: buffer_abs_path.clone(),
4646 version: None,
4647 diagnostics: Vec::new(),
4648 },
4649 result_id: None,
4650 registration_id: None,
4651 server_id,
4652 disk_based_sources: Cow::Borrowed(&[]),
4653 })
4654 .collect::<Vec<_>>();
4655
4656 lsp_store
4657 .merge_diagnostic_entries(
4658 diagnostic_updates,
4659 |_, diagnostic, _| {
4660 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4661 },
4662 cx,
4663 )
4664 .context("Clearing diagnostics for the closed buffer")
4665 .log_err();
4666 }
4667 }
4668 })
4669 .detach();
4670 }
4671 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4672 let buffer_id = buffer.read(cx).remote_id().to_proto();
4673 cx.background_spawn(async move {
4674 upstream_client
4675 .request(proto::RegisterBufferWithLanguageServers {
4676 project_id: upstream_project_id,
4677 buffer_id,
4678 only_servers: only_register_servers
4679 .into_iter()
4680 .map(|selector| {
4681 let selector = match selector {
4682 LanguageServerSelector::Id(language_server_id) => {
4683 proto::language_server_selector::Selector::ServerId(
4684 language_server_id.to_proto(),
4685 )
4686 }
4687 LanguageServerSelector::Name(language_server_name) => {
4688 proto::language_server_selector::Selector::Name(
4689 language_server_name.to_string(),
4690 )
4691 }
4692 };
4693 proto::LanguageServerSelector {
4694 selector: Some(selector),
4695 }
4696 })
4697 .collect(),
4698 })
4699 .await
4700 })
4701 .detach();
4702 } else {
4703 // Our remote connection got closed
4704 }
4705 handle
4706 }
4707
4708 fn maintain_buffer_languages(
4709 languages: Arc<LanguageRegistry>,
4710 cx: &mut Context<Self>,
4711 ) -> Task<()> {
4712 let mut subscription = languages.subscribe();
4713 let mut prev_reload_count = languages.reload_count();
4714 cx.spawn(async move |this, cx| {
4715 while let Some(()) = subscription.next().await {
4716 if let Some(this) = this.upgrade() {
4717 // If the language registry has been reloaded, then remove and
4718 // re-assign the languages on all open buffers.
4719 let reload_count = languages.reload_count();
4720 if reload_count > prev_reload_count {
4721 prev_reload_count = reload_count;
4722 this.update(cx, |this, cx| {
4723 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4724 for buffer in buffer_store.buffers() {
4725 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4726 {
4727 buffer.update(cx, |buffer, cx| {
4728 buffer.set_language_async(None, cx)
4729 });
4730 if let Some(local) = this.as_local_mut() {
4731 local.reset_buffer(&buffer, &f, cx);
4732
4733 if local
4734 .registered_buffers
4735 .contains_key(&buffer.read(cx).remote_id())
4736 && let Some(file_url) =
4737 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4738 {
4739 local.unregister_buffer_from_language_servers(
4740 &buffer, &file_url, cx,
4741 );
4742 }
4743 }
4744 }
4745 }
4746 });
4747 });
4748 }
4749
4750 this.update(cx, |this, cx| {
4751 let mut plain_text_buffers = Vec::new();
4752 let mut buffers_with_unknown_injections = Vec::new();
4753 for handle in this.buffer_store.read(cx).buffers() {
4754 let buffer = handle.read(cx);
4755 if buffer.language().is_none()
4756 || buffer.language() == Some(&*language::PLAIN_TEXT)
4757 {
4758 plain_text_buffers.push(handle);
4759 } else if buffer.contains_unknown_injections() {
4760 buffers_with_unknown_injections.push(handle);
4761 }
4762 }
4763
4764 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4765 // and reused later in the invisible worktrees.
4766 plain_text_buffers.sort_by_key(|buffer| {
4767 Reverse(
4768 File::from_dyn(buffer.read(cx).file())
4769 .map(|file| file.worktree.read(cx).is_visible()),
4770 )
4771 });
4772
4773 for buffer in plain_text_buffers {
4774 this.detect_language_for_buffer(&buffer, cx);
4775 if let Some(local) = this.as_local_mut() {
4776 local.initialize_buffer(&buffer, cx);
4777 if local
4778 .registered_buffers
4779 .contains_key(&buffer.read(cx).remote_id())
4780 {
4781 local.register_buffer_with_language_servers(
4782 &buffer,
4783 HashSet::default(),
4784 cx,
4785 );
4786 }
4787 }
4788 }
4789
4790 for buffer in buffers_with_unknown_injections {
4791 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4792 }
4793 });
4794 }
4795 }
4796 })
4797 }
4798
4799 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4800 let buffer = buffer_handle.read(cx);
4801 let content = buffer.as_rope();
4802
4803 let modeline_settings = {
4804 let settings_store = cx.global::<SettingsStore>();
4805 let modeline_lines = settings_store
4806 .raw_user_settings()
4807 .and_then(|s| s.content.modeline_lines)
4808 .or(settings_store.raw_default_settings().modeline_lines)
4809 .unwrap_or(5);
4810
4811 const MAX_MODELINE_BYTES: usize = 1024;
4812
4813 let first_bytes =
4814 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4815 let mut first_lines = Vec::new();
4816 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4817 for _ in 0..modeline_lines {
4818 if let Some(line) = lines.next() {
4819 first_lines.push(line.to_string());
4820 } else {
4821 break;
4822 }
4823 }
4824 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4825
4826 let last_start =
4827 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4828 let mut last_lines = Vec::new();
4829 let mut lines = content
4830 .reversed_chunks_in_range(last_start..content.len())
4831 .lines();
4832 for _ in 0..modeline_lines {
4833 if let Some(line) = lines.next() {
4834 last_lines.push(line.to_string());
4835 } else {
4836 break;
4837 }
4838 }
4839 let last_lines_ref: Vec<_> =
4840 last_lines.iter().rev().map(|line| line.as_str()).collect();
4841 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4842 };
4843
4844 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4845
4846 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4847 }
4848
4849 fn detect_language_for_buffer(
4850 &mut self,
4851 buffer_handle: &Entity<Buffer>,
4852 cx: &mut Context<Self>,
4853 ) -> Option<language::AvailableLanguage> {
4854 // If the buffer has a language, set it and start the language server if we haven't already.
4855 let buffer = buffer_handle.read(cx);
4856 let file = buffer.file()?;
4857 let content = buffer.as_rope();
4858 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4859
4860 let available_language = if let Some(ModelineSettings {
4861 mode: Some(mode_name),
4862 ..
4863 }) = modeline_settings
4864 {
4865 self.languages
4866 .available_language_for_modeline_name(mode_name)
4867 } else {
4868 self.languages.language_for_file(file, Some(content), cx)
4869 };
4870 if let Some(available_language) = &available_language {
4871 if let Some(Ok(Ok(new_language))) = self
4872 .languages
4873 .load_language(available_language)
4874 .now_or_never()
4875 {
4876 self.set_language_for_buffer(buffer_handle, new_language, cx);
4877 }
4878 } else {
4879 cx.emit(LspStoreEvent::LanguageDetected {
4880 buffer: buffer_handle.clone(),
4881 new_language: None,
4882 });
4883 }
4884
4885 available_language
4886 }
4887
4888 pub(crate) fn set_language_for_buffer(
4889 &mut self,
4890 buffer_entity: &Entity<Buffer>,
4891 new_language: Arc<Language>,
4892 cx: &mut Context<Self>,
4893 ) {
4894 let buffer = buffer_entity.read(cx);
4895 let buffer_file = buffer.file().cloned();
4896 let buffer_id = buffer.remote_id();
4897 if let Some(local_store) = self.as_local_mut()
4898 && local_store.registered_buffers.contains_key(&buffer_id)
4899 && let Some(abs_path) =
4900 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4901 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4902 {
4903 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4904 }
4905 buffer_entity.update(cx, |buffer, cx| {
4906 if buffer
4907 .language()
4908 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4909 {
4910 buffer.set_language_async(Some(new_language.clone()), cx);
4911 }
4912 });
4913
4914 let settings = LanguageSettings::resolve(
4915 Some(&buffer_entity.read(cx)),
4916 Some(&new_language.name()),
4917 cx,
4918 )
4919 .into_owned();
4920 let buffer_file = File::from_dyn(buffer_file.as_ref());
4921
4922 let worktree_id = if let Some(file) = buffer_file {
4923 let worktree = file.worktree.clone();
4924
4925 if let Some(local) = self.as_local_mut()
4926 && local.registered_buffers.contains_key(&buffer_id)
4927 {
4928 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4929 }
4930 Some(worktree.read(cx).id())
4931 } else {
4932 None
4933 };
4934
4935 if settings.prettier.allowed
4936 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4937 {
4938 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4939 if let Some(prettier_store) = prettier_store {
4940 prettier_store.update(cx, |prettier_store, cx| {
4941 prettier_store.install_default_prettier(
4942 worktree_id,
4943 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4944 cx,
4945 )
4946 })
4947 }
4948 }
4949
4950 cx.emit(LspStoreEvent::LanguageDetected {
4951 buffer: buffer_entity.clone(),
4952 new_language: Some(new_language),
4953 })
4954 }
4955
4956 pub fn buffer_store(&self) -> Entity<BufferStore> {
4957 self.buffer_store.clone()
4958 }
4959
4960 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4961 self.active_entry = active_entry;
4962 }
4963
4964 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4965 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4966 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4967 {
4968 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4969 summaries
4970 .iter()
4971 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4972 });
4973 if let Some(summary) = summaries.next() {
4974 client
4975 .send(proto::UpdateDiagnosticSummary {
4976 project_id: downstream_project_id,
4977 worktree_id: worktree.id().to_proto(),
4978 summary: Some(summary),
4979 more_summaries: summaries.collect(),
4980 })
4981 .log_err();
4982 }
4983 }
4984 }
4985
4986 fn is_capable_for_proto_request<R>(
4987 &self,
4988 buffer: &Entity<Buffer>,
4989 request: &R,
4990 cx: &App,
4991 ) -> bool
4992 where
4993 R: LspCommand,
4994 {
4995 self.check_if_capable_for_proto_request(
4996 buffer,
4997 |capabilities| {
4998 request.check_capabilities(AdapterServerCapabilities {
4999 server_capabilities: capabilities.clone(),
5000 code_action_kinds: None,
5001 })
5002 },
5003 cx,
5004 )
5005 }
5006
5007 fn check_if_capable_for_proto_request<F>(
5008 &self,
5009 buffer: &Entity<Buffer>,
5010 check: F,
5011 cx: &App,
5012 ) -> bool
5013 where
5014 F: FnMut(&lsp::ServerCapabilities) -> bool,
5015 {
5016 let Some(language) = buffer.read(cx).language().cloned() else {
5017 return false;
5018 };
5019 let registered_language_servers = self
5020 .languages
5021 .lsp_adapters(&language.name())
5022 .into_iter()
5023 .map(|lsp_adapter| lsp_adapter.name())
5024 .collect::<HashSet<_>>();
5025 self.language_server_statuses
5026 .iter()
5027 .filter_map(|(server_id, server_status)| {
5028 // Include servers that are either registered for this language OR
5029 // available to be loaded (for SSH remote mode where adapters like
5030 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5031 // but only loaded on the server side)
5032 let is_relevant = registered_language_servers.contains(&server_status.name)
5033 || self.languages.is_lsp_adapter_available(&server_status.name);
5034 is_relevant.then_some(server_id)
5035 })
5036 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
5037 .any(check)
5038 }
5039
5040 fn all_capable_for_proto_request<F>(
5041 &self,
5042 buffer: &Entity<Buffer>,
5043 mut check: F,
5044 cx: &App,
5045 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5046 where
5047 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5048 {
5049 let Some(language) = buffer.read(cx).language().cloned() else {
5050 return Vec::default();
5051 };
5052 let registered_language_servers = self
5053 .languages
5054 .lsp_adapters(&language.name())
5055 .into_iter()
5056 .map(|lsp_adapter| lsp_adapter.name())
5057 .collect::<HashSet<_>>();
5058 self.language_server_statuses
5059 .iter()
5060 .filter_map(|(server_id, server_status)| {
5061 // Include servers that are either registered for this language OR
5062 // available to be loaded (for SSH remote mode where adapters like
5063 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5064 // but only loaded on the server side)
5065 let is_relevant = registered_language_servers.contains(&server_status.name)
5066 || self.languages.is_lsp_adapter_available(&server_status.name);
5067 is_relevant.then_some((server_id, &server_status.name))
5068 })
5069 .filter_map(|(server_id, server_name)| {
5070 self.lsp_server_capabilities
5071 .get(server_id)
5072 .map(|c| (server_id, server_name, c))
5073 })
5074 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5075 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5076 .collect()
5077 }
5078
5079 pub fn request_lsp<R>(
5080 &mut self,
5081 buffer: Entity<Buffer>,
5082 server: LanguageServerToQuery,
5083 request: R,
5084 cx: &mut Context<Self>,
5085 ) -> Task<Result<R::Response>>
5086 where
5087 R: LspCommand,
5088 <R::LspRequest as lsp::request::Request>::Result: Send,
5089 <R::LspRequest as lsp::request::Request>::Params: Send,
5090 {
5091 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5092 return self.send_lsp_proto_request(
5093 buffer,
5094 upstream_client,
5095 upstream_project_id,
5096 request,
5097 cx,
5098 );
5099 }
5100
5101 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5102 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5103 local
5104 .language_servers_for_buffer(buffer, cx)
5105 .find(|(_, server)| {
5106 request.check_capabilities(server.adapter_server_capabilities())
5107 })
5108 .map(|(_, server)| server.clone())
5109 }),
5110 LanguageServerToQuery::Other(id) => self
5111 .language_server_for_local_buffer(buffer, id, cx)
5112 .and_then(|(_, server)| {
5113 request
5114 .check_capabilities(server.adapter_server_capabilities())
5115 .then(|| Arc::clone(server))
5116 }),
5117 }) else {
5118 return Task::ready(Ok(Default::default()));
5119 };
5120
5121 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5122
5123 let Some(file) = file else {
5124 return Task::ready(Ok(Default::default()));
5125 };
5126
5127 let lsp_params = match request.to_lsp_params_or_response(
5128 &file.abs_path(cx),
5129 buffer.read(cx),
5130 &language_server,
5131 cx,
5132 ) {
5133 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5134 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5135 Err(err) => {
5136 let message = format!(
5137 "{} via {} failed: {}",
5138 request.display_name(),
5139 language_server.name(),
5140 err
5141 );
5142 // rust-analyzer likes to error with this when its still loading up
5143 if !message.ends_with("content modified") {
5144 log::warn!("{message}");
5145 }
5146 return Task::ready(Err(anyhow!(message)));
5147 }
5148 };
5149
5150 let status = request.status();
5151 let request_timeout = ProjectSettings::get_global(cx)
5152 .global_lsp_settings
5153 .get_request_timeout();
5154
5155 cx.spawn(async move |this, cx| {
5156 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5157
5158 let id = lsp_request.id();
5159 let _cleanup = if status.is_some() {
5160 cx.update(|cx| {
5161 this.update(cx, |this, cx| {
5162 this.on_lsp_work_start(
5163 language_server.server_id(),
5164 ProgressToken::Number(id),
5165 LanguageServerProgress {
5166 is_disk_based_diagnostics_progress: false,
5167 is_cancellable: false,
5168 title: None,
5169 message: status.clone(),
5170 percentage: None,
5171 last_update_at: cx.background_executor().now(),
5172 },
5173 cx,
5174 );
5175 })
5176 })
5177 .log_err();
5178
5179 Some(defer(|| {
5180 cx.update(|cx| {
5181 this.update(cx, |this, cx| {
5182 this.on_lsp_work_end(
5183 language_server.server_id(),
5184 ProgressToken::Number(id),
5185 cx,
5186 );
5187 })
5188 })
5189 .log_err();
5190 }))
5191 } else {
5192 None
5193 };
5194
5195 let result = lsp_request.await.into_response();
5196
5197 let response = result.map_err(|err| {
5198 let message = format!(
5199 "{} via {} failed: {}",
5200 request.display_name(),
5201 language_server.name(),
5202 err
5203 );
5204 // rust-analyzer likes to error with this when its still loading up
5205 if !message.ends_with("content modified") {
5206 log::warn!("{message}");
5207 }
5208 anyhow::anyhow!(message)
5209 })?;
5210
5211 request
5212 .response_from_lsp(
5213 response,
5214 this.upgrade().context("no app context")?,
5215 buffer,
5216 language_server.server_id(),
5217 cx.clone(),
5218 )
5219 .await
5220 })
5221 }
5222
5223 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5224 let mut language_formatters_to_check = Vec::new();
5225 for buffer in self.buffer_store.read(cx).buffers() {
5226 let buffer = buffer.read(cx);
5227 let settings = LanguageSettings::for_buffer(buffer, cx);
5228 if buffer.language().is_some() {
5229 let buffer_file = File::from_dyn(buffer.file());
5230 language_formatters_to_check.push((
5231 buffer_file.map(|f| f.worktree_id(cx)),
5232 settings.into_owned(),
5233 ));
5234 }
5235 }
5236
5237 self.request_workspace_config_refresh();
5238
5239 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5240 prettier_store.update(cx, |prettier_store, cx| {
5241 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5242 })
5243 }
5244
5245 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5246 .global_lsp_settings
5247 .semantic_token_rules
5248 .clone();
5249 self.semantic_token_config
5250 .update_rules(new_semantic_token_rules);
5251 // Always clear cached stylizers so that changes to language-specific
5252 // semantic token rules (e.g. from extension install/uninstall) are
5253 // picked up. Stylizers are recreated lazily, so this is cheap.
5254 self.semantic_token_config.clear_stylizers();
5255
5256 let new_global_semantic_tokens_mode =
5257 all_language_settings(None, cx).defaults.semantic_tokens;
5258 if self
5259 .semantic_token_config
5260 .update_global_mode(new_global_semantic_tokens_mode)
5261 {
5262 self.restart_all_language_servers(cx);
5263 }
5264
5265 cx.notify();
5266 }
5267
5268 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5269 let buffer_store = self.buffer_store.clone();
5270 let Some(local) = self.as_local_mut() else {
5271 return;
5272 };
5273 let mut adapters = BTreeMap::default();
5274 let get_adapter = {
5275 let languages = local.languages.clone();
5276 let environment = local.environment.clone();
5277 let weak = local.weak.clone();
5278 let worktree_store = local.worktree_store.clone();
5279 let http_client = local.http_client.clone();
5280 let fs = local.fs.clone();
5281 move |worktree_id, cx: &mut App| {
5282 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5283 Some(LocalLspAdapterDelegate::new(
5284 languages.clone(),
5285 &environment,
5286 weak.clone(),
5287 &worktree,
5288 http_client.clone(),
5289 fs.clone(),
5290 cx,
5291 ))
5292 }
5293 };
5294
5295 let mut messages_to_report = Vec::new();
5296 let (new_tree, to_stop) = {
5297 let mut rebase = local.lsp_tree.rebase();
5298 let buffers = buffer_store
5299 .read(cx)
5300 .buffers()
5301 .filter_map(|buffer| {
5302 let raw_buffer = buffer.read(cx);
5303 if !local
5304 .registered_buffers
5305 .contains_key(&raw_buffer.remote_id())
5306 {
5307 return None;
5308 }
5309 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5310 let language = raw_buffer.language().cloned()?;
5311 Some((file, language, raw_buffer.remote_id()))
5312 })
5313 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5314 for (file, language, buffer_id) in buffers {
5315 let worktree_id = file.worktree_id(cx);
5316 let Some(worktree) = local
5317 .worktree_store
5318 .read(cx)
5319 .worktree_for_id(worktree_id, cx)
5320 else {
5321 continue;
5322 };
5323
5324 if let Some((_, apply)) = local.reuse_existing_language_server(
5325 rebase.server_tree(),
5326 &worktree,
5327 &language.name(),
5328 cx,
5329 ) {
5330 (apply)(rebase.server_tree());
5331 } else if let Some(lsp_delegate) = adapters
5332 .entry(worktree_id)
5333 .or_insert_with(|| get_adapter(worktree_id, cx))
5334 .clone()
5335 {
5336 let delegate =
5337 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5338 let path = file
5339 .path()
5340 .parent()
5341 .map(Arc::from)
5342 .unwrap_or_else(|| file.path().clone());
5343 let worktree_path = ProjectPath { worktree_id, path };
5344 let abs_path = file.abs_path(cx);
5345 let nodes = rebase
5346 .walk(
5347 worktree_path,
5348 language.name(),
5349 language.manifest(),
5350 delegate.clone(),
5351 cx,
5352 )
5353 .collect::<Vec<_>>();
5354 for node in nodes {
5355 let server_id = node.server_id_or_init(|disposition| {
5356 let path = &disposition.path;
5357 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5358 let key = LanguageServerSeed {
5359 worktree_id,
5360 name: disposition.server_name.clone(),
5361 settings: LanguageServerSeedSettings {
5362 binary: disposition.settings.binary.clone(),
5363 initialization_options: disposition
5364 .settings
5365 .initialization_options
5366 .clone(),
5367 },
5368 toolchain: local.toolchain_store.read(cx).active_toolchain(
5369 path.worktree_id,
5370 &path.path,
5371 language.name(),
5372 ),
5373 };
5374 local.language_server_ids.remove(&key);
5375
5376 let server_id = local.get_or_insert_language_server(
5377 &worktree,
5378 lsp_delegate.clone(),
5379 disposition,
5380 &language.name(),
5381 cx,
5382 );
5383 if let Some(state) = local.language_servers.get(&server_id)
5384 && let Ok(uri) = uri
5385 {
5386 state.add_workspace_folder(uri);
5387 };
5388 server_id
5389 });
5390
5391 if let Some(language_server_id) = server_id {
5392 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5393 language_server_id,
5394 name: node.name(),
5395 message:
5396 proto::update_language_server::Variant::RegisteredForBuffer(
5397 proto::RegisteredForBuffer {
5398 buffer_abs_path: abs_path
5399 .to_string_lossy()
5400 .into_owned(),
5401 buffer_id: buffer_id.to_proto(),
5402 },
5403 ),
5404 });
5405 }
5406 }
5407 } else {
5408 continue;
5409 }
5410 }
5411 rebase.finish()
5412 };
5413 for message in messages_to_report {
5414 cx.emit(message);
5415 }
5416 local.lsp_tree = new_tree;
5417 for (id, _) in to_stop {
5418 self.stop_local_language_server(id, cx).detach();
5419 }
5420 }
5421
5422 pub fn apply_code_action(
5423 &self,
5424 buffer_handle: Entity<Buffer>,
5425 mut action: CodeAction,
5426 push_to_history: bool,
5427 cx: &mut Context<Self>,
5428 ) -> Task<Result<ProjectTransaction>> {
5429 if let Some((upstream_client, project_id)) = self.upstream_client() {
5430 let request = proto::ApplyCodeAction {
5431 project_id,
5432 buffer_id: buffer_handle.read(cx).remote_id().into(),
5433 action: Some(Self::serialize_code_action(&action)),
5434 };
5435 let buffer_store = self.buffer_store();
5436 cx.spawn(async move |_, cx| {
5437 let response = upstream_client
5438 .request(request)
5439 .await?
5440 .transaction
5441 .context("missing transaction")?;
5442
5443 buffer_store
5444 .update(cx, |buffer_store, cx| {
5445 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5446 })
5447 .await
5448 })
5449 } else if self.mode.is_local() {
5450 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5451 let request_timeout = ProjectSettings::get_global(cx)
5452 .global_lsp_settings
5453 .get_request_timeout();
5454 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5455 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5456 }) else {
5457 return Task::ready(Ok(ProjectTransaction::default()));
5458 };
5459
5460 cx.spawn(async move |this, cx| {
5461 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5462 .await
5463 .context("resolving a code action")?;
5464 if let Some(edit) = action.lsp_action.edit()
5465 && (edit.changes.is_some() || edit.document_changes.is_some())
5466 {
5467 return LocalLspStore::deserialize_workspace_edit(
5468 this.upgrade().context("no app present")?,
5469 edit.clone(),
5470 push_to_history,
5471 lang_server.clone(),
5472 cx,
5473 )
5474 .await;
5475 }
5476
5477 let Some(command) = action.lsp_action.command() else {
5478 return Ok(ProjectTransaction::default());
5479 };
5480
5481 let server_capabilities = lang_server.capabilities();
5482 let available_commands = server_capabilities
5483 .execute_command_provider
5484 .as_ref()
5485 .map(|options| options.commands.as_slice())
5486 .unwrap_or_default();
5487
5488 if !available_commands.contains(&command.command) {
5489 log::warn!(
5490 "Executing command {} not listed in the language server capabilities",
5491 command.command
5492 );
5493 }
5494
5495 let request_timeout = cx.update(|app| {
5496 ProjectSettings::get_global(app)
5497 .global_lsp_settings
5498 .get_request_timeout()
5499 });
5500
5501 this.update(cx, |this, _| {
5502 this.as_local_mut()
5503 .unwrap()
5504 .last_workspace_edits_by_language_server
5505 .remove(&lang_server.server_id());
5506 })?;
5507
5508 let _result = lang_server
5509 .request::<lsp::request::ExecuteCommand>(
5510 lsp::ExecuteCommandParams {
5511 command: command.command.clone(),
5512 arguments: command.arguments.clone().unwrap_or_default(),
5513 ..lsp::ExecuteCommandParams::default()
5514 },
5515 request_timeout,
5516 )
5517 .await
5518 .into_response()
5519 .context("execute command")?;
5520
5521 return this.update(cx, |this, _| {
5522 this.as_local_mut()
5523 .unwrap()
5524 .last_workspace_edits_by_language_server
5525 .remove(&lang_server.server_id())
5526 .unwrap_or_default()
5527 });
5528 })
5529 } else {
5530 Task::ready(Err(anyhow!("no upstream client and not local")))
5531 }
5532 }
5533
5534 pub fn apply_code_action_kind(
5535 &mut self,
5536 buffers: HashSet<Entity<Buffer>>,
5537 kind: CodeActionKind,
5538 push_to_history: bool,
5539 cx: &mut Context<Self>,
5540 ) -> Task<anyhow::Result<ProjectTransaction>> {
5541 if self.as_local().is_some() {
5542 cx.spawn(async move |lsp_store, cx| {
5543 let buffers = buffers.into_iter().collect::<Vec<_>>();
5544 let result = LocalLspStore::execute_code_action_kind_locally(
5545 lsp_store.clone(),
5546 buffers,
5547 kind,
5548 push_to_history,
5549 cx,
5550 )
5551 .await;
5552 lsp_store.update(cx, |lsp_store, _| {
5553 lsp_store.update_last_formatting_failure(&result);
5554 })?;
5555 result
5556 })
5557 } else if let Some((client, project_id)) = self.upstream_client() {
5558 let buffer_store = self.buffer_store();
5559 cx.spawn(async move |lsp_store, cx| {
5560 let result = client
5561 .request(proto::ApplyCodeActionKind {
5562 project_id,
5563 kind: kind.as_str().to_owned(),
5564 buffer_ids: buffers
5565 .iter()
5566 .map(|buffer| {
5567 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5568 })
5569 .collect(),
5570 })
5571 .await
5572 .and_then(|result| result.transaction.context("missing transaction"));
5573 lsp_store.update(cx, |lsp_store, _| {
5574 lsp_store.update_last_formatting_failure(&result);
5575 })?;
5576
5577 let transaction_response = result?;
5578 buffer_store
5579 .update(cx, |buffer_store, cx| {
5580 buffer_store.deserialize_project_transaction(
5581 transaction_response,
5582 push_to_history,
5583 cx,
5584 )
5585 })
5586 .await
5587 })
5588 } else {
5589 Task::ready(Ok(ProjectTransaction::default()))
5590 }
5591 }
5592
5593 pub fn resolved_hint(
5594 &mut self,
5595 buffer_id: BufferId,
5596 id: InlayId,
5597 cx: &mut Context<Self>,
5598 ) -> Option<ResolvedHint> {
5599 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5600
5601 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5602 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5603 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5604 let (server_id, resolve_data) = match &hint.resolve_state {
5605 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5606 ResolveState::Resolving => {
5607 return Some(ResolvedHint::Resolving(
5608 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5609 ));
5610 }
5611 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5612 };
5613
5614 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5615 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5616 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5617 id,
5618 cx.spawn(async move |lsp_store, cx| {
5619 let resolved_hint = resolve_task.await;
5620 lsp_store
5621 .update(cx, |lsp_store, _| {
5622 if let Some(old_inlay_hint) = lsp_store
5623 .lsp_data
5624 .get_mut(&buffer_id)
5625 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5626 {
5627 match resolved_hint {
5628 Ok(resolved_hint) => {
5629 *old_inlay_hint = resolved_hint;
5630 }
5631 Err(e) => {
5632 old_inlay_hint.resolve_state =
5633 ResolveState::CanResolve(server_id, resolve_data);
5634 log::error!("Inlay hint resolve failed: {e:#}");
5635 }
5636 }
5637 }
5638 })
5639 .ok();
5640 })
5641 .shared(),
5642 );
5643 debug_assert!(
5644 previous_task.is_none(),
5645 "Did not change hint's resolve state after spawning its resolve"
5646 );
5647 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5648 None
5649 }
5650
5651 pub(crate) fn linked_edits(
5652 &mut self,
5653 buffer: &Entity<Buffer>,
5654 position: Anchor,
5655 cx: &mut Context<Self>,
5656 ) -> Task<Result<Vec<Range<Anchor>>>> {
5657 let snapshot = buffer.read(cx).snapshot();
5658 let scope = snapshot.language_scope_at(position);
5659 let Some(server_id) = self
5660 .as_local()
5661 .and_then(|local| {
5662 buffer.update(cx, |buffer, cx| {
5663 local
5664 .language_servers_for_buffer(buffer, cx)
5665 .filter(|(_, server)| {
5666 LinkedEditingRange::check_server_capabilities(server.capabilities())
5667 })
5668 .filter(|(adapter, _)| {
5669 scope
5670 .as_ref()
5671 .map(|scope| scope.language_allowed(&adapter.name))
5672 .unwrap_or(true)
5673 })
5674 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5675 .next()
5676 })
5677 })
5678 .or_else(|| {
5679 self.upstream_client()
5680 .is_some()
5681 .then_some(LanguageServerToQuery::FirstCapable)
5682 })
5683 .filter(|_| {
5684 maybe!({
5685 buffer.read(cx).language_at(position)?;
5686 Some(
5687 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5688 .linked_edits,
5689 )
5690 }) == Some(true)
5691 })
5692 else {
5693 return Task::ready(Ok(Vec::new()));
5694 };
5695
5696 self.request_lsp(
5697 buffer.clone(),
5698 server_id,
5699 LinkedEditingRange { position },
5700 cx,
5701 )
5702 }
5703
5704 fn apply_on_type_formatting(
5705 &mut self,
5706 buffer: Entity<Buffer>,
5707 position: Anchor,
5708 trigger: String,
5709 cx: &mut Context<Self>,
5710 ) -> Task<Result<Option<Transaction>>> {
5711 if let Some((client, project_id)) = self.upstream_client() {
5712 if !self.check_if_capable_for_proto_request(
5713 &buffer,
5714 |capabilities| {
5715 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5716 },
5717 cx,
5718 ) {
5719 return Task::ready(Ok(None));
5720 }
5721 let request = proto::OnTypeFormatting {
5722 project_id,
5723 buffer_id: buffer.read(cx).remote_id().into(),
5724 position: Some(serialize_anchor(&position)),
5725 trigger,
5726 version: serialize_version(&buffer.read(cx).version()),
5727 };
5728 cx.background_spawn(async move {
5729 client
5730 .request(request)
5731 .await?
5732 .transaction
5733 .map(language::proto::deserialize_transaction)
5734 .transpose()
5735 })
5736 } else if let Some(local) = self.as_local_mut() {
5737 let buffer_id = buffer.read(cx).remote_id();
5738 local.buffers_being_formatted.insert(buffer_id);
5739 cx.spawn(async move |this, cx| {
5740 let _cleanup = defer({
5741 let this = this.clone();
5742 let mut cx = cx.clone();
5743 move || {
5744 this.update(&mut cx, |this, _| {
5745 if let Some(local) = this.as_local_mut() {
5746 local.buffers_being_formatted.remove(&buffer_id);
5747 }
5748 })
5749 .ok();
5750 }
5751 });
5752
5753 buffer
5754 .update(cx, |buffer, _| {
5755 buffer.wait_for_edits(Some(position.timestamp()))
5756 })
5757 .await?;
5758 this.update(cx, |this, cx| {
5759 let position = position.to_point_utf16(buffer.read(cx));
5760 this.on_type_format(buffer, position, trigger, false, cx)
5761 })?
5762 .await
5763 })
5764 } else {
5765 Task::ready(Err(anyhow!("No upstream client or local language server")))
5766 }
5767 }
5768
5769 pub fn on_type_format<T: ToPointUtf16>(
5770 &mut self,
5771 buffer: Entity<Buffer>,
5772 position: T,
5773 trigger: String,
5774 push_to_history: bool,
5775 cx: &mut Context<Self>,
5776 ) -> Task<Result<Option<Transaction>>> {
5777 let position = position.to_point_utf16(buffer.read(cx));
5778 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5779 }
5780
5781 fn on_type_format_impl(
5782 &mut self,
5783 buffer: Entity<Buffer>,
5784 position: PointUtf16,
5785 trigger: String,
5786 push_to_history: bool,
5787 cx: &mut Context<Self>,
5788 ) -> Task<Result<Option<Transaction>>> {
5789 let options = buffer.update(cx, |buffer, cx| {
5790 lsp_command::lsp_formatting_options(
5791 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5792 )
5793 });
5794
5795 cx.spawn(async move |this, cx| {
5796 if let Some(waiter) =
5797 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5798 {
5799 waiter.await?;
5800 }
5801 cx.update(|cx| {
5802 this.update(cx, |this, cx| {
5803 this.request_lsp(
5804 buffer.clone(),
5805 LanguageServerToQuery::FirstCapable,
5806 OnTypeFormatting {
5807 position,
5808 trigger,
5809 options,
5810 push_to_history,
5811 },
5812 cx,
5813 )
5814 })
5815 })?
5816 .await
5817 })
5818 }
5819
5820 pub fn definitions(
5821 &mut self,
5822 buffer: &Entity<Buffer>,
5823 position: PointUtf16,
5824 cx: &mut Context<Self>,
5825 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5826 if let Some((upstream_client, project_id)) = self.upstream_client() {
5827 let request = GetDefinitions { position };
5828 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5829 return Task::ready(Ok(None));
5830 }
5831
5832 let request_timeout = ProjectSettings::get_global(cx)
5833 .global_lsp_settings
5834 .get_request_timeout();
5835
5836 let request_task = upstream_client.request_lsp(
5837 project_id,
5838 None,
5839 request_timeout,
5840 cx.background_executor().clone(),
5841 request.to_proto(project_id, buffer.read(cx)),
5842 );
5843 let buffer = buffer.clone();
5844 cx.spawn(async move |weak_lsp_store, cx| {
5845 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5846 return Ok(None);
5847 };
5848 let Some(responses) = request_task.await? else {
5849 return Ok(None);
5850 };
5851 let actions = join_all(responses.payload.into_iter().map(|response| {
5852 GetDefinitions { position }.response_from_proto(
5853 response.response,
5854 lsp_store.clone(),
5855 buffer.clone(),
5856 cx.clone(),
5857 )
5858 }))
5859 .await;
5860
5861 Ok(Some(
5862 actions
5863 .into_iter()
5864 .collect::<Result<Vec<Vec<_>>>>()?
5865 .into_iter()
5866 .flatten()
5867 .dedup()
5868 .collect(),
5869 ))
5870 })
5871 } else {
5872 let definitions_task = self.request_multiple_lsp_locally(
5873 buffer,
5874 Some(position),
5875 GetDefinitions { position },
5876 cx,
5877 );
5878 cx.background_spawn(async move {
5879 Ok(Some(
5880 definitions_task
5881 .await
5882 .into_iter()
5883 .flat_map(|(_, definitions)| definitions)
5884 .dedup()
5885 .collect(),
5886 ))
5887 })
5888 }
5889 }
5890
5891 pub fn declarations(
5892 &mut self,
5893 buffer: &Entity<Buffer>,
5894 position: PointUtf16,
5895 cx: &mut Context<Self>,
5896 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5897 if let Some((upstream_client, project_id)) = self.upstream_client() {
5898 let request = GetDeclarations { position };
5899 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5900 return Task::ready(Ok(None));
5901 }
5902 let request_timeout = ProjectSettings::get_global(cx)
5903 .global_lsp_settings
5904 .get_request_timeout();
5905 let request_task = upstream_client.request_lsp(
5906 project_id,
5907 None,
5908 request_timeout,
5909 cx.background_executor().clone(),
5910 request.to_proto(project_id, buffer.read(cx)),
5911 );
5912 let buffer = buffer.clone();
5913 cx.spawn(async move |weak_lsp_store, cx| {
5914 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5915 return Ok(None);
5916 };
5917 let Some(responses) = request_task.await? else {
5918 return Ok(None);
5919 };
5920 let actions = join_all(responses.payload.into_iter().map(|response| {
5921 GetDeclarations { position }.response_from_proto(
5922 response.response,
5923 lsp_store.clone(),
5924 buffer.clone(),
5925 cx.clone(),
5926 )
5927 }))
5928 .await;
5929
5930 Ok(Some(
5931 actions
5932 .into_iter()
5933 .collect::<Result<Vec<Vec<_>>>>()?
5934 .into_iter()
5935 .flatten()
5936 .dedup()
5937 .collect(),
5938 ))
5939 })
5940 } else {
5941 let declarations_task = self.request_multiple_lsp_locally(
5942 buffer,
5943 Some(position),
5944 GetDeclarations { position },
5945 cx,
5946 );
5947 cx.background_spawn(async move {
5948 Ok(Some(
5949 declarations_task
5950 .await
5951 .into_iter()
5952 .flat_map(|(_, declarations)| declarations)
5953 .dedup()
5954 .collect(),
5955 ))
5956 })
5957 }
5958 }
5959
5960 pub fn type_definitions(
5961 &mut self,
5962 buffer: &Entity<Buffer>,
5963 position: PointUtf16,
5964 cx: &mut Context<Self>,
5965 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5966 if let Some((upstream_client, project_id)) = self.upstream_client() {
5967 let request = GetTypeDefinitions { position };
5968 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5969 return Task::ready(Ok(None));
5970 }
5971 let request_timeout = ProjectSettings::get_global(cx)
5972 .global_lsp_settings
5973 .get_request_timeout();
5974 let request_task = upstream_client.request_lsp(
5975 project_id,
5976 None,
5977 request_timeout,
5978 cx.background_executor().clone(),
5979 request.to_proto(project_id, buffer.read(cx)),
5980 );
5981 let buffer = buffer.clone();
5982 cx.spawn(async move |weak_lsp_store, cx| {
5983 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5984 return Ok(None);
5985 };
5986 let Some(responses) = request_task.await? else {
5987 return Ok(None);
5988 };
5989 let actions = join_all(responses.payload.into_iter().map(|response| {
5990 GetTypeDefinitions { position }.response_from_proto(
5991 response.response,
5992 lsp_store.clone(),
5993 buffer.clone(),
5994 cx.clone(),
5995 )
5996 }))
5997 .await;
5998
5999 Ok(Some(
6000 actions
6001 .into_iter()
6002 .collect::<Result<Vec<Vec<_>>>>()?
6003 .into_iter()
6004 .flatten()
6005 .dedup()
6006 .collect(),
6007 ))
6008 })
6009 } else {
6010 let type_definitions_task = self.request_multiple_lsp_locally(
6011 buffer,
6012 Some(position),
6013 GetTypeDefinitions { position },
6014 cx,
6015 );
6016 cx.background_spawn(async move {
6017 Ok(Some(
6018 type_definitions_task
6019 .await
6020 .into_iter()
6021 .flat_map(|(_, type_definitions)| type_definitions)
6022 .dedup()
6023 .collect(),
6024 ))
6025 })
6026 }
6027 }
6028
6029 pub fn implementations(
6030 &mut self,
6031 buffer: &Entity<Buffer>,
6032 position: PointUtf16,
6033 cx: &mut Context<Self>,
6034 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6035 if let Some((upstream_client, project_id)) = self.upstream_client() {
6036 let request = GetImplementations { position };
6037 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6038 return Task::ready(Ok(None));
6039 }
6040
6041 let request_timeout = ProjectSettings::get_global(cx)
6042 .global_lsp_settings
6043 .get_request_timeout();
6044 let request_task = upstream_client.request_lsp(
6045 project_id,
6046 None,
6047 request_timeout,
6048 cx.background_executor().clone(),
6049 request.to_proto(project_id, buffer.read(cx)),
6050 );
6051 let buffer = buffer.clone();
6052 cx.spawn(async move |weak_lsp_store, cx| {
6053 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6054 return Ok(None);
6055 };
6056 let Some(responses) = request_task.await? else {
6057 return Ok(None);
6058 };
6059 let actions = join_all(responses.payload.into_iter().map(|response| {
6060 GetImplementations { position }.response_from_proto(
6061 response.response,
6062 lsp_store.clone(),
6063 buffer.clone(),
6064 cx.clone(),
6065 )
6066 }))
6067 .await;
6068
6069 Ok(Some(
6070 actions
6071 .into_iter()
6072 .collect::<Result<Vec<Vec<_>>>>()?
6073 .into_iter()
6074 .flatten()
6075 .dedup()
6076 .collect(),
6077 ))
6078 })
6079 } else {
6080 let implementations_task = self.request_multiple_lsp_locally(
6081 buffer,
6082 Some(position),
6083 GetImplementations { position },
6084 cx,
6085 );
6086 cx.background_spawn(async move {
6087 Ok(Some(
6088 implementations_task
6089 .await
6090 .into_iter()
6091 .flat_map(|(_, implementations)| implementations)
6092 .dedup()
6093 .collect(),
6094 ))
6095 })
6096 }
6097 }
6098
6099 pub fn references(
6100 &mut self,
6101 buffer: &Entity<Buffer>,
6102 position: PointUtf16,
6103 cx: &mut Context<Self>,
6104 ) -> Task<Result<Option<Vec<Location>>>> {
6105 if let Some((upstream_client, project_id)) = self.upstream_client() {
6106 let request = GetReferences { position };
6107 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6108 return Task::ready(Ok(None));
6109 }
6110
6111 let request_timeout = ProjectSettings::get_global(cx)
6112 .global_lsp_settings
6113 .get_request_timeout();
6114 let request_task = upstream_client.request_lsp(
6115 project_id,
6116 None,
6117 request_timeout,
6118 cx.background_executor().clone(),
6119 request.to_proto(project_id, buffer.read(cx)),
6120 );
6121 let buffer = buffer.clone();
6122 cx.spawn(async move |weak_lsp_store, cx| {
6123 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6124 return Ok(None);
6125 };
6126 let Some(responses) = request_task.await? else {
6127 return Ok(None);
6128 };
6129
6130 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6131 GetReferences { position }.response_from_proto(
6132 lsp_response.response,
6133 lsp_store.clone(),
6134 buffer.clone(),
6135 cx.clone(),
6136 )
6137 }))
6138 .await
6139 .into_iter()
6140 .collect::<Result<Vec<Vec<_>>>>()?
6141 .into_iter()
6142 .flatten()
6143 .dedup()
6144 .collect();
6145 Ok(Some(locations))
6146 })
6147 } else {
6148 let references_task = self.request_multiple_lsp_locally(
6149 buffer,
6150 Some(position),
6151 GetReferences { position },
6152 cx,
6153 );
6154 cx.background_spawn(async move {
6155 Ok(Some(
6156 references_task
6157 .await
6158 .into_iter()
6159 .flat_map(|(_, references)| references)
6160 .dedup()
6161 .collect(),
6162 ))
6163 })
6164 }
6165 }
6166
6167 pub fn code_actions(
6168 &mut self,
6169 buffer: &Entity<Buffer>,
6170 range: Range<Anchor>,
6171 kinds: Option<Vec<CodeActionKind>>,
6172 cx: &mut Context<Self>,
6173 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6174 if let Some((upstream_client, project_id)) = self.upstream_client() {
6175 let request = GetCodeActions {
6176 range: range.clone(),
6177 kinds: kinds.clone(),
6178 };
6179 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6180 return Task::ready(Ok(None));
6181 }
6182 let request_timeout = ProjectSettings::get_global(cx)
6183 .global_lsp_settings
6184 .get_request_timeout();
6185 let request_task = upstream_client.request_lsp(
6186 project_id,
6187 None,
6188 request_timeout,
6189 cx.background_executor().clone(),
6190 request.to_proto(project_id, buffer.read(cx)),
6191 );
6192 let buffer = buffer.clone();
6193 cx.spawn(async move |weak_lsp_store, cx| {
6194 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6195 return Ok(None);
6196 };
6197 let Some(responses) = request_task.await? else {
6198 return Ok(None);
6199 };
6200 let actions = join_all(responses.payload.into_iter().map(|response| {
6201 GetCodeActions {
6202 range: range.clone(),
6203 kinds: kinds.clone(),
6204 }
6205 .response_from_proto(
6206 response.response,
6207 lsp_store.clone(),
6208 buffer.clone(),
6209 cx.clone(),
6210 )
6211 }))
6212 .await;
6213
6214 Ok(Some(
6215 actions
6216 .into_iter()
6217 .collect::<Result<Vec<Vec<_>>>>()?
6218 .into_iter()
6219 .flatten()
6220 .collect(),
6221 ))
6222 })
6223 } else {
6224 let all_actions_task = self.request_multiple_lsp_locally(
6225 buffer,
6226 Some(range.start),
6227 GetCodeActions { range, kinds },
6228 cx,
6229 );
6230 cx.background_spawn(async move {
6231 Ok(Some(
6232 all_actions_task
6233 .await
6234 .into_iter()
6235 .flat_map(|(_, actions)| actions)
6236 .collect(),
6237 ))
6238 })
6239 }
6240 }
6241
6242 #[inline(never)]
6243 pub fn completions(
6244 &self,
6245 buffer: &Entity<Buffer>,
6246 position: PointUtf16,
6247 context: CompletionContext,
6248 cx: &mut Context<Self>,
6249 ) -> Task<Result<Vec<CompletionResponse>>> {
6250 let language_registry = self.languages.clone();
6251
6252 if let Some((upstream_client, project_id)) = self.upstream_client() {
6253 let snapshot = buffer.read(cx).snapshot();
6254 let offset = position.to_offset(&snapshot);
6255 let scope = snapshot.language_scope_at(offset);
6256 let capable_lsps = self.all_capable_for_proto_request(
6257 buffer,
6258 |server_name, capabilities| {
6259 capabilities.completion_provider.is_some()
6260 && scope
6261 .as_ref()
6262 .map(|scope| scope.language_allowed(server_name))
6263 .unwrap_or(true)
6264 },
6265 cx,
6266 );
6267 if capable_lsps.is_empty() {
6268 return Task::ready(Ok(Vec::new()));
6269 }
6270
6271 let language = buffer.read(cx).language().cloned();
6272
6273 let buffer = buffer.clone();
6274
6275 cx.spawn(async move |this, cx| {
6276 let requests = join_all(
6277 capable_lsps
6278 .into_iter()
6279 .map(|(id, server_name)| {
6280 let request = GetCompletions {
6281 position,
6282 context: context.clone(),
6283 server_id: Some(id),
6284 };
6285 let buffer = buffer.clone();
6286 let language = language.clone();
6287 let lsp_adapter = language.as_ref().and_then(|language| {
6288 let adapters = language_registry.lsp_adapters(&language.name());
6289 adapters
6290 .iter()
6291 .find(|adapter| adapter.name() == server_name)
6292 .or_else(|| adapters.first())
6293 .cloned()
6294 });
6295 let upstream_client = upstream_client.clone();
6296 let response = this
6297 .update(cx, |this, cx| {
6298 this.send_lsp_proto_request(
6299 buffer,
6300 upstream_client,
6301 project_id,
6302 request,
6303 cx,
6304 )
6305 })
6306 .log_err();
6307 async move {
6308 let response = response?.await.log_err()?;
6309
6310 let completions = populate_labels_for_completions(
6311 response.completions,
6312 language,
6313 lsp_adapter,
6314 )
6315 .await;
6316
6317 Some(CompletionResponse {
6318 completions,
6319 display_options: CompletionDisplayOptions::default(),
6320 is_incomplete: response.is_incomplete,
6321 })
6322 }
6323 })
6324 .collect::<Vec<_>>(),
6325 );
6326 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6327 })
6328 } else if let Some(local) = self.as_local() {
6329 let snapshot = buffer.read(cx).snapshot();
6330 let offset = position.to_offset(&snapshot);
6331 let scope = snapshot.language_scope_at(offset);
6332 let language = snapshot.language().cloned();
6333 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6334 .completions
6335 .clone();
6336 if !completion_settings.lsp {
6337 return Task::ready(Ok(Vec::new()));
6338 }
6339
6340 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6341 local
6342 .language_servers_for_buffer(buffer, cx)
6343 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6344 .filter(|(adapter, _)| {
6345 scope
6346 .as_ref()
6347 .map(|scope| scope.language_allowed(&adapter.name))
6348 .unwrap_or(true)
6349 })
6350 .map(|(_, server)| server.server_id())
6351 .collect()
6352 });
6353
6354 let buffer = buffer.clone();
6355 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6356 let lsp_timeout = if lsp_timeout > 0 {
6357 Some(Duration::from_millis(lsp_timeout))
6358 } else {
6359 None
6360 };
6361 cx.spawn(async move |this, cx| {
6362 let mut tasks = Vec::with_capacity(server_ids.len());
6363 this.update(cx, |lsp_store, cx| {
6364 for server_id in server_ids {
6365 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6366 let lsp_timeout = lsp_timeout
6367 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6368 let mut timeout = cx.background_spawn(async move {
6369 match lsp_timeout {
6370 Some(lsp_timeout) => {
6371 lsp_timeout.await;
6372 true
6373 },
6374 None => false,
6375 }
6376 }).fuse();
6377 let mut lsp_request = lsp_store.request_lsp(
6378 buffer.clone(),
6379 LanguageServerToQuery::Other(server_id),
6380 GetCompletions {
6381 position,
6382 context: context.clone(),
6383 server_id: Some(server_id),
6384 },
6385 cx,
6386 ).fuse();
6387 let new_task = cx.background_spawn(async move {
6388 select_biased! {
6389 response = lsp_request => anyhow::Ok(Some(response?)),
6390 timeout_happened = timeout => {
6391 if timeout_happened {
6392 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6393 Ok(None)
6394 } else {
6395 let completions = lsp_request.await?;
6396 Ok(Some(completions))
6397 }
6398 },
6399 }
6400 });
6401 tasks.push((lsp_adapter, new_task));
6402 }
6403 })?;
6404
6405 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6406 let completion_response = task.await.ok()??;
6407 let completions = populate_labels_for_completions(
6408 completion_response.completions,
6409 language.clone(),
6410 lsp_adapter,
6411 )
6412 .await;
6413 Some(CompletionResponse {
6414 completions,
6415 display_options: CompletionDisplayOptions::default(),
6416 is_incomplete: completion_response.is_incomplete,
6417 })
6418 });
6419
6420 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6421
6422 Ok(responses.into_iter().flatten().collect())
6423 })
6424 } else {
6425 Task::ready(Err(anyhow!("No upstream client or local language server")))
6426 }
6427 }
6428
6429 pub fn resolve_completions(
6430 &self,
6431 buffer: Entity<Buffer>,
6432 completion_indices: Vec<usize>,
6433 completions: Rc<RefCell<Box<[Completion]>>>,
6434 cx: &mut Context<Self>,
6435 ) -> Task<Result<bool>> {
6436 let client = self.upstream_client();
6437 let buffer_id = buffer.read(cx).remote_id();
6438 let buffer_snapshot = buffer.read(cx).snapshot();
6439
6440 if !self.check_if_capable_for_proto_request(
6441 &buffer,
6442 GetCompletions::can_resolve_completions,
6443 cx,
6444 ) {
6445 return Task::ready(Ok(false));
6446 }
6447 cx.spawn(async move |lsp_store, cx| {
6448 let request_timeout = cx.update(|app| {
6449 ProjectSettings::get_global(app)
6450 .global_lsp_settings
6451 .get_request_timeout()
6452 });
6453
6454 let mut did_resolve = false;
6455 if let Some((client, project_id)) = client {
6456 for completion_index in completion_indices {
6457 let server_id = {
6458 let completion = &completions.borrow()[completion_index];
6459 completion.source.server_id()
6460 };
6461 if let Some(server_id) = server_id {
6462 if Self::resolve_completion_remote(
6463 project_id,
6464 server_id,
6465 buffer_id,
6466 completions.clone(),
6467 completion_index,
6468 client.clone(),
6469 )
6470 .await
6471 .log_err()
6472 .is_some()
6473 {
6474 did_resolve = true;
6475 }
6476 } else {
6477 resolve_word_completion(
6478 &buffer_snapshot,
6479 &mut completions.borrow_mut()[completion_index],
6480 );
6481 }
6482 }
6483 } else {
6484 for completion_index in completion_indices {
6485 let server_id = {
6486 let completion = &completions.borrow()[completion_index];
6487 completion.source.server_id()
6488 };
6489 if let Some(server_id) = server_id {
6490 let server_and_adapter = lsp_store
6491 .read_with(cx, |lsp_store, _| {
6492 let server = lsp_store.language_server_for_id(server_id)?;
6493 let adapter =
6494 lsp_store.language_server_adapter_for_id(server.server_id())?;
6495 Some((server, adapter))
6496 })
6497 .ok()
6498 .flatten();
6499 let Some((server, adapter)) = server_and_adapter else {
6500 continue;
6501 };
6502
6503 let resolved = Self::resolve_completion_local(
6504 server,
6505 completions.clone(),
6506 completion_index,
6507 request_timeout,
6508 )
6509 .await
6510 .log_err()
6511 .is_some();
6512 if resolved {
6513 Self::regenerate_completion_labels(
6514 adapter,
6515 &buffer_snapshot,
6516 completions.clone(),
6517 completion_index,
6518 )
6519 .await
6520 .log_err();
6521 did_resolve = true;
6522 }
6523 } else {
6524 resolve_word_completion(
6525 &buffer_snapshot,
6526 &mut completions.borrow_mut()[completion_index],
6527 );
6528 }
6529 }
6530 }
6531
6532 Ok(did_resolve)
6533 })
6534 }
6535
6536 async fn resolve_completion_local(
6537 server: Arc<lsp::LanguageServer>,
6538 completions: Rc<RefCell<Box<[Completion]>>>,
6539 completion_index: usize,
6540 request_timeout: Duration,
6541 ) -> Result<()> {
6542 let server_id = server.server_id();
6543 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6544 return Ok(());
6545 }
6546
6547 let request = {
6548 let completion = &completions.borrow()[completion_index];
6549 match &completion.source {
6550 CompletionSource::Lsp {
6551 lsp_completion,
6552 resolved,
6553 server_id: completion_server_id,
6554 ..
6555 } => {
6556 if *resolved {
6557 return Ok(());
6558 }
6559 anyhow::ensure!(
6560 server_id == *completion_server_id,
6561 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6562 );
6563 server.request::<lsp::request::ResolveCompletionItem>(
6564 *lsp_completion.clone(),
6565 request_timeout,
6566 )
6567 }
6568 CompletionSource::BufferWord { .. }
6569 | CompletionSource::Dap { .. }
6570 | CompletionSource::Custom => {
6571 return Ok(());
6572 }
6573 }
6574 };
6575 let resolved_completion = request
6576 .await
6577 .into_response()
6578 .context("resolve completion")?;
6579
6580 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6581 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6582
6583 let mut completions = completions.borrow_mut();
6584 let completion = &mut completions[completion_index];
6585 if let CompletionSource::Lsp {
6586 lsp_completion,
6587 resolved,
6588 server_id: completion_server_id,
6589 ..
6590 } = &mut completion.source
6591 {
6592 if *resolved {
6593 return Ok(());
6594 }
6595 anyhow::ensure!(
6596 server_id == *completion_server_id,
6597 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6598 );
6599 **lsp_completion = resolved_completion;
6600 *resolved = true;
6601 }
6602 Ok(())
6603 }
6604
6605 async fn regenerate_completion_labels(
6606 adapter: Arc<CachedLspAdapter>,
6607 snapshot: &BufferSnapshot,
6608 completions: Rc<RefCell<Box<[Completion]>>>,
6609 completion_index: usize,
6610 ) -> Result<()> {
6611 let completion_item = completions.borrow()[completion_index]
6612 .source
6613 .lsp_completion(true)
6614 .map(Cow::into_owned);
6615 if let Some(lsp_documentation) = completion_item
6616 .as_ref()
6617 .and_then(|completion_item| completion_item.documentation.clone())
6618 {
6619 let mut completions = completions.borrow_mut();
6620 let completion = &mut completions[completion_index];
6621 completion.documentation = Some(lsp_documentation.into());
6622 } else {
6623 let mut completions = completions.borrow_mut();
6624 let completion = &mut completions[completion_index];
6625 completion.documentation = Some(CompletionDocumentation::Undocumented);
6626 }
6627
6628 let mut new_label = match completion_item {
6629 Some(completion_item) => {
6630 // Some language servers always return `detail` lazily via resolve, regardless of
6631 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6632 // See: https://github.com/yioneko/vtsls/issues/213
6633 let language = snapshot.language();
6634 match language {
6635 Some(language) => {
6636 adapter
6637 .labels_for_completions(
6638 std::slice::from_ref(&completion_item),
6639 language,
6640 )
6641 .await?
6642 }
6643 None => Vec::new(),
6644 }
6645 .pop()
6646 .flatten()
6647 .unwrap_or_else(|| {
6648 CodeLabel::fallback_for_completion(
6649 &completion_item,
6650 language.map(|language| language.as_ref()),
6651 )
6652 })
6653 }
6654 None => CodeLabel::plain(
6655 completions.borrow()[completion_index].new_text.clone(),
6656 None,
6657 ),
6658 };
6659 ensure_uniform_list_compatible_label(&mut new_label);
6660
6661 let mut completions = completions.borrow_mut();
6662 let completion = &mut completions[completion_index];
6663 if completion.label.filter_text() == new_label.filter_text() {
6664 completion.label = new_label;
6665 } else {
6666 log::error!(
6667 "Resolved completion changed display label from {} to {}. \
6668 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6669 completion.label.text(),
6670 new_label.text(),
6671 completion.label.filter_text(),
6672 new_label.filter_text()
6673 );
6674 }
6675
6676 Ok(())
6677 }
6678
6679 async fn resolve_completion_remote(
6680 project_id: u64,
6681 server_id: LanguageServerId,
6682 buffer_id: BufferId,
6683 completions: Rc<RefCell<Box<[Completion]>>>,
6684 completion_index: usize,
6685 client: AnyProtoClient,
6686 ) -> Result<()> {
6687 let lsp_completion = {
6688 let completion = &completions.borrow()[completion_index];
6689 match &completion.source {
6690 CompletionSource::Lsp {
6691 lsp_completion,
6692 resolved,
6693 server_id: completion_server_id,
6694 ..
6695 } => {
6696 anyhow::ensure!(
6697 server_id == *completion_server_id,
6698 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6699 );
6700 if *resolved {
6701 return Ok(());
6702 }
6703 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6704 }
6705 CompletionSource::Custom
6706 | CompletionSource::Dap { .. }
6707 | CompletionSource::BufferWord { .. } => {
6708 return Ok(());
6709 }
6710 }
6711 };
6712 let request = proto::ResolveCompletionDocumentation {
6713 project_id,
6714 language_server_id: server_id.0 as u64,
6715 lsp_completion,
6716 buffer_id: buffer_id.into(),
6717 };
6718
6719 let response = client
6720 .request(request)
6721 .await
6722 .context("completion documentation resolve proto request")?;
6723 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6724
6725 let documentation = if response.documentation.is_empty() {
6726 CompletionDocumentation::Undocumented
6727 } else if response.documentation_is_markdown {
6728 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6729 } else if response.documentation.lines().count() <= 1 {
6730 CompletionDocumentation::SingleLine(response.documentation.into())
6731 } else {
6732 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6733 };
6734
6735 let mut completions = completions.borrow_mut();
6736 let completion = &mut completions[completion_index];
6737 completion.documentation = Some(documentation);
6738 if let CompletionSource::Lsp {
6739 insert_range,
6740 lsp_completion,
6741 resolved,
6742 server_id: completion_server_id,
6743 lsp_defaults: _,
6744 } = &mut completion.source
6745 {
6746 let completion_insert_range = response
6747 .old_insert_start
6748 .and_then(deserialize_anchor)
6749 .zip(response.old_insert_end.and_then(deserialize_anchor));
6750 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6751
6752 if *resolved {
6753 return Ok(());
6754 }
6755 anyhow::ensure!(
6756 server_id == *completion_server_id,
6757 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6758 );
6759 **lsp_completion = resolved_lsp_completion;
6760 *resolved = true;
6761 }
6762
6763 let replace_range = response
6764 .old_replace_start
6765 .and_then(deserialize_anchor)
6766 .zip(response.old_replace_end.and_then(deserialize_anchor));
6767 if let Some((old_replace_start, old_replace_end)) = replace_range
6768 && !response.new_text.is_empty()
6769 {
6770 completion.new_text = response.new_text;
6771 completion.replace_range = old_replace_start..old_replace_end;
6772 }
6773
6774 Ok(())
6775 }
6776
6777 pub fn apply_additional_edits_for_completion(
6778 &self,
6779 buffer_handle: Entity<Buffer>,
6780 completions: Rc<RefCell<Box<[Completion]>>>,
6781 completion_index: usize,
6782 push_to_history: bool,
6783 all_commit_ranges: Vec<Range<language::Anchor>>,
6784 cx: &mut Context<Self>,
6785 ) -> Task<Result<Option<Transaction>>> {
6786 if let Some((client, project_id)) = self.upstream_client() {
6787 let buffer = buffer_handle.read(cx);
6788 let buffer_id = buffer.remote_id();
6789 cx.spawn(async move |_, cx| {
6790 let request = {
6791 let completion = completions.borrow()[completion_index].clone();
6792 proto::ApplyCompletionAdditionalEdits {
6793 project_id,
6794 buffer_id: buffer_id.into(),
6795 completion: Some(Self::serialize_completion(&CoreCompletion {
6796 replace_range: completion.replace_range,
6797 new_text: completion.new_text,
6798 source: completion.source,
6799 })),
6800 all_commit_ranges: all_commit_ranges
6801 .iter()
6802 .cloned()
6803 .map(language::proto::serialize_anchor_range)
6804 .collect(),
6805 }
6806 };
6807
6808 let Some(transaction) = client.request(request).await?.transaction else {
6809 return Ok(None);
6810 };
6811
6812 let transaction = language::proto::deserialize_transaction(transaction)?;
6813 buffer_handle
6814 .update(cx, |buffer, _| {
6815 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6816 })
6817 .await?;
6818 if push_to_history {
6819 buffer_handle.update(cx, |buffer, _| {
6820 buffer.push_transaction(transaction.clone(), Instant::now());
6821 buffer.finalize_last_transaction();
6822 });
6823 }
6824 Ok(Some(transaction))
6825 })
6826 } else {
6827 let request_timeout = ProjectSettings::get_global(cx)
6828 .global_lsp_settings
6829 .get_request_timeout();
6830
6831 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6832 let completion = &completions.borrow()[completion_index];
6833 let server_id = completion.source.server_id()?;
6834 Some(
6835 self.language_server_for_local_buffer(buffer, server_id, cx)?
6836 .1
6837 .clone(),
6838 )
6839 }) else {
6840 return Task::ready(Ok(None));
6841 };
6842
6843 cx.spawn(async move |this, cx| {
6844 Self::resolve_completion_local(
6845 server.clone(),
6846 completions.clone(),
6847 completion_index,
6848 request_timeout,
6849 )
6850 .await
6851 .context("resolving completion")?;
6852 let completion = completions.borrow()[completion_index].clone();
6853 let additional_text_edits = completion
6854 .source
6855 .lsp_completion(true)
6856 .as_ref()
6857 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6858 if let Some(edits) = additional_text_edits {
6859 let edits = this
6860 .update(cx, |this, cx| {
6861 this.as_local_mut().unwrap().edits_from_lsp(
6862 &buffer_handle,
6863 edits,
6864 server.server_id(),
6865 None,
6866 cx,
6867 )
6868 })?
6869 .await?;
6870
6871 buffer_handle.update(cx, |buffer, cx| {
6872 buffer.finalize_last_transaction();
6873 buffer.start_transaction();
6874
6875 for (range, text) in edits {
6876 let primary = &completion.replace_range;
6877
6878 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6879 // and the primary completion is just an insertion (empty range), then this is likely
6880 // an auto-import scenario and should not be considered overlapping
6881 // https://github.com/zed-industries/zed/issues/26136
6882 let is_file_start_auto_import = {
6883 let snapshot = buffer.snapshot();
6884 let primary_start_point = primary.start.to_point(&snapshot);
6885 let range_start_point = range.start.to_point(&snapshot);
6886
6887 let result = primary_start_point.row == 0
6888 && primary_start_point.column == 0
6889 && range_start_point.row == 0
6890 && range_start_point.column == 0;
6891
6892 result
6893 };
6894
6895 let has_overlap = if is_file_start_auto_import {
6896 false
6897 } else {
6898 all_commit_ranges.iter().any(|commit_range| {
6899 let start_within =
6900 commit_range.start.cmp(&range.start, buffer).is_le()
6901 && commit_range.end.cmp(&range.start, buffer).is_ge();
6902 let end_within =
6903 range.start.cmp(&commit_range.end, buffer).is_le()
6904 && range.end.cmp(&commit_range.end, buffer).is_ge();
6905 start_within || end_within
6906 })
6907 };
6908
6909 //Skip additional edits which overlap with the primary completion edit
6910 //https://github.com/zed-industries/zed/pull/1871
6911 if !has_overlap {
6912 buffer.edit([(range, text)], None, cx);
6913 }
6914 }
6915
6916 let transaction = if buffer.end_transaction(cx).is_some() {
6917 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6918 if !push_to_history {
6919 buffer.forget_transaction(transaction.id);
6920 }
6921 Some(transaction)
6922 } else {
6923 None
6924 };
6925 Ok(transaction)
6926 })
6927 } else {
6928 Ok(None)
6929 }
6930 })
6931 }
6932 }
6933
6934 pub fn pull_diagnostics(
6935 &mut self,
6936 buffer: Entity<Buffer>,
6937 cx: &mut Context<Self>,
6938 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6939 let buffer_id = buffer.read(cx).remote_id();
6940
6941 if let Some((client, upstream_project_id)) = self.upstream_client() {
6942 let mut suitable_capabilities = None;
6943 // Are we capable for proto request?
6944 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6945 &buffer,
6946 |capabilities| {
6947 if let Some(caps) = &capabilities.diagnostic_provider {
6948 suitable_capabilities = Some(caps.clone());
6949 true
6950 } else {
6951 false
6952 }
6953 },
6954 cx,
6955 );
6956 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6957 let Some(dynamic_caps) = suitable_capabilities else {
6958 return Task::ready(Ok(None));
6959 };
6960 assert!(any_server_has_diagnostics_provider);
6961
6962 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6963 let request = GetDocumentDiagnostics {
6964 previous_result_id: None,
6965 identifier,
6966 registration_id: None,
6967 };
6968 let request_timeout = ProjectSettings::get_global(cx)
6969 .global_lsp_settings
6970 .get_request_timeout();
6971 let request_task = client.request_lsp(
6972 upstream_project_id,
6973 None,
6974 request_timeout,
6975 cx.background_executor().clone(),
6976 request.to_proto(upstream_project_id, buffer.read(cx)),
6977 );
6978 cx.background_spawn(async move {
6979 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6980 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6981 // Do not attempt to further process the dummy responses here.
6982 let _response = request_task.await?;
6983 Ok(None)
6984 })
6985 } else {
6986 let servers = buffer.update(cx, |buffer, cx| {
6987 self.running_language_servers_for_local_buffer(buffer, cx)
6988 .map(|(_, server)| server.clone())
6989 .collect::<Vec<_>>()
6990 });
6991
6992 let pull_diagnostics = servers
6993 .into_iter()
6994 .flat_map(|server| {
6995 let result = maybe!({
6996 let local = self.as_local()?;
6997 let server_id = server.server_id();
6998 let providers_with_identifiers = local
6999 .language_server_dynamic_registrations
7000 .get(&server_id)
7001 .into_iter()
7002 .flat_map(|registrations| registrations.diagnostics.clone())
7003 .collect::<Vec<_>>();
7004 Some(
7005 providers_with_identifiers
7006 .into_iter()
7007 .map(|(registration_id, dynamic_caps)| {
7008 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7009 let registration_id = registration_id.map(SharedString::from);
7010 let result_id = self.result_id_for_buffer_pull(
7011 server_id,
7012 buffer_id,
7013 ®istration_id,
7014 cx,
7015 );
7016 self.request_lsp(
7017 buffer.clone(),
7018 LanguageServerToQuery::Other(server_id),
7019 GetDocumentDiagnostics {
7020 previous_result_id: result_id,
7021 registration_id,
7022 identifier,
7023 },
7024 cx,
7025 )
7026 })
7027 .collect::<Vec<_>>(),
7028 )
7029 });
7030
7031 result.unwrap_or_default()
7032 })
7033 .collect::<Vec<_>>();
7034
7035 cx.background_spawn(async move {
7036 let mut responses = Vec::new();
7037 for diagnostics in join_all(pull_diagnostics).await {
7038 responses.extend(diagnostics?);
7039 }
7040 Ok(Some(responses))
7041 })
7042 }
7043 }
7044
7045 pub fn applicable_inlay_chunks(
7046 &mut self,
7047 buffer: &Entity<Buffer>,
7048 ranges: &[Range<text::Anchor>],
7049 cx: &mut Context<Self>,
7050 ) -> Vec<Range<BufferRow>> {
7051 let buffer_snapshot = buffer.read(cx).snapshot();
7052 let ranges = ranges
7053 .iter()
7054 .map(|range| range.to_point(&buffer_snapshot))
7055 .collect::<Vec<_>>();
7056
7057 self.latest_lsp_data(buffer, cx)
7058 .inlay_hints
7059 .applicable_chunks(ranges.as_slice())
7060 .map(|chunk| chunk.row_range())
7061 .collect()
7062 }
7063
7064 pub fn invalidate_inlay_hints<'a>(
7065 &'a mut self,
7066 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7067 ) {
7068 for buffer_id in for_buffers {
7069 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7070 lsp_data.inlay_hints.clear();
7071 }
7072 }
7073 }
7074
7075 pub fn inlay_hints(
7076 &mut self,
7077 invalidate: InvalidationStrategy,
7078 buffer: Entity<Buffer>,
7079 ranges: Vec<Range<text::Anchor>>,
7080 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7081 cx: &mut Context<Self>,
7082 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7083 let next_hint_id = self.next_hint_id.clone();
7084 let lsp_data = self.latest_lsp_data(&buffer, cx);
7085 let query_version = lsp_data.buffer_version.clone();
7086 let mut lsp_refresh_requested = false;
7087 let for_server = if let InvalidationStrategy::RefreshRequested {
7088 server_id,
7089 request_id,
7090 } = invalidate
7091 {
7092 let invalidated = lsp_data
7093 .inlay_hints
7094 .invalidate_for_server_refresh(server_id, request_id);
7095 lsp_refresh_requested = invalidated;
7096 Some(server_id)
7097 } else {
7098 None
7099 };
7100 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7101 let known_chunks = known_chunks
7102 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7103 .map(|(_, known_chunks)| known_chunks)
7104 .unwrap_or_default();
7105
7106 let buffer_snapshot = buffer.read(cx).snapshot();
7107 let ranges = ranges
7108 .iter()
7109 .map(|range| range.to_point(&buffer_snapshot))
7110 .collect::<Vec<_>>();
7111
7112 let mut hint_fetch_tasks = Vec::new();
7113 let mut cached_inlay_hints = None;
7114 let mut ranges_to_query = None;
7115 let applicable_chunks = existing_inlay_hints
7116 .applicable_chunks(ranges.as_slice())
7117 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7118 .collect::<Vec<_>>();
7119 if applicable_chunks.is_empty() {
7120 return HashMap::default();
7121 }
7122
7123 for row_chunk in applicable_chunks {
7124 match (
7125 existing_inlay_hints
7126 .cached_hints(&row_chunk)
7127 .filter(|_| !lsp_refresh_requested)
7128 .cloned(),
7129 existing_inlay_hints
7130 .fetched_hints(&row_chunk)
7131 .as_ref()
7132 .filter(|_| !lsp_refresh_requested)
7133 .cloned(),
7134 ) {
7135 (None, None) => {
7136 let chunk_range = row_chunk.anchor_range();
7137 ranges_to_query
7138 .get_or_insert_with(Vec::new)
7139 .push((row_chunk, chunk_range));
7140 }
7141 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7142 (Some(cached_hints), None) => {
7143 for (server_id, cached_hints) in cached_hints {
7144 if for_server.is_none_or(|for_server| for_server == server_id) {
7145 cached_inlay_hints
7146 .get_or_insert_with(HashMap::default)
7147 .entry(row_chunk.row_range())
7148 .or_insert_with(HashMap::default)
7149 .entry(server_id)
7150 .or_insert_with(Vec::new)
7151 .extend(cached_hints);
7152 }
7153 }
7154 }
7155 (Some(cached_hints), Some(fetched_hints)) => {
7156 hint_fetch_tasks.push((row_chunk, fetched_hints));
7157 for (server_id, cached_hints) in cached_hints {
7158 if for_server.is_none_or(|for_server| for_server == server_id) {
7159 cached_inlay_hints
7160 .get_or_insert_with(HashMap::default)
7161 .entry(row_chunk.row_range())
7162 .or_insert_with(HashMap::default)
7163 .entry(server_id)
7164 .or_insert_with(Vec::new)
7165 .extend(cached_hints);
7166 }
7167 }
7168 }
7169 }
7170 }
7171
7172 if hint_fetch_tasks.is_empty()
7173 && ranges_to_query
7174 .as_ref()
7175 .is_none_or(|ranges| ranges.is_empty())
7176 && let Some(cached_inlay_hints) = cached_inlay_hints
7177 {
7178 cached_inlay_hints
7179 .into_iter()
7180 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7181 .collect()
7182 } else {
7183 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7184 // When a server refresh was requested, other servers' cached hints
7185 // are unaffected by the refresh and must be included in the result.
7186 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7187 // removes all visible hints but only adds back the requesting
7188 // server's new hints, permanently losing other servers' hints.
7189 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7190 lsp_data
7191 .inlay_hints
7192 .cached_hints(&chunk)
7193 .cloned()
7194 .unwrap_or_default()
7195 } else {
7196 HashMap::default()
7197 };
7198
7199 let next_hint_id = next_hint_id.clone();
7200 let buffer = buffer.clone();
7201 let query_version = query_version.clone();
7202 let new_inlay_hints = cx
7203 .spawn(async move |lsp_store, cx| {
7204 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7205 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7206 })?;
7207 new_fetch_task
7208 .await
7209 .and_then(|new_hints_by_server| {
7210 lsp_store.update(cx, |lsp_store, cx| {
7211 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7212 let update_cache = lsp_data.buffer_version == query_version;
7213 if new_hints_by_server.is_empty() {
7214 if update_cache {
7215 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7216 }
7217 other_servers_cached
7218 } else {
7219 let mut result = other_servers_cached;
7220 for (server_id, new_hints) in new_hints_by_server {
7221 let new_hints = new_hints
7222 .into_iter()
7223 .map(|new_hint| {
7224 (
7225 InlayId::Hint(next_hint_id.fetch_add(
7226 1,
7227 atomic::Ordering::AcqRel,
7228 )),
7229 new_hint,
7230 )
7231 })
7232 .collect::<Vec<_>>();
7233 if update_cache {
7234 lsp_data.inlay_hints.insert_new_hints(
7235 chunk,
7236 server_id,
7237 new_hints.clone(),
7238 );
7239 }
7240 result.insert(server_id, new_hints);
7241 }
7242 result
7243 }
7244 })
7245 })
7246 .map_err(Arc::new)
7247 })
7248 .shared();
7249
7250 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7251 *fetch_task = Some(new_inlay_hints.clone());
7252 hint_fetch_tasks.push((chunk, new_inlay_hints));
7253 }
7254
7255 cached_inlay_hints
7256 .unwrap_or_default()
7257 .into_iter()
7258 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7259 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7260 (
7261 chunk.row_range(),
7262 cx.spawn(async move |_, _| {
7263 hints_fetch.await.map_err(|e| {
7264 if e.error_code() != ErrorCode::Internal {
7265 anyhow!(e.error_code())
7266 } else {
7267 anyhow!("{e:#}")
7268 }
7269 })
7270 }),
7271 )
7272 }))
7273 .collect()
7274 }
7275 }
7276
7277 fn fetch_inlay_hints(
7278 &mut self,
7279 for_server: Option<LanguageServerId>,
7280 buffer: &Entity<Buffer>,
7281 range: Range<Anchor>,
7282 cx: &mut Context<Self>,
7283 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7284 let request = InlayHints {
7285 range: range.clone(),
7286 };
7287 if let Some((upstream_client, project_id)) = self.upstream_client() {
7288 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7289 return Task::ready(Ok(HashMap::default()));
7290 }
7291 let request_timeout = ProjectSettings::get_global(cx)
7292 .global_lsp_settings
7293 .get_request_timeout();
7294 let request_task = upstream_client.request_lsp(
7295 project_id,
7296 for_server.map(|id| id.to_proto()),
7297 request_timeout,
7298 cx.background_executor().clone(),
7299 request.to_proto(project_id, buffer.read(cx)),
7300 );
7301 let buffer = buffer.clone();
7302 cx.spawn(async move |weak_lsp_store, cx| {
7303 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7304 return Ok(HashMap::default());
7305 };
7306 let Some(responses) = request_task.await? else {
7307 return Ok(HashMap::default());
7308 };
7309
7310 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7311 let lsp_store = lsp_store.clone();
7312 let buffer = buffer.clone();
7313 let cx = cx.clone();
7314 let request = request.clone();
7315 async move {
7316 (
7317 LanguageServerId::from_proto(response.server_id),
7318 request
7319 .response_from_proto(response.response, lsp_store, buffer, cx)
7320 .await,
7321 )
7322 }
7323 }))
7324 .await;
7325
7326 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7327 let mut has_errors = false;
7328 let inlay_hints = inlay_hints
7329 .into_iter()
7330 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7331 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7332 Err(e) => {
7333 has_errors = true;
7334 log::error!("{e:#}");
7335 None
7336 }
7337 })
7338 .map(|(server_id, mut new_hints)| {
7339 new_hints.retain(|hint| {
7340 hint.position.is_valid(&buffer_snapshot)
7341 && range.start.is_valid(&buffer_snapshot)
7342 && range.end.is_valid(&buffer_snapshot)
7343 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7344 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7345 });
7346 (server_id, new_hints)
7347 })
7348 .collect::<HashMap<_, _>>();
7349 anyhow::ensure!(
7350 !has_errors || !inlay_hints.is_empty(),
7351 "Failed to fetch inlay hints"
7352 );
7353 Ok(inlay_hints)
7354 })
7355 } else {
7356 let inlay_hints_task = match for_server {
7357 Some(server_id) => {
7358 let server_task = self.request_lsp(
7359 buffer.clone(),
7360 LanguageServerToQuery::Other(server_id),
7361 request,
7362 cx,
7363 );
7364 cx.background_spawn(async move {
7365 let mut responses = Vec::new();
7366 match server_task.await {
7367 Ok(response) => responses.push((server_id, response)),
7368 // rust-analyzer likes to error with this when its still loading up
7369 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7370 Err(e) => log::error!(
7371 "Error handling response for inlay hints request: {e:#}"
7372 ),
7373 }
7374 responses
7375 })
7376 }
7377 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7378 };
7379 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7380 cx.background_spawn(async move {
7381 Ok(inlay_hints_task
7382 .await
7383 .into_iter()
7384 .map(|(server_id, mut new_hints)| {
7385 new_hints.retain(|hint| {
7386 hint.position.is_valid(&buffer_snapshot)
7387 && range.start.is_valid(&buffer_snapshot)
7388 && range.end.is_valid(&buffer_snapshot)
7389 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7390 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7391 });
7392 (server_id, new_hints)
7393 })
7394 .collect())
7395 })
7396 }
7397 }
7398
7399 fn diagnostic_registration_exists(
7400 &self,
7401 server_id: LanguageServerId,
7402 registration_id: &Option<SharedString>,
7403 ) -> bool {
7404 let Some(local) = self.as_local() else {
7405 return false;
7406 };
7407 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7408 else {
7409 return false;
7410 };
7411 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7412 registrations.diagnostics.contains_key(®istration_key)
7413 }
7414
7415 pub fn pull_diagnostics_for_buffer(
7416 &mut self,
7417 buffer: Entity<Buffer>,
7418 cx: &mut Context<Self>,
7419 ) -> Task<anyhow::Result<()>> {
7420 let diagnostics = self.pull_diagnostics(buffer, cx);
7421 cx.spawn(async move |lsp_store, cx| {
7422 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7423 return Ok(());
7424 };
7425 lsp_store.update(cx, |lsp_store, cx| {
7426 if lsp_store.as_local().is_none() {
7427 return;
7428 }
7429
7430 let mut unchanged_buffers = HashMap::default();
7431 let server_diagnostics_updates = diagnostics
7432 .into_iter()
7433 .filter_map(|diagnostics_set| match diagnostics_set {
7434 LspPullDiagnostics::Response {
7435 server_id,
7436 uri,
7437 diagnostics,
7438 registration_id,
7439 } => Some((server_id, uri, diagnostics, registration_id)),
7440 LspPullDiagnostics::Default => None,
7441 })
7442 .filter(|(server_id, _, _, registration_id)| {
7443 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7444 })
7445 .fold(
7446 HashMap::default(),
7447 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7448 let (result_id, diagnostics) = match diagnostics {
7449 PulledDiagnostics::Unchanged { result_id } => {
7450 unchanged_buffers
7451 .entry(new_registration_id.clone())
7452 .or_insert_with(HashSet::default)
7453 .insert(uri.clone());
7454 (Some(result_id), Vec::new())
7455 }
7456 PulledDiagnostics::Changed {
7457 result_id,
7458 diagnostics,
7459 } => (result_id, diagnostics),
7460 };
7461 let disk_based_sources = Cow::Owned(
7462 lsp_store
7463 .language_server_adapter_for_id(server_id)
7464 .as_ref()
7465 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7466 .unwrap_or(&[])
7467 .to_vec(),
7468 );
7469 acc.entry(server_id)
7470 .or_insert_with(HashMap::default)
7471 .entry(new_registration_id.clone())
7472 .or_insert_with(Vec::new)
7473 .push(DocumentDiagnosticsUpdate {
7474 server_id,
7475 diagnostics: lsp::PublishDiagnosticsParams {
7476 uri,
7477 diagnostics,
7478 version: None,
7479 },
7480 result_id: result_id.map(SharedString::new),
7481 disk_based_sources,
7482 registration_id: new_registration_id,
7483 });
7484 acc
7485 },
7486 );
7487
7488 for diagnostic_updates in server_diagnostics_updates.into_values() {
7489 for (registration_id, diagnostic_updates) in diagnostic_updates {
7490 lsp_store
7491 .merge_lsp_diagnostics(
7492 DiagnosticSourceKind::Pulled,
7493 diagnostic_updates,
7494 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7495 DiagnosticSourceKind::Pulled => {
7496 old_diagnostic.registration_id != registration_id
7497 || unchanged_buffers
7498 .get(&old_diagnostic.registration_id)
7499 .is_some_and(|unchanged_buffers| {
7500 unchanged_buffers.contains(&document_uri)
7501 })
7502 }
7503 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7504 true
7505 }
7506 },
7507 cx,
7508 )
7509 .log_err();
7510 }
7511 }
7512 })
7513 })
7514 }
7515
7516 pub fn signature_help<T: ToPointUtf16>(
7517 &mut self,
7518 buffer: &Entity<Buffer>,
7519 position: T,
7520 cx: &mut Context<Self>,
7521 ) -> Task<Option<Vec<SignatureHelp>>> {
7522 let position = position.to_point_utf16(buffer.read(cx));
7523
7524 if let Some((client, upstream_project_id)) = self.upstream_client() {
7525 let request = GetSignatureHelp { position };
7526 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7527 return Task::ready(None);
7528 }
7529 let request_timeout = ProjectSettings::get_global(cx)
7530 .global_lsp_settings
7531 .get_request_timeout();
7532 let request_task = client.request_lsp(
7533 upstream_project_id,
7534 None,
7535 request_timeout,
7536 cx.background_executor().clone(),
7537 request.to_proto(upstream_project_id, buffer.read(cx)),
7538 );
7539 let buffer = buffer.clone();
7540 cx.spawn(async move |weak_lsp_store, cx| {
7541 let lsp_store = weak_lsp_store.upgrade()?;
7542 let signatures = join_all(
7543 request_task
7544 .await
7545 .log_err()
7546 .flatten()
7547 .map(|response| response.payload)
7548 .unwrap_or_default()
7549 .into_iter()
7550 .map(|response| {
7551 let response = GetSignatureHelp { position }.response_from_proto(
7552 response.response,
7553 lsp_store.clone(),
7554 buffer.clone(),
7555 cx.clone(),
7556 );
7557 async move { response.await.log_err().flatten() }
7558 }),
7559 )
7560 .await
7561 .into_iter()
7562 .flatten()
7563 .collect();
7564 Some(signatures)
7565 })
7566 } else {
7567 let all_actions_task = self.request_multiple_lsp_locally(
7568 buffer,
7569 Some(position),
7570 GetSignatureHelp { position },
7571 cx,
7572 );
7573 cx.background_spawn(async move {
7574 Some(
7575 all_actions_task
7576 .await
7577 .into_iter()
7578 .flat_map(|(_, actions)| actions)
7579 .collect::<Vec<_>>(),
7580 )
7581 })
7582 }
7583 }
7584
7585 pub fn hover(
7586 &mut self,
7587 buffer: &Entity<Buffer>,
7588 position: PointUtf16,
7589 cx: &mut Context<Self>,
7590 ) -> Task<Option<Vec<Hover>>> {
7591 if let Some((client, upstream_project_id)) = self.upstream_client() {
7592 let request = GetHover { position };
7593 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7594 return Task::ready(None);
7595 }
7596 let request_timeout = ProjectSettings::get_global(cx)
7597 .global_lsp_settings
7598 .get_request_timeout();
7599 let request_task = client.request_lsp(
7600 upstream_project_id,
7601 None,
7602 request_timeout,
7603 cx.background_executor().clone(),
7604 request.to_proto(upstream_project_id, buffer.read(cx)),
7605 );
7606 let buffer = buffer.clone();
7607 cx.spawn(async move |weak_lsp_store, cx| {
7608 let lsp_store = weak_lsp_store.upgrade()?;
7609 let hovers = join_all(
7610 request_task
7611 .await
7612 .log_err()
7613 .flatten()
7614 .map(|response| response.payload)
7615 .unwrap_or_default()
7616 .into_iter()
7617 .map(|response| {
7618 let response = GetHover { position }.response_from_proto(
7619 response.response,
7620 lsp_store.clone(),
7621 buffer.clone(),
7622 cx.clone(),
7623 );
7624 async move {
7625 response
7626 .await
7627 .log_err()
7628 .flatten()
7629 .and_then(remove_empty_hover_blocks)
7630 }
7631 }),
7632 )
7633 .await
7634 .into_iter()
7635 .flatten()
7636 .collect();
7637 Some(hovers)
7638 })
7639 } else {
7640 let all_actions_task = self.request_multiple_lsp_locally(
7641 buffer,
7642 Some(position),
7643 GetHover { position },
7644 cx,
7645 );
7646 cx.background_spawn(async move {
7647 Some(
7648 all_actions_task
7649 .await
7650 .into_iter()
7651 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7652 .collect::<Vec<Hover>>(),
7653 )
7654 })
7655 }
7656 }
7657
7658 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7659 let language_registry = self.languages.clone();
7660
7661 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7662 let request = upstream_client.request(proto::GetProjectSymbols {
7663 project_id: *project_id,
7664 query: query.to_string(),
7665 });
7666 cx.foreground_executor().spawn(async move {
7667 let response = request.await?;
7668 let mut symbols = Vec::new();
7669 let core_symbols = response
7670 .symbols
7671 .into_iter()
7672 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7673 .collect::<Vec<_>>();
7674 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7675 .await;
7676 Ok(symbols)
7677 })
7678 } else if let Some(local) = self.as_local() {
7679 struct WorkspaceSymbolsResult {
7680 server_id: LanguageServerId,
7681 lsp_adapter: Arc<CachedLspAdapter>,
7682 worktree: WeakEntity<Worktree>,
7683 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7684 }
7685
7686 let mut requests = Vec::new();
7687 let mut requested_servers = BTreeSet::new();
7688 let request_timeout = ProjectSettings::get_global(cx)
7689 .global_lsp_settings
7690 .get_request_timeout();
7691
7692 for (seed, state) in local.language_server_ids.iter() {
7693 let Some(worktree_handle) = self
7694 .worktree_store
7695 .read(cx)
7696 .worktree_for_id(seed.worktree_id, cx)
7697 else {
7698 continue;
7699 };
7700
7701 let worktree = worktree_handle.read(cx);
7702 if !worktree.is_visible() {
7703 continue;
7704 }
7705
7706 if !requested_servers.insert(state.id) {
7707 continue;
7708 }
7709
7710 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7711 Some(LanguageServerState::Running {
7712 adapter, server, ..
7713 }) => (adapter.clone(), server),
7714
7715 _ => continue,
7716 };
7717
7718 let supports_workspace_symbol_request =
7719 match server.capabilities().workspace_symbol_provider {
7720 Some(OneOf::Left(supported)) => supported,
7721 Some(OneOf::Right(_)) => true,
7722 None => false,
7723 };
7724
7725 if !supports_workspace_symbol_request {
7726 continue;
7727 }
7728
7729 let worktree_handle = worktree_handle.clone();
7730 let server_id = server.server_id();
7731 requests.push(
7732 server
7733 .request::<lsp::request::WorkspaceSymbolRequest>(
7734 lsp::WorkspaceSymbolParams {
7735 query: query.to_string(),
7736 ..Default::default()
7737 },
7738 request_timeout,
7739 )
7740 .map(move |response| {
7741 let lsp_symbols = response
7742 .into_response()
7743 .context("workspace symbols request")
7744 .log_err()
7745 .flatten()
7746 .map(|symbol_response| match symbol_response {
7747 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7748 flat_responses
7749 .into_iter()
7750 .map(|lsp_symbol| {
7751 (
7752 lsp_symbol.name,
7753 lsp_symbol.kind,
7754 lsp_symbol.location,
7755 lsp_symbol.container_name,
7756 )
7757 })
7758 .collect::<Vec<_>>()
7759 }
7760 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7761 nested_responses
7762 .into_iter()
7763 .filter_map(|lsp_symbol| {
7764 let location = match lsp_symbol.location {
7765 OneOf::Left(location) => location,
7766 OneOf::Right(_) => {
7767 log::error!(
7768 "Unexpected: client capabilities \
7769 forbid symbol resolutions in \
7770 workspace.symbol.resolveSupport"
7771 );
7772 return None;
7773 }
7774 };
7775 Some((
7776 lsp_symbol.name,
7777 lsp_symbol.kind,
7778 location,
7779 lsp_symbol.container_name,
7780 ))
7781 })
7782 .collect::<Vec<_>>()
7783 }
7784 })
7785 .unwrap_or_default();
7786
7787 WorkspaceSymbolsResult {
7788 server_id,
7789 lsp_adapter,
7790 worktree: worktree_handle.downgrade(),
7791 lsp_symbols,
7792 }
7793 }),
7794 );
7795 }
7796
7797 cx.spawn(async move |this, cx| {
7798 let responses = futures::future::join_all(requests).await;
7799 let this = match this.upgrade() {
7800 Some(this) => this,
7801 None => return Ok(Vec::new()),
7802 };
7803
7804 let mut symbols = Vec::new();
7805 for result in responses {
7806 let core_symbols = this.update(cx, |this, cx| {
7807 result
7808 .lsp_symbols
7809 .into_iter()
7810 .filter_map(
7811 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7812 let abs_path = symbol_location.uri.to_file_path().ok()?;
7813 let source_worktree = result.worktree.upgrade()?;
7814 let source_worktree_id = source_worktree.read(cx).id();
7815
7816 let path = if let Some((tree, rel_path)) =
7817 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7818 {
7819 let worktree_id = tree.read(cx).id();
7820 SymbolLocation::InProject(ProjectPath {
7821 worktree_id,
7822 path: rel_path,
7823 })
7824 } else {
7825 SymbolLocation::OutsideProject {
7826 signature: this.symbol_signature(&abs_path),
7827 abs_path: abs_path.into(),
7828 }
7829 };
7830
7831 Some(CoreSymbol {
7832 source_language_server_id: result.server_id,
7833 language_server_name: result.lsp_adapter.name.clone(),
7834 source_worktree_id,
7835 path,
7836 kind: symbol_kind,
7837 name: collapse_newlines(&symbol_name, "↵ "),
7838 range: range_from_lsp(symbol_location.range),
7839 container_name: container_name
7840 .map(|c| collapse_newlines(&c, "↵ ")),
7841 })
7842 },
7843 )
7844 .collect::<Vec<_>>()
7845 });
7846
7847 populate_labels_for_symbols(
7848 core_symbols,
7849 &language_registry,
7850 Some(result.lsp_adapter),
7851 &mut symbols,
7852 )
7853 .await;
7854 }
7855
7856 Ok(symbols)
7857 })
7858 } else {
7859 Task::ready(Err(anyhow!("No upstream client or local language server")))
7860 }
7861 }
7862
7863 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7864 let mut summary = DiagnosticSummary::default();
7865 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7866 summary.error_count += path_summary.error_count;
7867 summary.warning_count += path_summary.warning_count;
7868 }
7869 summary
7870 }
7871
7872 /// Returns the diagnostic summary for a specific project path.
7873 pub fn diagnostic_summary_for_path(
7874 &self,
7875 project_path: &ProjectPath,
7876 _: &App,
7877 ) -> DiagnosticSummary {
7878 if let Some(summaries) = self
7879 .diagnostic_summaries
7880 .get(&project_path.worktree_id)
7881 .and_then(|map| map.get(&project_path.path))
7882 {
7883 let (error_count, warning_count) = summaries.iter().fold(
7884 (0, 0),
7885 |(error_count, warning_count), (_language_server_id, summary)| {
7886 (
7887 error_count + summary.error_count,
7888 warning_count + summary.warning_count,
7889 )
7890 },
7891 );
7892
7893 DiagnosticSummary {
7894 error_count,
7895 warning_count,
7896 }
7897 } else {
7898 DiagnosticSummary::default()
7899 }
7900 }
7901
7902 pub fn diagnostic_summaries<'a>(
7903 &'a self,
7904 include_ignored: bool,
7905 cx: &'a App,
7906 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7907 self.worktree_store
7908 .read(cx)
7909 .visible_worktrees(cx)
7910 .filter_map(|worktree| {
7911 let worktree = worktree.read(cx);
7912 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7913 })
7914 .flat_map(move |(worktree, summaries)| {
7915 let worktree_id = worktree.id();
7916 summaries
7917 .iter()
7918 .filter(move |(path, _)| {
7919 include_ignored
7920 || worktree
7921 .entry_for_path(path.as_ref())
7922 .is_some_and(|entry| !entry.is_ignored)
7923 })
7924 .flat_map(move |(path, summaries)| {
7925 summaries.iter().map(move |(server_id, summary)| {
7926 (
7927 ProjectPath {
7928 worktree_id,
7929 path: path.clone(),
7930 },
7931 *server_id,
7932 *summary,
7933 )
7934 })
7935 })
7936 })
7937 }
7938
7939 pub fn on_buffer_edited(
7940 &mut self,
7941 buffer: Entity<Buffer>,
7942 cx: &mut Context<Self>,
7943 ) -> Option<()> {
7944 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7945 Some(
7946 self.as_local()?
7947 .language_servers_for_buffer(buffer, cx)
7948 .map(|i| i.1.clone())
7949 .collect(),
7950 )
7951 })?;
7952
7953 let buffer = buffer.read(cx);
7954 let file = File::from_dyn(buffer.file())?;
7955 let abs_path = file.as_local()?.abs_path(cx);
7956 let uri = lsp::Uri::from_file_path(&abs_path)
7957 .ok()
7958 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7959 .log_err()?;
7960 let next_snapshot = buffer.text_snapshot();
7961 for language_server in language_servers {
7962 let language_server = language_server.clone();
7963
7964 let buffer_snapshots = self
7965 .as_local_mut()?
7966 .buffer_snapshots
7967 .get_mut(&buffer.remote_id())
7968 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7969 let previous_snapshot = buffer_snapshots.last()?;
7970
7971 let build_incremental_change = || {
7972 buffer
7973 .edits_since::<Dimensions<PointUtf16, usize>>(
7974 previous_snapshot.snapshot.version(),
7975 )
7976 .map(|edit| {
7977 let edit_start = edit.new.start.0;
7978 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7979 let new_text = next_snapshot
7980 .text_for_range(edit.new.start.1..edit.new.end.1)
7981 .collect();
7982 lsp::TextDocumentContentChangeEvent {
7983 range: Some(lsp::Range::new(
7984 point_to_lsp(edit_start),
7985 point_to_lsp(edit_end),
7986 )),
7987 range_length: None,
7988 text: new_text,
7989 }
7990 })
7991 .collect()
7992 };
7993
7994 let document_sync_kind = language_server
7995 .capabilities()
7996 .text_document_sync
7997 .as_ref()
7998 .and_then(|sync| match sync {
7999 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8000 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8001 });
8002
8003 let content_changes: Vec<_> = match document_sync_kind {
8004 Some(lsp::TextDocumentSyncKind::FULL) => {
8005 vec![lsp::TextDocumentContentChangeEvent {
8006 range: None,
8007 range_length: None,
8008 text: next_snapshot.text(),
8009 }]
8010 }
8011 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8012 _ => {
8013 #[cfg(any(test, feature = "test-support"))]
8014 {
8015 build_incremental_change()
8016 }
8017
8018 #[cfg(not(any(test, feature = "test-support")))]
8019 {
8020 continue;
8021 }
8022 }
8023 };
8024
8025 let next_version = previous_snapshot.version + 1;
8026 buffer_snapshots.push(LspBufferSnapshot {
8027 version: next_version,
8028 snapshot: next_snapshot.clone(),
8029 });
8030
8031 language_server
8032 .notify::<lsp::notification::DidChangeTextDocument>(
8033 lsp::DidChangeTextDocumentParams {
8034 text_document: lsp::VersionedTextDocumentIdentifier::new(
8035 uri.clone(),
8036 next_version,
8037 ),
8038 content_changes,
8039 },
8040 )
8041 .ok();
8042 self.pull_workspace_diagnostics(language_server.server_id());
8043 }
8044
8045 None
8046 }
8047
8048 pub fn on_buffer_saved(
8049 &mut self,
8050 buffer: Entity<Buffer>,
8051 cx: &mut Context<Self>,
8052 ) -> Option<()> {
8053 let file = File::from_dyn(buffer.read(cx).file())?;
8054 let worktree_id = file.worktree_id(cx);
8055 let abs_path = file.as_local()?.abs_path(cx);
8056 let text_document = lsp::TextDocumentIdentifier {
8057 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8058 };
8059 let local = self.as_local()?;
8060
8061 for server in local.language_servers_for_worktree(worktree_id) {
8062 if let Some(include_text) = include_text(server.as_ref()) {
8063 let text = if include_text {
8064 Some(buffer.read(cx).text())
8065 } else {
8066 None
8067 };
8068 server
8069 .notify::<lsp::notification::DidSaveTextDocument>(
8070 lsp::DidSaveTextDocumentParams {
8071 text_document: text_document.clone(),
8072 text,
8073 },
8074 )
8075 .ok();
8076 }
8077 }
8078
8079 let language_servers = buffer.update(cx, |buffer, cx| {
8080 local.language_server_ids_for_buffer(buffer, cx)
8081 });
8082 for language_server_id in language_servers {
8083 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8084 }
8085
8086 None
8087 }
8088
8089 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8090 maybe!(async move {
8091 let mut refreshed_servers = HashSet::default();
8092 let servers = lsp_store
8093 .update(cx, |lsp_store, cx| {
8094 let local = lsp_store.as_local()?;
8095
8096 let servers = local
8097 .language_server_ids
8098 .iter()
8099 .filter_map(|(seed, state)| {
8100 let worktree = lsp_store
8101 .worktree_store
8102 .read(cx)
8103 .worktree_for_id(seed.worktree_id, cx);
8104 let delegate: Arc<dyn LspAdapterDelegate> =
8105 worktree.map(|worktree| {
8106 LocalLspAdapterDelegate::new(
8107 local.languages.clone(),
8108 &local.environment,
8109 cx.weak_entity(),
8110 &worktree,
8111 local.http_client.clone(),
8112 local.fs.clone(),
8113 cx,
8114 )
8115 })?;
8116 let server_id = state.id;
8117
8118 let states = local.language_servers.get(&server_id)?;
8119
8120 match states {
8121 LanguageServerState::Starting { .. } => None,
8122 LanguageServerState::Running {
8123 adapter, server, ..
8124 } => {
8125 let adapter = adapter.clone();
8126 let server = server.clone();
8127 refreshed_servers.insert(server.name());
8128 let toolchain = seed.toolchain.clone();
8129 Some(cx.spawn(async move |_, cx| {
8130 let settings =
8131 LocalLspStore::workspace_configuration_for_adapter(
8132 adapter.adapter.clone(),
8133 &delegate,
8134 toolchain,
8135 None,
8136 cx,
8137 )
8138 .await
8139 .ok()?;
8140 server
8141 .notify::<lsp::notification::DidChangeConfiguration>(
8142 lsp::DidChangeConfigurationParams { settings },
8143 )
8144 .ok()?;
8145 Some(())
8146 }))
8147 }
8148 }
8149 })
8150 .collect::<Vec<_>>();
8151
8152 Some(servers)
8153 })
8154 .ok()
8155 .flatten()?;
8156
8157 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8158 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8159 // to stop and unregister its language server wrapper.
8160 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8161 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8162 let _: Vec<Option<()>> = join_all(servers).await;
8163
8164 Some(())
8165 })
8166 .await;
8167 }
8168
8169 fn maintain_workspace_config(
8170 external_refresh_requests: watch::Receiver<()>,
8171 cx: &mut Context<Self>,
8172 ) -> Task<Result<()>> {
8173 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8174 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8175
8176 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8177 *settings_changed_tx.borrow_mut() = ();
8178 });
8179
8180 let mut joint_future =
8181 futures::stream::select(settings_changed_rx, external_refresh_requests);
8182 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8183 // - 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).
8184 // - 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.
8185 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8186 // - 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,
8187 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8188 cx.spawn(async move |this, cx| {
8189 while let Some(()) = joint_future.next().await {
8190 this.update(cx, |this, cx| {
8191 this.refresh_server_tree(cx);
8192 })
8193 .ok();
8194
8195 Self::refresh_workspace_configurations(&this, cx).await;
8196 }
8197
8198 drop(settings_observation);
8199 anyhow::Ok(())
8200 })
8201 }
8202
8203 pub fn running_language_servers_for_local_buffer<'a>(
8204 &'a self,
8205 buffer: &Buffer,
8206 cx: &mut App,
8207 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8208 let local = self.as_local();
8209 let language_server_ids = local
8210 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8211 .unwrap_or_default();
8212
8213 language_server_ids
8214 .into_iter()
8215 .filter_map(
8216 move |server_id| match local?.language_servers.get(&server_id)? {
8217 LanguageServerState::Running {
8218 adapter, server, ..
8219 } => Some((adapter, server)),
8220 _ => None,
8221 },
8222 )
8223 }
8224
8225 pub fn language_servers_for_local_buffer(
8226 &self,
8227 buffer: &Buffer,
8228 cx: &mut App,
8229 ) -> Vec<LanguageServerId> {
8230 let local = self.as_local();
8231 local
8232 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8233 .unwrap_or_default()
8234 }
8235
8236 pub fn language_server_for_local_buffer<'a>(
8237 &'a self,
8238 buffer: &'a Buffer,
8239 server_id: LanguageServerId,
8240 cx: &'a mut App,
8241 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8242 self.as_local()?
8243 .language_servers_for_buffer(buffer, cx)
8244 .find(|(_, s)| s.server_id() == server_id)
8245 }
8246
8247 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8248 self.diagnostic_summaries.remove(&id_to_remove);
8249 if let Some(local) = self.as_local_mut() {
8250 let to_remove = local.remove_worktree(id_to_remove, cx);
8251 for server in to_remove {
8252 self.language_server_statuses.remove(&server);
8253 }
8254 }
8255 }
8256
8257 fn invalidate_diagnostic_summaries_for_removed_entries(
8258 &mut self,
8259 worktree_id: WorktreeId,
8260 changes: &UpdatedEntriesSet,
8261 cx: &mut Context<Self>,
8262 ) {
8263 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8264 return;
8265 };
8266
8267 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8268 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8269 let downstream = self.downstream_client.clone();
8270
8271 for (path, _, _) in changes
8272 .iter()
8273 .filter(|(_, _, change)| *change == PathChange::Removed)
8274 {
8275 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8276 for (server_id, _) in &summaries_by_server_id {
8277 cleared_server_ids.insert(*server_id);
8278 if let Some((client, project_id)) = &downstream {
8279 client
8280 .send(proto::UpdateDiagnosticSummary {
8281 project_id: *project_id,
8282 worktree_id: worktree_id.to_proto(),
8283 summary: Some(proto::DiagnosticSummary {
8284 path: path.as_ref().to_proto(),
8285 language_server_id: server_id.0 as u64,
8286 error_count: 0,
8287 warning_count: 0,
8288 }),
8289 more_summaries: Vec::new(),
8290 })
8291 .ok();
8292 }
8293 }
8294 cleared_paths.push(ProjectPath {
8295 worktree_id,
8296 path: path.clone(),
8297 });
8298 }
8299 }
8300
8301 if !cleared_paths.is_empty() {
8302 for server_id in cleared_server_ids {
8303 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8304 server_id,
8305 paths: cleared_paths.clone(),
8306 });
8307 }
8308 }
8309 }
8310
8311 pub fn shared(
8312 &mut self,
8313 project_id: u64,
8314 downstream_client: AnyProtoClient,
8315 _: &mut Context<Self>,
8316 ) {
8317 self.downstream_client = Some((downstream_client.clone(), project_id));
8318
8319 for (server_id, status) in &self.language_server_statuses {
8320 if let Some(server) = self.language_server_for_id(*server_id) {
8321 downstream_client
8322 .send(proto::StartLanguageServer {
8323 project_id,
8324 server: Some(proto::LanguageServer {
8325 id: server_id.to_proto(),
8326 name: status.name.to_string(),
8327 worktree_id: status.worktree.map(|id| id.to_proto()),
8328 }),
8329 capabilities: serde_json::to_string(&server.capabilities())
8330 .expect("serializing server LSP capabilities"),
8331 })
8332 .log_err();
8333 }
8334 }
8335 }
8336
8337 pub fn disconnected_from_host(&mut self) {
8338 self.downstream_client.take();
8339 }
8340
8341 pub fn disconnected_from_ssh_remote(&mut self) {
8342 if let LspStoreMode::Remote(RemoteLspStore {
8343 upstream_client, ..
8344 }) = &mut self.mode
8345 {
8346 upstream_client.take();
8347 }
8348 }
8349
8350 pub(crate) fn set_language_server_statuses_from_proto(
8351 &mut self,
8352 project: WeakEntity<Project>,
8353 language_servers: Vec<proto::LanguageServer>,
8354 server_capabilities: Vec<String>,
8355 cx: &mut Context<Self>,
8356 ) {
8357 let lsp_logs = cx
8358 .try_global::<GlobalLogStore>()
8359 .map(|lsp_store| lsp_store.0.clone());
8360
8361 self.language_server_statuses = language_servers
8362 .into_iter()
8363 .zip(server_capabilities)
8364 .map(|(server, server_capabilities)| {
8365 let server_id = LanguageServerId(server.id as usize);
8366 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8367 self.lsp_server_capabilities
8368 .insert(server_id, server_capabilities);
8369 }
8370
8371 let name = LanguageServerName::from_proto(server.name);
8372 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8373
8374 if let Some(lsp_logs) = &lsp_logs {
8375 lsp_logs.update(cx, |lsp_logs, cx| {
8376 lsp_logs.add_language_server(
8377 // Only remote clients get their language servers set from proto
8378 LanguageServerKind::Remote {
8379 project: project.clone(),
8380 },
8381 server_id,
8382 Some(name.clone()),
8383 worktree,
8384 None,
8385 cx,
8386 );
8387 });
8388 }
8389
8390 (
8391 server_id,
8392 LanguageServerStatus {
8393 name,
8394 server_version: None,
8395 server_readable_version: None,
8396 pending_work: Default::default(),
8397 has_pending_diagnostic_updates: false,
8398 progress_tokens: Default::default(),
8399 worktree,
8400 binary: None,
8401 configuration: None,
8402 workspace_folders: BTreeSet::new(),
8403 process_id: None,
8404 },
8405 )
8406 })
8407 .collect();
8408 }
8409
8410 #[cfg(feature = "test-support")]
8411 pub fn update_diagnostic_entries(
8412 &mut self,
8413 server_id: LanguageServerId,
8414 abs_path: PathBuf,
8415 result_id: Option<SharedString>,
8416 version: Option<i32>,
8417 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8418 cx: &mut Context<Self>,
8419 ) -> anyhow::Result<()> {
8420 self.merge_diagnostic_entries(
8421 vec![DocumentDiagnosticsUpdate {
8422 diagnostics: DocumentDiagnostics {
8423 diagnostics,
8424 document_abs_path: abs_path,
8425 version,
8426 },
8427 result_id,
8428 server_id,
8429 disk_based_sources: Cow::Borrowed(&[]),
8430 registration_id: None,
8431 }],
8432 |_, _, _| false,
8433 cx,
8434 )?;
8435 Ok(())
8436 }
8437
8438 pub fn merge_diagnostic_entries<'a>(
8439 &mut self,
8440 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8441 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8442 cx: &mut Context<Self>,
8443 ) -> anyhow::Result<()> {
8444 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8445 let mut updated_diagnostics_paths = HashMap::default();
8446 for mut update in diagnostic_updates {
8447 let abs_path = &update.diagnostics.document_abs_path;
8448 let server_id = update.server_id;
8449 let Some((worktree, relative_path)) =
8450 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8451 else {
8452 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8453 return Ok(());
8454 };
8455
8456 let worktree_id = worktree.read(cx).id();
8457 let project_path = ProjectPath {
8458 worktree_id,
8459 path: relative_path,
8460 };
8461
8462 let document_uri = lsp::Uri::from_file_path(abs_path)
8463 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8464 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8465 let snapshot = buffer_handle.read(cx).snapshot();
8466 let buffer = buffer_handle.read(cx);
8467 let reused_diagnostics = buffer
8468 .buffer_diagnostics(Some(server_id))
8469 .iter()
8470 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8471 .map(|v| {
8472 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8473 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8474 DiagnosticEntry {
8475 range: start..end,
8476 diagnostic: v.diagnostic.clone(),
8477 }
8478 })
8479 .collect::<Vec<_>>();
8480
8481 self.as_local_mut()
8482 .context("cannot merge diagnostics on a remote LspStore")?
8483 .update_buffer_diagnostics(
8484 &buffer_handle,
8485 server_id,
8486 Some(update.registration_id),
8487 update.result_id,
8488 update.diagnostics.version,
8489 update.diagnostics.diagnostics.clone(),
8490 reused_diagnostics.clone(),
8491 cx,
8492 )?;
8493
8494 update.diagnostics.diagnostics.extend(reused_diagnostics);
8495 } else if let Some(local) = self.as_local() {
8496 let reused_diagnostics = local
8497 .diagnostics
8498 .get(&worktree_id)
8499 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8500 .and_then(|diagnostics_by_server_id| {
8501 diagnostics_by_server_id
8502 .binary_search_by_key(&server_id, |e| e.0)
8503 .ok()
8504 .map(|ix| &diagnostics_by_server_id[ix].1)
8505 })
8506 .into_iter()
8507 .flatten()
8508 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8509
8510 update
8511 .diagnostics
8512 .diagnostics
8513 .extend(reused_diagnostics.cloned());
8514 }
8515
8516 let updated = worktree.update(cx, |worktree, cx| {
8517 self.update_worktree_diagnostics(
8518 worktree.id(),
8519 server_id,
8520 project_path.path.clone(),
8521 update.diagnostics.diagnostics,
8522 cx,
8523 )
8524 })?;
8525 match updated {
8526 ControlFlow::Continue(new_summary) => {
8527 if let Some((project_id, new_summary)) = new_summary {
8528 match &mut diagnostics_summary {
8529 Some(diagnostics_summary) => {
8530 diagnostics_summary
8531 .more_summaries
8532 .push(proto::DiagnosticSummary {
8533 path: project_path.path.as_ref().to_proto(),
8534 language_server_id: server_id.0 as u64,
8535 error_count: new_summary.error_count,
8536 warning_count: new_summary.warning_count,
8537 })
8538 }
8539 None => {
8540 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8541 project_id,
8542 worktree_id: worktree_id.to_proto(),
8543 summary: Some(proto::DiagnosticSummary {
8544 path: project_path.path.as_ref().to_proto(),
8545 language_server_id: server_id.0 as u64,
8546 error_count: new_summary.error_count,
8547 warning_count: new_summary.warning_count,
8548 }),
8549 more_summaries: Vec::new(),
8550 })
8551 }
8552 }
8553 }
8554 updated_diagnostics_paths
8555 .entry(server_id)
8556 .or_insert_with(Vec::new)
8557 .push(project_path);
8558 }
8559 ControlFlow::Break(()) => {}
8560 }
8561 }
8562
8563 if let Some((diagnostics_summary, (downstream_client, _))) =
8564 diagnostics_summary.zip(self.downstream_client.as_ref())
8565 {
8566 downstream_client.send(diagnostics_summary).log_err();
8567 }
8568 for (server_id, paths) in updated_diagnostics_paths {
8569 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8570 }
8571 Ok(())
8572 }
8573
8574 fn update_worktree_diagnostics(
8575 &mut self,
8576 worktree_id: WorktreeId,
8577 server_id: LanguageServerId,
8578 path_in_worktree: Arc<RelPath>,
8579 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8580 _: &mut Context<Worktree>,
8581 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8582 let local = match &mut self.mode {
8583 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8584 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8585 };
8586
8587 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8588 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8589 let summaries_by_server_id = summaries_for_tree
8590 .entry(path_in_worktree.clone())
8591 .or_default();
8592
8593 let old_summary = summaries_by_server_id
8594 .remove(&server_id)
8595 .unwrap_or_default();
8596
8597 let new_summary = DiagnosticSummary::new(&diagnostics);
8598 if diagnostics.is_empty() {
8599 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8600 {
8601 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8602 diagnostics_by_server_id.remove(ix);
8603 }
8604 if diagnostics_by_server_id.is_empty() {
8605 diagnostics_for_tree.remove(&path_in_worktree);
8606 }
8607 }
8608 } else {
8609 summaries_by_server_id.insert(server_id, new_summary);
8610 let diagnostics_by_server_id = diagnostics_for_tree
8611 .entry(path_in_worktree.clone())
8612 .or_default();
8613 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8614 Ok(ix) => {
8615 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8616 }
8617 Err(ix) => {
8618 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8619 }
8620 }
8621 }
8622
8623 if !old_summary.is_empty() || !new_summary.is_empty() {
8624 if let Some((_, project_id)) = &self.downstream_client {
8625 Ok(ControlFlow::Continue(Some((
8626 *project_id,
8627 proto::DiagnosticSummary {
8628 path: path_in_worktree.to_proto(),
8629 language_server_id: server_id.0 as u64,
8630 error_count: new_summary.error_count as u32,
8631 warning_count: new_summary.warning_count as u32,
8632 },
8633 ))))
8634 } else {
8635 Ok(ControlFlow::Continue(None))
8636 }
8637 } else {
8638 Ok(ControlFlow::Break(()))
8639 }
8640 }
8641
8642 pub fn open_buffer_for_symbol(
8643 &mut self,
8644 symbol: &Symbol,
8645 cx: &mut Context<Self>,
8646 ) -> Task<Result<Entity<Buffer>>> {
8647 if let Some((client, project_id)) = self.upstream_client() {
8648 let request = client.request(proto::OpenBufferForSymbol {
8649 project_id,
8650 symbol: Some(Self::serialize_symbol(symbol)),
8651 });
8652 cx.spawn(async move |this, cx| {
8653 let response = request.await?;
8654 let buffer_id = BufferId::new(response.buffer_id)?;
8655 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8656 .await
8657 })
8658 } else if let Some(local) = self.as_local() {
8659 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8660 seed.worktree_id == symbol.source_worktree_id
8661 && state.id == symbol.source_language_server_id
8662 && symbol.language_server_name == seed.name
8663 });
8664 if !is_valid {
8665 return Task::ready(Err(anyhow!(
8666 "language server for worktree and language not found"
8667 )));
8668 };
8669
8670 let symbol_abs_path = match &symbol.path {
8671 SymbolLocation::InProject(project_path) => self
8672 .worktree_store
8673 .read(cx)
8674 .absolutize(&project_path, cx)
8675 .context("no such worktree"),
8676 SymbolLocation::OutsideProject {
8677 abs_path,
8678 signature: _,
8679 } => Ok(abs_path.to_path_buf()),
8680 };
8681 let symbol_abs_path = match symbol_abs_path {
8682 Ok(abs_path) => abs_path,
8683 Err(err) => return Task::ready(Err(err)),
8684 };
8685 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8686 uri
8687 } else {
8688 return Task::ready(Err(anyhow!("invalid symbol path")));
8689 };
8690
8691 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8692 } else {
8693 Task::ready(Err(anyhow!("no upstream client or local store")))
8694 }
8695 }
8696
8697 pub(crate) fn open_local_buffer_via_lsp(
8698 &mut self,
8699 abs_path: lsp::Uri,
8700 language_server_id: LanguageServerId,
8701 cx: &mut Context<Self>,
8702 ) -> Task<Result<Entity<Buffer>>> {
8703 let path_style = self.worktree_store.read(cx).path_style();
8704 cx.spawn(async move |lsp_store, cx| {
8705 // Escape percent-encoded string.
8706 let current_scheme = abs_path.scheme().to_owned();
8707 // Uri is immutable, so we can't modify the scheme
8708
8709 let abs_path = abs_path
8710 .to_file_path_ext(path_style)
8711 .map_err(|()| anyhow!("can't convert URI to path"))?;
8712 let p = abs_path.clone();
8713 let yarn_worktree = lsp_store
8714 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8715 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8716 cx.spawn(async move |this, cx| {
8717 let t = this
8718 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8719 .ok()?;
8720 t.await
8721 })
8722 }),
8723 None => Task::ready(None),
8724 })?
8725 .await;
8726 let (worktree_root_target, known_relative_path) =
8727 if let Some((zip_root, relative_path)) = yarn_worktree {
8728 (zip_root, Some(relative_path))
8729 } else {
8730 (Arc::<Path>::from(abs_path.as_path()), None)
8731 };
8732 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8733 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8734 worktree_store.find_worktree(&worktree_root_target, cx)
8735 })
8736 })?;
8737 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8738 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8739 (result.0, relative_path, None)
8740 } else {
8741 let worktree = lsp_store
8742 .update(cx, |lsp_store, cx| {
8743 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8744 worktree_store.create_worktree(&worktree_root_target, false, cx)
8745 })
8746 })?
8747 .await?;
8748 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8749 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8750 lsp_store
8751 .update(cx, |lsp_store, cx| {
8752 if let Some(local) = lsp_store.as_local_mut() {
8753 local.register_language_server_for_invisible_worktree(
8754 &worktree,
8755 language_server_id,
8756 cx,
8757 )
8758 }
8759 match lsp_store.language_server_statuses.get(&language_server_id) {
8760 Some(status) => status.worktree,
8761 None => None,
8762 }
8763 })
8764 .ok()
8765 .flatten()
8766 .zip(Some(worktree_root.clone()))
8767 } else {
8768 None
8769 };
8770 let relative_path = if let Some(known_path) = known_relative_path {
8771 known_path
8772 } else {
8773 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8774 .into_arc()
8775 };
8776 (worktree, relative_path, source_ws)
8777 };
8778 let project_path = ProjectPath {
8779 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8780 path: relative_path,
8781 };
8782 let buffer = lsp_store
8783 .update(cx, |lsp_store, cx| {
8784 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8785 buffer_store.open_buffer(project_path, cx)
8786 })
8787 })?
8788 .await?;
8789 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8790 if let Some((source_ws, worktree_root)) = source_ws {
8791 buffer.update(cx, |buffer, cx| {
8792 let settings = WorktreeSettings::get(
8793 Some(
8794 (&ProjectPath {
8795 worktree_id: source_ws,
8796 path: Arc::from(RelPath::empty()),
8797 })
8798 .into(),
8799 ),
8800 cx,
8801 );
8802 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8803 if is_read_only {
8804 buffer.set_capability(Capability::ReadOnly, cx);
8805 }
8806 });
8807 }
8808 Ok(buffer)
8809 })
8810 }
8811
8812 fn local_lsp_servers_for_buffer(
8813 &self,
8814 buffer: &Entity<Buffer>,
8815 cx: &mut Context<Self>,
8816 ) -> Vec<LanguageServerId> {
8817 let Some(local) = self.as_local() else {
8818 return Vec::new();
8819 };
8820
8821 let snapshot = buffer.read(cx).snapshot();
8822
8823 buffer.update(cx, |buffer, cx| {
8824 local
8825 .language_servers_for_buffer(buffer, cx)
8826 .map(|(_, server)| server.server_id())
8827 .filter(|server_id| {
8828 self.as_local().is_none_or(|local| {
8829 local
8830 .buffers_opened_in_servers
8831 .get(&snapshot.remote_id())
8832 .is_some_and(|servers| servers.contains(server_id))
8833 })
8834 })
8835 .collect()
8836 })
8837 }
8838
8839 fn request_multiple_lsp_locally<P, R>(
8840 &mut self,
8841 buffer: &Entity<Buffer>,
8842 position: Option<P>,
8843 request: R,
8844 cx: &mut Context<Self>,
8845 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8846 where
8847 P: ToOffset,
8848 R: LspCommand + Clone,
8849 <R::LspRequest as lsp::request::Request>::Result: Send,
8850 <R::LspRequest as lsp::request::Request>::Params: Send,
8851 {
8852 let Some(local) = self.as_local() else {
8853 return Task::ready(Vec::new());
8854 };
8855
8856 let snapshot = buffer.read(cx).snapshot();
8857 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8858
8859 let server_ids = buffer.update(cx, |buffer, cx| {
8860 local
8861 .language_servers_for_buffer(buffer, cx)
8862 .filter(|(adapter, _)| {
8863 scope
8864 .as_ref()
8865 .map(|scope| scope.language_allowed(&adapter.name))
8866 .unwrap_or(true)
8867 })
8868 .map(|(_, server)| server.server_id())
8869 .filter(|server_id| {
8870 self.as_local().is_none_or(|local| {
8871 local
8872 .buffers_opened_in_servers
8873 .get(&snapshot.remote_id())
8874 .is_some_and(|servers| servers.contains(server_id))
8875 })
8876 })
8877 .collect::<Vec<_>>()
8878 });
8879
8880 let mut response_results = server_ids
8881 .into_iter()
8882 .map(|server_id| {
8883 let task = self.request_lsp(
8884 buffer.clone(),
8885 LanguageServerToQuery::Other(server_id),
8886 request.clone(),
8887 cx,
8888 );
8889 async move { (server_id, task.await) }
8890 })
8891 .collect::<FuturesUnordered<_>>();
8892
8893 cx.background_spawn(async move {
8894 let mut responses = Vec::with_capacity(response_results.len());
8895 while let Some((server_id, response_result)) = response_results.next().await {
8896 match response_result {
8897 Ok(response) => responses.push((server_id, response)),
8898 // rust-analyzer likes to error with this when its still loading up
8899 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8900 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8901 }
8902 }
8903 responses
8904 })
8905 }
8906
8907 async fn handle_lsp_get_completions(
8908 this: Entity<Self>,
8909 envelope: TypedEnvelope<proto::GetCompletions>,
8910 mut cx: AsyncApp,
8911 ) -> Result<proto::GetCompletionsResponse> {
8912 let sender_id = envelope.original_sender_id().unwrap_or_default();
8913
8914 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8915 let buffer_handle = this.update(&mut cx, |this, cx| {
8916 this.buffer_store.read(cx).get_existing(buffer_id)
8917 })?;
8918 let request = GetCompletions::from_proto(
8919 envelope.payload,
8920 this.clone(),
8921 buffer_handle.clone(),
8922 cx.clone(),
8923 )
8924 .await?;
8925
8926 let server_to_query = match request.server_id {
8927 Some(server_id) => LanguageServerToQuery::Other(server_id),
8928 None => LanguageServerToQuery::FirstCapable,
8929 };
8930
8931 let response = this
8932 .update(&mut cx, |this, cx| {
8933 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8934 })
8935 .await?;
8936 this.update(&mut cx, |this, cx| {
8937 Ok(GetCompletions::response_to_proto(
8938 response,
8939 this,
8940 sender_id,
8941 &buffer_handle.read(cx).version(),
8942 cx,
8943 ))
8944 })
8945 }
8946
8947 async fn handle_lsp_command<T: LspCommand>(
8948 this: Entity<Self>,
8949 envelope: TypedEnvelope<T::ProtoRequest>,
8950 mut cx: AsyncApp,
8951 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8952 where
8953 <T::LspRequest as lsp::request::Request>::Params: Send,
8954 <T::LspRequest as lsp::request::Request>::Result: Send,
8955 {
8956 let sender_id = envelope.original_sender_id().unwrap_or_default();
8957 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8958 let buffer_handle = this.update(&mut cx, |this, cx| {
8959 this.buffer_store.read(cx).get_existing(buffer_id)
8960 })?;
8961 let request = T::from_proto(
8962 envelope.payload,
8963 this.clone(),
8964 buffer_handle.clone(),
8965 cx.clone(),
8966 )
8967 .await?;
8968 let response = this
8969 .update(&mut cx, |this, cx| {
8970 this.request_lsp(
8971 buffer_handle.clone(),
8972 LanguageServerToQuery::FirstCapable,
8973 request,
8974 cx,
8975 )
8976 })
8977 .await?;
8978 this.update(&mut cx, |this, cx| {
8979 Ok(T::response_to_proto(
8980 response,
8981 this,
8982 sender_id,
8983 &buffer_handle.read(cx).version(),
8984 cx,
8985 ))
8986 })
8987 }
8988
8989 async fn handle_lsp_query(
8990 lsp_store: Entity<Self>,
8991 envelope: TypedEnvelope<proto::LspQuery>,
8992 mut cx: AsyncApp,
8993 ) -> Result<proto::Ack> {
8994 use proto::lsp_query::Request;
8995 let sender_id = envelope.original_sender_id().unwrap_or_default();
8996 let lsp_query = envelope.payload;
8997 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8998 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8999 match lsp_query.request.context("invalid LSP query request")? {
9000 Request::GetReferences(get_references) => {
9001 let position = get_references.position.clone().and_then(deserialize_anchor);
9002 Self::query_lsp_locally::<GetReferences>(
9003 lsp_store,
9004 server_id,
9005 sender_id,
9006 lsp_request_id,
9007 get_references,
9008 position,
9009 &mut cx,
9010 )
9011 .await?;
9012 }
9013 Request::GetDocumentColor(get_document_color) => {
9014 Self::query_lsp_locally::<GetDocumentColor>(
9015 lsp_store,
9016 server_id,
9017 sender_id,
9018 lsp_request_id,
9019 get_document_color,
9020 None,
9021 &mut cx,
9022 )
9023 .await?;
9024 }
9025 Request::GetFoldingRanges(get_folding_ranges) => {
9026 Self::query_lsp_locally::<GetFoldingRanges>(
9027 lsp_store,
9028 server_id,
9029 sender_id,
9030 lsp_request_id,
9031 get_folding_ranges,
9032 None,
9033 &mut cx,
9034 )
9035 .await?;
9036 }
9037 Request::GetDocumentSymbols(get_document_symbols) => {
9038 Self::query_lsp_locally::<GetDocumentSymbols>(
9039 lsp_store,
9040 server_id,
9041 sender_id,
9042 lsp_request_id,
9043 get_document_symbols,
9044 None,
9045 &mut cx,
9046 )
9047 .await?;
9048 }
9049 Request::GetHover(get_hover) => {
9050 let position = get_hover.position.clone().and_then(deserialize_anchor);
9051 Self::query_lsp_locally::<GetHover>(
9052 lsp_store,
9053 server_id,
9054 sender_id,
9055 lsp_request_id,
9056 get_hover,
9057 position,
9058 &mut cx,
9059 )
9060 .await?;
9061 }
9062 Request::GetCodeActions(get_code_actions) => {
9063 Self::query_lsp_locally::<GetCodeActions>(
9064 lsp_store,
9065 server_id,
9066 sender_id,
9067 lsp_request_id,
9068 get_code_actions,
9069 None,
9070 &mut cx,
9071 )
9072 .await?;
9073 }
9074 Request::GetSignatureHelp(get_signature_help) => {
9075 let position = get_signature_help
9076 .position
9077 .clone()
9078 .and_then(deserialize_anchor);
9079 Self::query_lsp_locally::<GetSignatureHelp>(
9080 lsp_store,
9081 server_id,
9082 sender_id,
9083 lsp_request_id,
9084 get_signature_help,
9085 position,
9086 &mut cx,
9087 )
9088 .await?;
9089 }
9090 Request::GetCodeLens(get_code_lens) => {
9091 Self::query_lsp_locally::<GetCodeLens>(
9092 lsp_store,
9093 server_id,
9094 sender_id,
9095 lsp_request_id,
9096 get_code_lens,
9097 None,
9098 &mut cx,
9099 )
9100 .await?;
9101 }
9102 Request::GetDefinition(get_definition) => {
9103 let position = get_definition.position.clone().and_then(deserialize_anchor);
9104 Self::query_lsp_locally::<GetDefinitions>(
9105 lsp_store,
9106 server_id,
9107 sender_id,
9108 lsp_request_id,
9109 get_definition,
9110 position,
9111 &mut cx,
9112 )
9113 .await?;
9114 }
9115 Request::GetDeclaration(get_declaration) => {
9116 let position = get_declaration
9117 .position
9118 .clone()
9119 .and_then(deserialize_anchor);
9120 Self::query_lsp_locally::<GetDeclarations>(
9121 lsp_store,
9122 server_id,
9123 sender_id,
9124 lsp_request_id,
9125 get_declaration,
9126 position,
9127 &mut cx,
9128 )
9129 .await?;
9130 }
9131 Request::GetTypeDefinition(get_type_definition) => {
9132 let position = get_type_definition
9133 .position
9134 .clone()
9135 .and_then(deserialize_anchor);
9136 Self::query_lsp_locally::<GetTypeDefinitions>(
9137 lsp_store,
9138 server_id,
9139 sender_id,
9140 lsp_request_id,
9141 get_type_definition,
9142 position,
9143 &mut cx,
9144 )
9145 .await?;
9146 }
9147 Request::GetImplementation(get_implementation) => {
9148 let position = get_implementation
9149 .position
9150 .clone()
9151 .and_then(deserialize_anchor);
9152 Self::query_lsp_locally::<GetImplementations>(
9153 lsp_store,
9154 server_id,
9155 sender_id,
9156 lsp_request_id,
9157 get_implementation,
9158 position,
9159 &mut cx,
9160 )
9161 .await?;
9162 }
9163 Request::InlayHints(inlay_hints) => {
9164 let query_start = inlay_hints
9165 .start
9166 .clone()
9167 .and_then(deserialize_anchor)
9168 .context("invalid inlay hints range start")?;
9169 let query_end = inlay_hints
9170 .end
9171 .clone()
9172 .and_then(deserialize_anchor)
9173 .context("invalid inlay hints range end")?;
9174 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9175 &lsp_store,
9176 server_id,
9177 lsp_request_id,
9178 &inlay_hints,
9179 query_start..query_end,
9180 &mut cx,
9181 )
9182 .await
9183 .context("preparing inlay hints request")?;
9184 Self::query_lsp_locally::<InlayHints>(
9185 lsp_store,
9186 server_id,
9187 sender_id,
9188 lsp_request_id,
9189 inlay_hints,
9190 None,
9191 &mut cx,
9192 )
9193 .await
9194 .context("querying for inlay hints")?
9195 }
9196 //////////////////////////////
9197 // Below are LSP queries that need to fetch more data,
9198 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9199 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9200 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9201 &lsp_store,
9202 &get_document_diagnostics,
9203 &mut cx,
9204 )
9205 .await?;
9206 lsp_store.update(&mut cx, |lsp_store, cx| {
9207 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9208 let key = LspKey {
9209 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9210 server_queried: server_id,
9211 };
9212 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9213 ) {
9214 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9215 lsp_requests.clear();
9216 };
9217 }
9218
9219 lsp_data.lsp_requests.entry(key).or_default().insert(
9220 lsp_request_id,
9221 cx.spawn(async move |lsp_store, cx| {
9222 let diagnostics_pull = lsp_store
9223 .update(cx, |lsp_store, cx| {
9224 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9225 })
9226 .ok();
9227 if let Some(diagnostics_pull) = diagnostics_pull {
9228 match diagnostics_pull.await {
9229 Ok(()) => {}
9230 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9231 };
9232 }
9233 }),
9234 );
9235 });
9236 }
9237 Request::SemanticTokens(semantic_tokens) => {
9238 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9239 &lsp_store,
9240 &semantic_tokens,
9241 &mut cx,
9242 )
9243 .await?;
9244 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9245 lsp_store.update(&mut cx, |lsp_store, cx| {
9246 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9247 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9248 let key = LspKey {
9249 request_type: TypeId::of::<SemanticTokensFull>(),
9250 server_queried: server_id,
9251 };
9252 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9253 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9254 lsp_requests.clear();
9255 };
9256 }
9257
9258 lsp_data.lsp_requests.entry(key).or_default().insert(
9259 lsp_request_id,
9260 cx.spawn(async move |lsp_store, cx| {
9261 let tokens_fetch = lsp_store
9262 .update(cx, |lsp_store, cx| {
9263 lsp_store
9264 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9265 })
9266 .ok();
9267 if let Some(tokens_fetch) = tokens_fetch {
9268 let new_tokens = tokens_fetch.await;
9269 if let Some(new_tokens) = new_tokens {
9270 lsp_store
9271 .update(cx, |lsp_store, cx| {
9272 let response = new_tokens
9273 .into_iter()
9274 .map(|(server_id, response)| {
9275 (
9276 server_id.to_proto(),
9277 SemanticTokensFull::response_to_proto(
9278 response,
9279 lsp_store,
9280 sender_id,
9281 &buffer_version,
9282 cx,
9283 ),
9284 )
9285 })
9286 .collect::<HashMap<_, _>>();
9287 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9288 project_id,
9289 lsp_request_id,
9290 response,
9291 ) {
9292 Ok(()) => {}
9293 Err(e) => {
9294 log::error!(
9295 "Failed to send semantic tokens LSP response: {e:#}",
9296 )
9297 }
9298 }
9299 })
9300 .ok();
9301 }
9302 }
9303 }),
9304 );
9305 }
9306 });
9307 }
9308 }
9309 Ok(proto::Ack {})
9310 }
9311
9312 async fn handle_lsp_query_response(
9313 lsp_store: Entity<Self>,
9314 envelope: TypedEnvelope<proto::LspQueryResponse>,
9315 cx: AsyncApp,
9316 ) -> Result<()> {
9317 lsp_store.read_with(&cx, |lsp_store, _| {
9318 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9319 upstream_client.handle_lsp_response(envelope.clone());
9320 }
9321 });
9322 Ok(())
9323 }
9324
9325 async fn handle_apply_code_action(
9326 this: Entity<Self>,
9327 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9328 mut cx: AsyncApp,
9329 ) -> Result<proto::ApplyCodeActionResponse> {
9330 let sender_id = envelope.original_sender_id().unwrap_or_default();
9331 let action =
9332 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9333 let apply_code_action = this.update(&mut cx, |this, cx| {
9334 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9335 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9336 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9337 })?;
9338
9339 let project_transaction = apply_code_action.await?;
9340 let project_transaction = this.update(&mut cx, |this, cx| {
9341 this.buffer_store.update(cx, |buffer_store, cx| {
9342 buffer_store.serialize_project_transaction_for_peer(
9343 project_transaction,
9344 sender_id,
9345 cx,
9346 )
9347 })
9348 });
9349 Ok(proto::ApplyCodeActionResponse {
9350 transaction: Some(project_transaction),
9351 })
9352 }
9353
9354 async fn handle_register_buffer_with_language_servers(
9355 this: Entity<Self>,
9356 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9357 mut cx: AsyncApp,
9358 ) -> Result<proto::Ack> {
9359 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9360 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9361 this.update(&mut cx, |this, cx| {
9362 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9363 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9364 project_id: upstream_project_id,
9365 buffer_id: buffer_id.to_proto(),
9366 only_servers: envelope.payload.only_servers,
9367 });
9368 }
9369
9370 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9371 anyhow::bail!("buffer is not open");
9372 };
9373
9374 let handle = this.register_buffer_with_language_servers(
9375 &buffer,
9376 envelope
9377 .payload
9378 .only_servers
9379 .into_iter()
9380 .filter_map(|selector| {
9381 Some(match selector.selector? {
9382 proto::language_server_selector::Selector::ServerId(server_id) => {
9383 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9384 }
9385 proto::language_server_selector::Selector::Name(name) => {
9386 LanguageServerSelector::Name(LanguageServerName(
9387 SharedString::from(name),
9388 ))
9389 }
9390 })
9391 })
9392 .collect(),
9393 false,
9394 cx,
9395 );
9396 // Pull diagnostics for the buffer even if it was already registered.
9397 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9398 // but it's unclear if we need it.
9399 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9400 .detach();
9401 this.buffer_store().update(cx, |buffer_store, _| {
9402 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9403 });
9404
9405 Ok(())
9406 })?;
9407 Ok(proto::Ack {})
9408 }
9409
9410 async fn handle_rename_project_entry(
9411 this: Entity<Self>,
9412 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9413 mut cx: AsyncApp,
9414 ) -> Result<proto::ProjectEntryResponse> {
9415 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9416 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9417 let new_path =
9418 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9419
9420 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9421 .update(&mut cx, |this, cx| {
9422 let (worktree, entry) = this
9423 .worktree_store
9424 .read(cx)
9425 .worktree_and_entry_for_id(entry_id, cx)?;
9426 let new_worktree = this
9427 .worktree_store
9428 .read(cx)
9429 .worktree_for_id(new_worktree_id, cx)?;
9430 Some((
9431 this.worktree_store.clone(),
9432 worktree,
9433 new_worktree,
9434 entry.clone(),
9435 ))
9436 })
9437 .context("worktree not found")?;
9438 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9439 (worktree.absolutize(&old_entry.path), worktree.id())
9440 });
9441 let new_abs_path =
9442 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9443
9444 let _transaction = Self::will_rename_entry(
9445 this.downgrade(),
9446 old_worktree_id,
9447 &old_abs_path,
9448 &new_abs_path,
9449 old_entry.is_dir(),
9450 cx.clone(),
9451 )
9452 .await;
9453 let response = WorktreeStore::handle_rename_project_entry(
9454 worktree_store,
9455 envelope.payload,
9456 cx.clone(),
9457 )
9458 .await;
9459 this.read_with(&cx, |this, _| {
9460 this.did_rename_entry(
9461 old_worktree_id,
9462 &old_abs_path,
9463 &new_abs_path,
9464 old_entry.is_dir(),
9465 );
9466 });
9467 response
9468 }
9469
9470 async fn handle_update_diagnostic_summary(
9471 this: Entity<Self>,
9472 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9473 mut cx: AsyncApp,
9474 ) -> Result<()> {
9475 this.update(&mut cx, |lsp_store, cx| {
9476 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9477 let mut updated_diagnostics_paths = HashMap::default();
9478 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9479 for message_summary in envelope
9480 .payload
9481 .summary
9482 .into_iter()
9483 .chain(envelope.payload.more_summaries)
9484 {
9485 let project_path = ProjectPath {
9486 worktree_id,
9487 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9488 };
9489 let path = project_path.path.clone();
9490 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9491 let summary = DiagnosticSummary {
9492 error_count: message_summary.error_count as usize,
9493 warning_count: message_summary.warning_count as usize,
9494 };
9495
9496 if summary.is_empty() {
9497 if let Some(worktree_summaries) =
9498 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9499 && let Some(summaries) = worktree_summaries.get_mut(&path)
9500 {
9501 summaries.remove(&server_id);
9502 if summaries.is_empty() {
9503 worktree_summaries.remove(&path);
9504 }
9505 }
9506 } else {
9507 lsp_store
9508 .diagnostic_summaries
9509 .entry(worktree_id)
9510 .or_default()
9511 .entry(path)
9512 .or_default()
9513 .insert(server_id, summary);
9514 }
9515
9516 if let Some((_, project_id)) = &lsp_store.downstream_client {
9517 match &mut diagnostics_summary {
9518 Some(diagnostics_summary) => {
9519 diagnostics_summary
9520 .more_summaries
9521 .push(proto::DiagnosticSummary {
9522 path: project_path.path.as_ref().to_proto(),
9523 language_server_id: server_id.0 as u64,
9524 error_count: summary.error_count as u32,
9525 warning_count: summary.warning_count as u32,
9526 })
9527 }
9528 None => {
9529 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9530 project_id: *project_id,
9531 worktree_id: worktree_id.to_proto(),
9532 summary: Some(proto::DiagnosticSummary {
9533 path: project_path.path.as_ref().to_proto(),
9534 language_server_id: server_id.0 as u64,
9535 error_count: summary.error_count as u32,
9536 warning_count: summary.warning_count as u32,
9537 }),
9538 more_summaries: Vec::new(),
9539 })
9540 }
9541 }
9542 }
9543 updated_diagnostics_paths
9544 .entry(server_id)
9545 .or_insert_with(Vec::new)
9546 .push(project_path);
9547 }
9548
9549 if let Some((diagnostics_summary, (downstream_client, _))) =
9550 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9551 {
9552 downstream_client.send(diagnostics_summary).log_err();
9553 }
9554 for (server_id, paths) in updated_diagnostics_paths {
9555 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9556 }
9557 Ok(())
9558 })
9559 }
9560
9561 async fn handle_start_language_server(
9562 lsp_store: Entity<Self>,
9563 envelope: TypedEnvelope<proto::StartLanguageServer>,
9564 mut cx: AsyncApp,
9565 ) -> Result<()> {
9566 let server = envelope.payload.server.context("invalid server")?;
9567 let server_capabilities =
9568 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9569 .with_context(|| {
9570 format!(
9571 "incorrect server capabilities {}",
9572 envelope.payload.capabilities
9573 )
9574 })?;
9575 lsp_store.update(&mut cx, |lsp_store, cx| {
9576 let server_id = LanguageServerId(server.id as usize);
9577 let server_name = LanguageServerName::from_proto(server.name.clone());
9578 lsp_store
9579 .lsp_server_capabilities
9580 .insert(server_id, server_capabilities);
9581 lsp_store.language_server_statuses.insert(
9582 server_id,
9583 LanguageServerStatus {
9584 name: server_name.clone(),
9585 server_version: None,
9586 server_readable_version: None,
9587 pending_work: Default::default(),
9588 has_pending_diagnostic_updates: false,
9589 progress_tokens: Default::default(),
9590 worktree: server.worktree_id.map(WorktreeId::from_proto),
9591 binary: None,
9592 configuration: None,
9593 workspace_folders: BTreeSet::new(),
9594 process_id: None,
9595 },
9596 );
9597 cx.emit(LspStoreEvent::LanguageServerAdded(
9598 server_id,
9599 server_name,
9600 server.worktree_id.map(WorktreeId::from_proto),
9601 ));
9602 cx.notify();
9603 });
9604 Ok(())
9605 }
9606
9607 async fn handle_update_language_server(
9608 lsp_store: Entity<Self>,
9609 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9610 mut cx: AsyncApp,
9611 ) -> Result<()> {
9612 lsp_store.update(&mut cx, |lsp_store, cx| {
9613 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9614
9615 match envelope.payload.variant.context("invalid variant")? {
9616 proto::update_language_server::Variant::WorkStart(payload) => {
9617 lsp_store.on_lsp_work_start(
9618 language_server_id,
9619 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9620 .context("invalid progress token value")?,
9621 LanguageServerProgress {
9622 title: payload.title,
9623 is_disk_based_diagnostics_progress: false,
9624 is_cancellable: payload.is_cancellable.unwrap_or(false),
9625 message: payload.message,
9626 percentage: payload.percentage.map(|p| p as usize),
9627 last_update_at: cx.background_executor().now(),
9628 },
9629 cx,
9630 );
9631 }
9632 proto::update_language_server::Variant::WorkProgress(payload) => {
9633 lsp_store.on_lsp_work_progress(
9634 language_server_id,
9635 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9636 .context("invalid progress token value")?,
9637 LanguageServerProgress {
9638 title: None,
9639 is_disk_based_diagnostics_progress: false,
9640 is_cancellable: payload.is_cancellable.unwrap_or(false),
9641 message: payload.message,
9642 percentage: payload.percentage.map(|p| p as usize),
9643 last_update_at: cx.background_executor().now(),
9644 },
9645 cx,
9646 );
9647 }
9648
9649 proto::update_language_server::Variant::WorkEnd(payload) => {
9650 lsp_store.on_lsp_work_end(
9651 language_server_id,
9652 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9653 .context("invalid progress token value")?,
9654 cx,
9655 );
9656 }
9657
9658 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9659 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9660 }
9661
9662 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9663 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9664 }
9665
9666 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9667 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9668 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9669 cx.emit(LspStoreEvent::LanguageServerUpdate {
9670 language_server_id,
9671 name: envelope
9672 .payload
9673 .server_name
9674 .map(SharedString::new)
9675 .map(LanguageServerName),
9676 message: non_lsp,
9677 });
9678 }
9679 }
9680
9681 Ok(())
9682 })
9683 }
9684
9685 async fn handle_language_server_log(
9686 this: Entity<Self>,
9687 envelope: TypedEnvelope<proto::LanguageServerLog>,
9688 mut cx: AsyncApp,
9689 ) -> Result<()> {
9690 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9691 let log_type = envelope
9692 .payload
9693 .log_type
9694 .map(LanguageServerLogType::from_proto)
9695 .context("invalid language server log type")?;
9696
9697 let message = envelope.payload.message;
9698
9699 this.update(&mut cx, |_, cx| {
9700 cx.emit(LspStoreEvent::LanguageServerLog(
9701 language_server_id,
9702 log_type,
9703 message,
9704 ));
9705 });
9706 Ok(())
9707 }
9708
9709 async fn handle_lsp_ext_cancel_flycheck(
9710 lsp_store: Entity<Self>,
9711 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9712 cx: AsyncApp,
9713 ) -> Result<proto::Ack> {
9714 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9715 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9716 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9717 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9718 } else {
9719 None
9720 }
9721 });
9722 if let Some(task) = task {
9723 task.context("handling lsp ext cancel flycheck")?;
9724 }
9725
9726 Ok(proto::Ack {})
9727 }
9728
9729 async fn handle_lsp_ext_run_flycheck(
9730 lsp_store: Entity<Self>,
9731 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9732 mut cx: AsyncApp,
9733 ) -> Result<proto::Ack> {
9734 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9735 lsp_store.update(&mut cx, |lsp_store, cx| {
9736 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9737 let text_document = if envelope.payload.current_file_only {
9738 let buffer_id = envelope
9739 .payload
9740 .buffer_id
9741 .map(|id| BufferId::new(id))
9742 .transpose()?;
9743 buffer_id
9744 .and_then(|buffer_id| {
9745 lsp_store
9746 .buffer_store()
9747 .read(cx)
9748 .get(buffer_id)
9749 .and_then(|buffer| {
9750 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9751 })
9752 .map(|path| make_text_document_identifier(&path))
9753 })
9754 .transpose()?
9755 } else {
9756 None
9757 };
9758 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9759 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9760 )?;
9761 }
9762 anyhow::Ok(())
9763 })?;
9764
9765 Ok(proto::Ack {})
9766 }
9767
9768 async fn handle_lsp_ext_clear_flycheck(
9769 lsp_store: Entity<Self>,
9770 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9771 cx: AsyncApp,
9772 ) -> Result<proto::Ack> {
9773 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9774 lsp_store.read_with(&cx, |lsp_store, _| {
9775 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9776 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9777 } else {
9778 None
9779 }
9780 });
9781
9782 Ok(proto::Ack {})
9783 }
9784
9785 pub fn disk_based_diagnostics_started(
9786 &mut self,
9787 language_server_id: LanguageServerId,
9788 cx: &mut Context<Self>,
9789 ) {
9790 if let Some(language_server_status) =
9791 self.language_server_statuses.get_mut(&language_server_id)
9792 {
9793 language_server_status.has_pending_diagnostic_updates = true;
9794 }
9795
9796 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9797 cx.emit(LspStoreEvent::LanguageServerUpdate {
9798 language_server_id,
9799 name: self
9800 .language_server_adapter_for_id(language_server_id)
9801 .map(|adapter| adapter.name()),
9802 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9803 Default::default(),
9804 ),
9805 })
9806 }
9807
9808 pub fn disk_based_diagnostics_finished(
9809 &mut self,
9810 language_server_id: LanguageServerId,
9811 cx: &mut Context<Self>,
9812 ) {
9813 if let Some(language_server_status) =
9814 self.language_server_statuses.get_mut(&language_server_id)
9815 {
9816 language_server_status.has_pending_diagnostic_updates = false;
9817 }
9818
9819 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9820 cx.emit(LspStoreEvent::LanguageServerUpdate {
9821 language_server_id,
9822 name: self
9823 .language_server_adapter_for_id(language_server_id)
9824 .map(|adapter| adapter.name()),
9825 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9826 Default::default(),
9827 ),
9828 })
9829 }
9830
9831 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9832 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9833 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9834 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9835 // the language server might take some time to publish diagnostics.
9836 fn simulate_disk_based_diagnostics_events_if_needed(
9837 &mut self,
9838 language_server_id: LanguageServerId,
9839 cx: &mut Context<Self>,
9840 ) {
9841 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9842
9843 let Some(LanguageServerState::Running {
9844 simulate_disk_based_diagnostics_completion,
9845 adapter,
9846 ..
9847 }) = self
9848 .as_local_mut()
9849 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9850 else {
9851 return;
9852 };
9853
9854 if adapter.disk_based_diagnostics_progress_token.is_some() {
9855 return;
9856 }
9857
9858 let prev_task =
9859 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9860 cx.background_executor()
9861 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9862 .await;
9863
9864 this.update(cx, |this, cx| {
9865 this.disk_based_diagnostics_finished(language_server_id, cx);
9866
9867 if let Some(LanguageServerState::Running {
9868 simulate_disk_based_diagnostics_completion,
9869 ..
9870 }) = this.as_local_mut().and_then(|local_store| {
9871 local_store.language_servers.get_mut(&language_server_id)
9872 }) {
9873 *simulate_disk_based_diagnostics_completion = None;
9874 }
9875 })
9876 .ok();
9877 }));
9878
9879 if prev_task.is_none() {
9880 self.disk_based_diagnostics_started(language_server_id, cx);
9881 }
9882 }
9883
9884 pub fn language_server_statuses(
9885 &self,
9886 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9887 self.language_server_statuses
9888 .iter()
9889 .map(|(key, value)| (*key, value))
9890 }
9891
9892 pub(super) fn did_rename_entry(
9893 &self,
9894 worktree_id: WorktreeId,
9895 old_path: &Path,
9896 new_path: &Path,
9897 is_dir: bool,
9898 ) {
9899 maybe!({
9900 let local_store = self.as_local()?;
9901
9902 let old_uri = lsp::Uri::from_file_path(old_path)
9903 .ok()
9904 .map(|uri| uri.to_string())?;
9905 let new_uri = lsp::Uri::from_file_path(new_path)
9906 .ok()
9907 .map(|uri| uri.to_string())?;
9908
9909 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9910 let Some(filter) = local_store
9911 .language_server_paths_watched_for_rename
9912 .get(&language_server.server_id())
9913 else {
9914 continue;
9915 };
9916
9917 if filter.should_send_did_rename(&old_uri, is_dir) {
9918 language_server
9919 .notify::<DidRenameFiles>(RenameFilesParams {
9920 files: vec![FileRename {
9921 old_uri: old_uri.clone(),
9922 new_uri: new_uri.clone(),
9923 }],
9924 })
9925 .ok();
9926 }
9927 }
9928 Some(())
9929 });
9930 }
9931
9932 pub(super) fn will_rename_entry(
9933 this: WeakEntity<Self>,
9934 worktree_id: WorktreeId,
9935 old_path: &Path,
9936 new_path: &Path,
9937 is_dir: bool,
9938 cx: AsyncApp,
9939 ) -> Task<ProjectTransaction> {
9940 let old_uri = lsp::Uri::from_file_path(old_path)
9941 .ok()
9942 .map(|uri| uri.to_string());
9943 let new_uri = lsp::Uri::from_file_path(new_path)
9944 .ok()
9945 .map(|uri| uri.to_string());
9946 cx.spawn(async move |cx| {
9947 let mut tasks = vec![];
9948 this.update(cx, |this, cx| {
9949 let local_store = this.as_local()?;
9950 let old_uri = old_uri?;
9951 let new_uri = new_uri?;
9952 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9953 let Some(filter) = local_store
9954 .language_server_paths_watched_for_rename
9955 .get(&language_server.server_id())
9956 else {
9957 continue;
9958 };
9959
9960 if !filter.should_send_will_rename(&old_uri, is_dir) {
9961 continue;
9962 }
9963 let request_timeout = ProjectSettings::get_global(cx)
9964 .global_lsp_settings
9965 .get_request_timeout();
9966
9967 let apply_edit = cx.spawn({
9968 let old_uri = old_uri.clone();
9969 let new_uri = new_uri.clone();
9970 let language_server = language_server.clone();
9971 async move |this, cx| {
9972 let edit = language_server
9973 .request::<WillRenameFiles>(
9974 RenameFilesParams {
9975 files: vec![FileRename { old_uri, new_uri }],
9976 },
9977 request_timeout,
9978 )
9979 .await
9980 .into_response()
9981 .context("will rename files")
9982 .log_err()
9983 .flatten()?;
9984
9985 LocalLspStore::deserialize_workspace_edit(
9986 this.upgrade()?,
9987 edit,
9988 false,
9989 language_server.clone(),
9990 cx,
9991 )
9992 .await
9993 .ok()
9994 }
9995 });
9996 tasks.push(apply_edit);
9997 }
9998 Some(())
9999 })
10000 .ok()
10001 .flatten();
10002 let mut merged_transaction = ProjectTransaction::default();
10003 for task in tasks {
10004 // Await on tasks sequentially so that the order of application of edits is deterministic
10005 // (at least with regards to the order of registration of language servers)
10006 if let Some(transaction) = task.await {
10007 for (buffer, buffer_transaction) in transaction.0 {
10008 merged_transaction.0.insert(buffer, buffer_transaction);
10009 }
10010 }
10011 }
10012 merged_transaction
10013 })
10014 }
10015
10016 fn lsp_notify_abs_paths_changed(
10017 &mut self,
10018 server_id: LanguageServerId,
10019 changes: Vec<PathEvent>,
10020 ) {
10021 maybe!({
10022 let server = self.language_server_for_id(server_id)?;
10023 let changes = changes
10024 .into_iter()
10025 .filter_map(|event| {
10026 let typ = match event.kind? {
10027 PathEventKind::Created => lsp::FileChangeType::CREATED,
10028 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10029 PathEventKind::Changed | PathEventKind::Rescan => {
10030 lsp::FileChangeType::CHANGED
10031 }
10032 };
10033 Some(lsp::FileEvent {
10034 uri: file_path_to_lsp_url(&event.path).log_err()?,
10035 typ,
10036 })
10037 })
10038 .collect::<Vec<_>>();
10039 if !changes.is_empty() {
10040 server
10041 .notify::<lsp::notification::DidChangeWatchedFiles>(
10042 lsp::DidChangeWatchedFilesParams { changes },
10043 )
10044 .ok();
10045 }
10046 Some(())
10047 });
10048 }
10049
10050 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10051 self.as_local()?.language_server_for_id(id)
10052 }
10053
10054 fn on_lsp_progress(
10055 &mut self,
10056 progress_params: lsp::ProgressParams,
10057 language_server_id: LanguageServerId,
10058 disk_based_diagnostics_progress_token: Option<String>,
10059 cx: &mut Context<Self>,
10060 ) {
10061 match progress_params.value {
10062 lsp::ProgressParamsValue::WorkDone(progress) => {
10063 self.handle_work_done_progress(
10064 progress,
10065 language_server_id,
10066 disk_based_diagnostics_progress_token,
10067 ProgressToken::from_lsp(progress_params.token),
10068 cx,
10069 );
10070 }
10071 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10072 let registration_id = match progress_params.token {
10073 lsp::NumberOrString::Number(_) => None,
10074 lsp::NumberOrString::String(token) => token
10075 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10076 .map(|(_, id)| id.to_owned()),
10077 };
10078 if let Some(LanguageServerState::Running {
10079 workspace_diagnostics_refresh_tasks,
10080 ..
10081 }) = self
10082 .as_local_mut()
10083 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10084 && let Some(workspace_diagnostics) =
10085 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10086 {
10087 workspace_diagnostics.progress_tx.try_send(()).ok();
10088 self.apply_workspace_diagnostic_report(
10089 language_server_id,
10090 report,
10091 registration_id.map(SharedString::from),
10092 cx,
10093 )
10094 }
10095 }
10096 }
10097 }
10098
10099 fn handle_work_done_progress(
10100 &mut self,
10101 progress: lsp::WorkDoneProgress,
10102 language_server_id: LanguageServerId,
10103 disk_based_diagnostics_progress_token: Option<String>,
10104 token: ProgressToken,
10105 cx: &mut Context<Self>,
10106 ) {
10107 let language_server_status =
10108 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10109 status
10110 } else {
10111 return;
10112 };
10113
10114 if !language_server_status.progress_tokens.contains(&token) {
10115 return;
10116 }
10117
10118 let is_disk_based_diagnostics_progress =
10119 if let (Some(disk_based_token), ProgressToken::String(token)) =
10120 (&disk_based_diagnostics_progress_token, &token)
10121 {
10122 token.starts_with(disk_based_token)
10123 } else {
10124 false
10125 };
10126
10127 match progress {
10128 lsp::WorkDoneProgress::Begin(report) => {
10129 if is_disk_based_diagnostics_progress {
10130 self.disk_based_diagnostics_started(language_server_id, cx);
10131 }
10132 self.on_lsp_work_start(
10133 language_server_id,
10134 token.clone(),
10135 LanguageServerProgress {
10136 title: Some(report.title),
10137 is_disk_based_diagnostics_progress,
10138 is_cancellable: report.cancellable.unwrap_or(false),
10139 message: report.message.clone(),
10140 percentage: report.percentage.map(|p| p as usize),
10141 last_update_at: cx.background_executor().now(),
10142 },
10143 cx,
10144 );
10145 }
10146 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10147 language_server_id,
10148 token,
10149 LanguageServerProgress {
10150 title: None,
10151 is_disk_based_diagnostics_progress,
10152 is_cancellable: report.cancellable.unwrap_or(false),
10153 message: report.message,
10154 percentage: report.percentage.map(|p| p as usize),
10155 last_update_at: cx.background_executor().now(),
10156 },
10157 cx,
10158 ),
10159 lsp::WorkDoneProgress::End(_) => {
10160 language_server_status.progress_tokens.remove(&token);
10161 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10162 if is_disk_based_diagnostics_progress {
10163 self.disk_based_diagnostics_finished(language_server_id, cx);
10164 }
10165 }
10166 }
10167 }
10168
10169 fn on_lsp_work_start(
10170 &mut self,
10171 language_server_id: LanguageServerId,
10172 token: ProgressToken,
10173 progress: LanguageServerProgress,
10174 cx: &mut Context<Self>,
10175 ) {
10176 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10177 status.pending_work.insert(token.clone(), progress.clone());
10178 cx.notify();
10179 }
10180 cx.emit(LspStoreEvent::LanguageServerUpdate {
10181 language_server_id,
10182 name: self
10183 .language_server_adapter_for_id(language_server_id)
10184 .map(|adapter| adapter.name()),
10185 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10186 token: Some(token.to_proto()),
10187 title: progress.title,
10188 message: progress.message,
10189 percentage: progress.percentage.map(|p| p as u32),
10190 is_cancellable: Some(progress.is_cancellable),
10191 }),
10192 })
10193 }
10194
10195 fn on_lsp_work_progress(
10196 &mut self,
10197 language_server_id: LanguageServerId,
10198 token: ProgressToken,
10199 progress: LanguageServerProgress,
10200 cx: &mut Context<Self>,
10201 ) {
10202 let mut did_update = false;
10203 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10204 match status.pending_work.entry(token.clone()) {
10205 btree_map::Entry::Vacant(entry) => {
10206 entry.insert(progress.clone());
10207 did_update = true;
10208 }
10209 btree_map::Entry::Occupied(mut entry) => {
10210 let entry = entry.get_mut();
10211 if (progress.last_update_at - entry.last_update_at)
10212 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10213 {
10214 entry.last_update_at = progress.last_update_at;
10215 if progress.message.is_some() {
10216 entry.message = progress.message.clone();
10217 }
10218 if progress.percentage.is_some() {
10219 entry.percentage = progress.percentage;
10220 }
10221 if progress.is_cancellable != entry.is_cancellable {
10222 entry.is_cancellable = progress.is_cancellable;
10223 }
10224 did_update = true;
10225 }
10226 }
10227 }
10228 }
10229
10230 if did_update {
10231 cx.emit(LspStoreEvent::LanguageServerUpdate {
10232 language_server_id,
10233 name: self
10234 .language_server_adapter_for_id(language_server_id)
10235 .map(|adapter| adapter.name()),
10236 message: proto::update_language_server::Variant::WorkProgress(
10237 proto::LspWorkProgress {
10238 token: Some(token.to_proto()),
10239 message: progress.message,
10240 percentage: progress.percentage.map(|p| p as u32),
10241 is_cancellable: Some(progress.is_cancellable),
10242 },
10243 ),
10244 })
10245 }
10246 }
10247
10248 fn on_lsp_work_end(
10249 &mut self,
10250 language_server_id: LanguageServerId,
10251 token: ProgressToken,
10252 cx: &mut Context<Self>,
10253 ) {
10254 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10255 if let Some(work) = status.pending_work.remove(&token)
10256 && !work.is_disk_based_diagnostics_progress
10257 {
10258 cx.emit(LspStoreEvent::RefreshInlayHints {
10259 server_id: language_server_id,
10260 request_id: None,
10261 });
10262 }
10263 cx.notify();
10264 }
10265
10266 cx.emit(LspStoreEvent::LanguageServerUpdate {
10267 language_server_id,
10268 name: self
10269 .language_server_adapter_for_id(language_server_id)
10270 .map(|adapter| adapter.name()),
10271 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10272 token: Some(token.to_proto()),
10273 }),
10274 })
10275 }
10276
10277 pub async fn handle_resolve_completion_documentation(
10278 this: Entity<Self>,
10279 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10280 mut cx: AsyncApp,
10281 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10282 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10283
10284 let completion = this
10285 .read_with(&cx, |this, cx| {
10286 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10287 let server = this
10288 .language_server_for_id(id)
10289 .with_context(|| format!("No language server {id}"))?;
10290
10291 let request_timeout = ProjectSettings::get_global(cx)
10292 .global_lsp_settings
10293 .get_request_timeout();
10294
10295 anyhow::Ok(cx.background_spawn(async move {
10296 let can_resolve = server
10297 .capabilities()
10298 .completion_provider
10299 .as_ref()
10300 .and_then(|options| options.resolve_provider)
10301 .unwrap_or(false);
10302 if can_resolve {
10303 server
10304 .request::<lsp::request::ResolveCompletionItem>(
10305 lsp_completion,
10306 request_timeout,
10307 )
10308 .await
10309 .into_response()
10310 .context("resolve completion item")
10311 } else {
10312 anyhow::Ok(lsp_completion)
10313 }
10314 }))
10315 })?
10316 .await?;
10317
10318 let mut documentation_is_markdown = false;
10319 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10320 let documentation = match completion.documentation {
10321 Some(lsp::Documentation::String(text)) => text,
10322
10323 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10324 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10325 value
10326 }
10327
10328 _ => String::new(),
10329 };
10330
10331 // If we have a new buffer_id, that means we're talking to a new client
10332 // and want to check for new text_edits in the completion too.
10333 let mut old_replace_start = None;
10334 let mut old_replace_end = None;
10335 let mut old_insert_start = None;
10336 let mut old_insert_end = None;
10337 let mut new_text = String::default();
10338 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10339 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10340 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10341 anyhow::Ok(buffer.read(cx).snapshot())
10342 })?;
10343
10344 if let Some(text_edit) = completion.text_edit.as_ref() {
10345 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10346
10347 if let Some(mut edit) = edit {
10348 LineEnding::normalize(&mut edit.new_text);
10349
10350 new_text = edit.new_text;
10351 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10352 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10353 if let Some(insert_range) = edit.insert_range {
10354 old_insert_start = Some(serialize_anchor(&insert_range.start));
10355 old_insert_end = Some(serialize_anchor(&insert_range.end));
10356 }
10357 }
10358 }
10359 }
10360
10361 Ok(proto::ResolveCompletionDocumentationResponse {
10362 documentation,
10363 documentation_is_markdown,
10364 old_replace_start,
10365 old_replace_end,
10366 new_text,
10367 lsp_completion,
10368 old_insert_start,
10369 old_insert_end,
10370 })
10371 }
10372
10373 async fn handle_on_type_formatting(
10374 this: Entity<Self>,
10375 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10376 mut cx: AsyncApp,
10377 ) -> Result<proto::OnTypeFormattingResponse> {
10378 let on_type_formatting = this.update(&mut cx, |this, cx| {
10379 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10380 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10381 let position = envelope
10382 .payload
10383 .position
10384 .and_then(deserialize_anchor)
10385 .context("invalid position")?;
10386 anyhow::Ok(this.apply_on_type_formatting(
10387 buffer,
10388 position,
10389 envelope.payload.trigger.clone(),
10390 cx,
10391 ))
10392 })?;
10393
10394 let transaction = on_type_formatting
10395 .await?
10396 .as_ref()
10397 .map(language::proto::serialize_transaction);
10398 Ok(proto::OnTypeFormattingResponse { transaction })
10399 }
10400
10401 async fn handle_pull_workspace_diagnostics(
10402 lsp_store: Entity<Self>,
10403 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10404 mut cx: AsyncApp,
10405 ) -> Result<proto::Ack> {
10406 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10407 lsp_store.update(&mut cx, |lsp_store, _| {
10408 lsp_store.pull_workspace_diagnostics(server_id);
10409 });
10410 Ok(proto::Ack {})
10411 }
10412
10413 async fn handle_open_buffer_for_symbol(
10414 this: Entity<Self>,
10415 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10416 mut cx: AsyncApp,
10417 ) -> Result<proto::OpenBufferForSymbolResponse> {
10418 let peer_id = envelope.original_sender_id().unwrap_or_default();
10419 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10420 let symbol = Self::deserialize_symbol(symbol)?;
10421 this.read_with(&cx, |this, _| {
10422 if let SymbolLocation::OutsideProject {
10423 abs_path,
10424 signature,
10425 } = &symbol.path
10426 {
10427 let new_signature = this.symbol_signature(&abs_path);
10428 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10429 }
10430 Ok(())
10431 })?;
10432 let buffer = this
10433 .update(&mut cx, |this, cx| {
10434 this.open_buffer_for_symbol(
10435 &Symbol {
10436 language_server_name: symbol.language_server_name,
10437 source_worktree_id: symbol.source_worktree_id,
10438 source_language_server_id: symbol.source_language_server_id,
10439 path: symbol.path,
10440 name: symbol.name,
10441 kind: symbol.kind,
10442 range: symbol.range,
10443 label: CodeLabel::default(),
10444 container_name: symbol.container_name,
10445 },
10446 cx,
10447 )
10448 })
10449 .await?;
10450
10451 this.update(&mut cx, |this, cx| {
10452 let is_private = buffer
10453 .read(cx)
10454 .file()
10455 .map(|f| f.is_private())
10456 .unwrap_or_default();
10457 if is_private {
10458 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10459 } else {
10460 this.buffer_store
10461 .update(cx, |buffer_store, cx| {
10462 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10463 })
10464 .detach_and_log_err(cx);
10465 let buffer_id = buffer.read(cx).remote_id().to_proto();
10466 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10467 }
10468 })
10469 }
10470
10471 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10472 let mut hasher = Sha256::new();
10473 hasher.update(abs_path.to_string_lossy().as_bytes());
10474 hasher.update(self.nonce.to_be_bytes());
10475 hasher.finalize().as_slice().try_into().unwrap()
10476 }
10477
10478 pub async fn handle_get_project_symbols(
10479 this: Entity<Self>,
10480 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10481 mut cx: AsyncApp,
10482 ) -> Result<proto::GetProjectSymbolsResponse> {
10483 let symbols = this
10484 .update(&mut cx, |this, cx| {
10485 this.symbols(&envelope.payload.query, cx)
10486 })
10487 .await?;
10488
10489 Ok(proto::GetProjectSymbolsResponse {
10490 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10491 })
10492 }
10493
10494 pub async fn handle_restart_language_servers(
10495 this: Entity<Self>,
10496 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10497 mut cx: AsyncApp,
10498 ) -> Result<proto::Ack> {
10499 this.update(&mut cx, |lsp_store, cx| {
10500 let buffers =
10501 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10502 lsp_store.restart_language_servers_for_buffers(
10503 buffers,
10504 envelope
10505 .payload
10506 .only_servers
10507 .into_iter()
10508 .filter_map(|selector| {
10509 Some(match selector.selector? {
10510 proto::language_server_selector::Selector::ServerId(server_id) => {
10511 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10512 }
10513 proto::language_server_selector::Selector::Name(name) => {
10514 LanguageServerSelector::Name(LanguageServerName(
10515 SharedString::from(name),
10516 ))
10517 }
10518 })
10519 })
10520 .collect(),
10521 cx,
10522 );
10523 });
10524
10525 Ok(proto::Ack {})
10526 }
10527
10528 pub async fn handle_stop_language_servers(
10529 lsp_store: Entity<Self>,
10530 envelope: TypedEnvelope<proto::StopLanguageServers>,
10531 mut cx: AsyncApp,
10532 ) -> Result<proto::Ack> {
10533 lsp_store.update(&mut cx, |lsp_store, cx| {
10534 if envelope.payload.all
10535 && envelope.payload.also_servers.is_empty()
10536 && envelope.payload.buffer_ids.is_empty()
10537 {
10538 lsp_store.stop_all_language_servers(cx);
10539 } else {
10540 let buffers =
10541 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10542 lsp_store
10543 .stop_language_servers_for_buffers(
10544 buffers,
10545 envelope
10546 .payload
10547 .also_servers
10548 .into_iter()
10549 .filter_map(|selector| {
10550 Some(match selector.selector? {
10551 proto::language_server_selector::Selector::ServerId(
10552 server_id,
10553 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10554 server_id,
10555 )),
10556 proto::language_server_selector::Selector::Name(name) => {
10557 LanguageServerSelector::Name(LanguageServerName(
10558 SharedString::from(name),
10559 ))
10560 }
10561 })
10562 })
10563 .collect(),
10564 cx,
10565 )
10566 .detach_and_log_err(cx);
10567 }
10568 });
10569
10570 Ok(proto::Ack {})
10571 }
10572
10573 pub async fn handle_cancel_language_server_work(
10574 lsp_store: Entity<Self>,
10575 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10576 mut cx: AsyncApp,
10577 ) -> Result<proto::Ack> {
10578 lsp_store.update(&mut cx, |lsp_store, cx| {
10579 if let Some(work) = envelope.payload.work {
10580 match work {
10581 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10582 let buffers =
10583 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10584 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10585 }
10586 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10587 let server_id = LanguageServerId::from_proto(work.language_server_id);
10588 let token = work
10589 .token
10590 .map(|token| {
10591 ProgressToken::from_proto(token)
10592 .context("invalid work progress token")
10593 })
10594 .transpose()?;
10595 lsp_store.cancel_language_server_work(server_id, token, cx);
10596 }
10597 }
10598 }
10599 anyhow::Ok(())
10600 })?;
10601
10602 Ok(proto::Ack {})
10603 }
10604
10605 fn buffer_ids_to_buffers(
10606 &mut self,
10607 buffer_ids: impl Iterator<Item = u64>,
10608 cx: &mut Context<Self>,
10609 ) -> Vec<Entity<Buffer>> {
10610 buffer_ids
10611 .into_iter()
10612 .flat_map(|buffer_id| {
10613 self.buffer_store
10614 .read(cx)
10615 .get(BufferId::new(buffer_id).log_err()?)
10616 })
10617 .collect::<Vec<_>>()
10618 }
10619
10620 async fn handle_apply_additional_edits_for_completion(
10621 this: Entity<Self>,
10622 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10623 mut cx: AsyncApp,
10624 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10625 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10626 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10627 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10628 let completion = Self::deserialize_completion(
10629 envelope.payload.completion.context("invalid completion")?,
10630 )?;
10631 let all_commit_ranges = envelope
10632 .payload
10633 .all_commit_ranges
10634 .into_iter()
10635 .map(language::proto::deserialize_anchor_range)
10636 .collect::<Result<Vec<_>, _>>()?;
10637 anyhow::Ok((buffer, completion, all_commit_ranges))
10638 })?;
10639
10640 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10641 this.apply_additional_edits_for_completion(
10642 buffer,
10643 Rc::new(RefCell::new(Box::new([Completion {
10644 replace_range: completion.replace_range,
10645 new_text: completion.new_text,
10646 source: completion.source,
10647 documentation: None,
10648 label: CodeLabel::default(),
10649 match_start: None,
10650 snippet_deduplication_key: None,
10651 insert_text_mode: None,
10652 icon_path: None,
10653 confirm: None,
10654 }]))),
10655 0,
10656 false,
10657 all_commit_ranges,
10658 cx,
10659 )
10660 });
10661
10662 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10663 transaction: apply_additional_edits
10664 .await?
10665 .as_ref()
10666 .map(language::proto::serialize_transaction),
10667 })
10668 }
10669
10670 pub fn last_formatting_failure(&self) -> Option<&str> {
10671 self.last_formatting_failure.as_deref()
10672 }
10673
10674 pub fn reset_last_formatting_failure(&mut self) {
10675 self.last_formatting_failure = None;
10676 }
10677
10678 pub fn environment_for_buffer(
10679 &self,
10680 buffer: &Entity<Buffer>,
10681 cx: &mut Context<Self>,
10682 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10683 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10684 environment.update(cx, |env, cx| {
10685 env.buffer_environment(buffer, &self.worktree_store, cx)
10686 })
10687 } else {
10688 Task::ready(None).shared()
10689 }
10690 }
10691
10692 pub fn format(
10693 &mut self,
10694 buffers: HashSet<Entity<Buffer>>,
10695 target: LspFormatTarget,
10696 push_to_history: bool,
10697 trigger: FormatTrigger,
10698 cx: &mut Context<Self>,
10699 ) -> Task<anyhow::Result<ProjectTransaction>> {
10700 let logger = zlog::scoped!("format");
10701 if self.as_local().is_some() {
10702 zlog::trace!(logger => "Formatting locally");
10703 let logger = zlog::scoped!(logger => "local");
10704 let buffers = buffers
10705 .into_iter()
10706 .map(|buffer_handle| {
10707 let buffer = buffer_handle.read(cx);
10708 let buffer_abs_path = File::from_dyn(buffer.file())
10709 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10710
10711 (buffer_handle, buffer_abs_path, buffer.remote_id())
10712 })
10713 .collect::<Vec<_>>();
10714
10715 cx.spawn(async move |lsp_store, cx| {
10716 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10717
10718 for (handle, abs_path, id) in buffers {
10719 let env = lsp_store
10720 .update(cx, |lsp_store, cx| {
10721 lsp_store.environment_for_buffer(&handle, cx)
10722 })?
10723 .await;
10724
10725 let ranges = match &target {
10726 LspFormatTarget::Buffers => None,
10727 LspFormatTarget::Ranges(ranges) => {
10728 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10729 }
10730 };
10731
10732 formattable_buffers.push(FormattableBuffer {
10733 handle,
10734 abs_path,
10735 env,
10736 ranges,
10737 });
10738 }
10739 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10740
10741 let format_timer = zlog::time!(logger => "Formatting buffers");
10742 let result = LocalLspStore::format_locally(
10743 lsp_store.clone(),
10744 formattable_buffers,
10745 push_to_history,
10746 trigger,
10747 logger,
10748 cx,
10749 )
10750 .await;
10751 format_timer.end();
10752
10753 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10754
10755 lsp_store.update(cx, |lsp_store, _| {
10756 lsp_store.update_last_formatting_failure(&result);
10757 })?;
10758
10759 result
10760 })
10761 } else if let Some((client, project_id)) = self.upstream_client() {
10762 zlog::trace!(logger => "Formatting remotely");
10763 let logger = zlog::scoped!(logger => "remote");
10764
10765 let buffer_ranges = match &target {
10766 LspFormatTarget::Buffers => Vec::new(),
10767 LspFormatTarget::Ranges(ranges) => ranges
10768 .iter()
10769 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10770 buffer_id: buffer_id.to_proto(),
10771 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10772 })
10773 .collect(),
10774 };
10775
10776 let buffer_store = self.buffer_store();
10777 cx.spawn(async move |lsp_store, cx| {
10778 zlog::trace!(logger => "Sending remote format request");
10779 let request_timer = zlog::time!(logger => "remote format request");
10780 let result = client
10781 .request(proto::FormatBuffers {
10782 project_id,
10783 trigger: trigger as i32,
10784 buffer_ids: buffers
10785 .iter()
10786 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10787 .collect(),
10788 buffer_ranges,
10789 })
10790 .await
10791 .and_then(|result| result.transaction.context("missing transaction"));
10792 request_timer.end();
10793
10794 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10795
10796 lsp_store.update(cx, |lsp_store, _| {
10797 lsp_store.update_last_formatting_failure(&result);
10798 })?;
10799
10800 let transaction_response = result?;
10801 let _timer = zlog::time!(logger => "deserializing project transaction");
10802 buffer_store
10803 .update(cx, |buffer_store, cx| {
10804 buffer_store.deserialize_project_transaction(
10805 transaction_response,
10806 push_to_history,
10807 cx,
10808 )
10809 })
10810 .await
10811 })
10812 } else {
10813 zlog::trace!(logger => "Not formatting");
10814 Task::ready(Ok(ProjectTransaction::default()))
10815 }
10816 }
10817
10818 async fn handle_format_buffers(
10819 this: Entity<Self>,
10820 envelope: TypedEnvelope<proto::FormatBuffers>,
10821 mut cx: AsyncApp,
10822 ) -> Result<proto::FormatBuffersResponse> {
10823 let sender_id = envelope.original_sender_id().unwrap_or_default();
10824 let format = this.update(&mut cx, |this, cx| {
10825 let mut buffers = HashSet::default();
10826 for buffer_id in &envelope.payload.buffer_ids {
10827 let buffer_id = BufferId::new(*buffer_id)?;
10828 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10829 }
10830
10831 let target = if envelope.payload.buffer_ranges.is_empty() {
10832 LspFormatTarget::Buffers
10833 } else {
10834 let mut ranges_map = BTreeMap::new();
10835 for buffer_range in &envelope.payload.buffer_ranges {
10836 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10837 let ranges: Result<Vec<_>> = buffer_range
10838 .ranges
10839 .iter()
10840 .map(|range| {
10841 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10842 })
10843 .collect();
10844 ranges_map.insert(buffer_id, ranges?);
10845 }
10846 LspFormatTarget::Ranges(ranges_map)
10847 };
10848
10849 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10850 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10851 })?;
10852
10853 let project_transaction = format.await?;
10854 let project_transaction = this.update(&mut cx, |this, cx| {
10855 this.buffer_store.update(cx, |buffer_store, cx| {
10856 buffer_store.serialize_project_transaction_for_peer(
10857 project_transaction,
10858 sender_id,
10859 cx,
10860 )
10861 })
10862 });
10863 Ok(proto::FormatBuffersResponse {
10864 transaction: Some(project_transaction),
10865 })
10866 }
10867
10868 async fn handle_apply_code_action_kind(
10869 this: Entity<Self>,
10870 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10871 mut cx: AsyncApp,
10872 ) -> Result<proto::ApplyCodeActionKindResponse> {
10873 let sender_id = envelope.original_sender_id().unwrap_or_default();
10874 let format = this.update(&mut cx, |this, cx| {
10875 let mut buffers = HashSet::default();
10876 for buffer_id in &envelope.payload.buffer_ids {
10877 let buffer_id = BufferId::new(*buffer_id)?;
10878 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10879 }
10880 let kind = match envelope.payload.kind.as_str() {
10881 "" => CodeActionKind::EMPTY,
10882 "quickfix" => CodeActionKind::QUICKFIX,
10883 "refactor" => CodeActionKind::REFACTOR,
10884 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10885 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10886 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10887 "source" => CodeActionKind::SOURCE,
10888 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10889 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10890 _ => anyhow::bail!(
10891 "Invalid code action kind {}",
10892 envelope.payload.kind.as_str()
10893 ),
10894 };
10895 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10896 })?;
10897
10898 let project_transaction = format.await?;
10899 let project_transaction = this.update(&mut cx, |this, cx| {
10900 this.buffer_store.update(cx, |buffer_store, cx| {
10901 buffer_store.serialize_project_transaction_for_peer(
10902 project_transaction,
10903 sender_id,
10904 cx,
10905 )
10906 })
10907 });
10908 Ok(proto::ApplyCodeActionKindResponse {
10909 transaction: Some(project_transaction),
10910 })
10911 }
10912
10913 async fn shutdown_language_server(
10914 server_state: Option<LanguageServerState>,
10915 name: LanguageServerName,
10916 cx: &mut AsyncApp,
10917 ) {
10918 let server = match server_state {
10919 Some(LanguageServerState::Starting { startup, .. }) => {
10920 let mut timer = cx
10921 .background_executor()
10922 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10923 .fuse();
10924
10925 select! {
10926 server = startup.fuse() => server,
10927 () = timer => {
10928 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10929 None
10930 },
10931 }
10932 }
10933
10934 Some(LanguageServerState::Running { server, .. }) => Some(server),
10935
10936 None => None,
10937 };
10938
10939 let Some(server) = server else { return };
10940 if let Some(shutdown) = server.shutdown() {
10941 shutdown.await;
10942 }
10943 }
10944
10945 // Returns a list of all of the worktrees which no longer have a language server and the root path
10946 // for the stopped server
10947 fn stop_local_language_server(
10948 &mut self,
10949 server_id: LanguageServerId,
10950 cx: &mut Context<Self>,
10951 ) -> Task<()> {
10952 let local = match &mut self.mode {
10953 LspStoreMode::Local(local) => local,
10954 _ => {
10955 return Task::ready(());
10956 }
10957 };
10958
10959 // Remove this server ID from all entries in the given worktree.
10960 local
10961 .language_server_ids
10962 .retain(|_, state| state.id != server_id);
10963 self.buffer_store.update(cx, |buffer_store, cx| {
10964 for buffer in buffer_store.buffers() {
10965 buffer.update(cx, |buffer, cx| {
10966 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10967 buffer.set_completion_triggers(server_id, Default::default(), cx);
10968 });
10969 }
10970 });
10971
10972 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10973 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10974 summaries.retain(|path, summaries_by_server_id| {
10975 if summaries_by_server_id.remove(&server_id).is_some() {
10976 if let Some((client, project_id)) = self.downstream_client.clone() {
10977 client
10978 .send(proto::UpdateDiagnosticSummary {
10979 project_id,
10980 worktree_id: worktree_id.to_proto(),
10981 summary: Some(proto::DiagnosticSummary {
10982 path: path.as_ref().to_proto(),
10983 language_server_id: server_id.0 as u64,
10984 error_count: 0,
10985 warning_count: 0,
10986 }),
10987 more_summaries: Vec::new(),
10988 })
10989 .log_err();
10990 }
10991 cleared_paths.push(ProjectPath {
10992 worktree_id: *worktree_id,
10993 path: path.clone(),
10994 });
10995 !summaries_by_server_id.is_empty()
10996 } else {
10997 true
10998 }
10999 });
11000 }
11001 if !cleared_paths.is_empty() {
11002 cx.emit(LspStoreEvent::DiagnosticsUpdated {
11003 server_id,
11004 paths: cleared_paths,
11005 });
11006 }
11007
11008 let local = self.as_local_mut().unwrap();
11009 for diagnostics in local.diagnostics.values_mut() {
11010 diagnostics.retain(|_, diagnostics_by_server_id| {
11011 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11012 diagnostics_by_server_id.remove(ix);
11013 !diagnostics_by_server_id.is_empty()
11014 } else {
11015 true
11016 }
11017 });
11018 }
11019 local.language_server_watched_paths.remove(&server_id);
11020
11021 let server_state = local.language_servers.remove(&server_id);
11022 self.cleanup_lsp_data(server_id);
11023 let name = self
11024 .language_server_statuses
11025 .remove(&server_id)
11026 .map(|status| status.name)
11027 .or_else(|| {
11028 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11029 Some(adapter.name())
11030 } else {
11031 None
11032 }
11033 });
11034
11035 if let Some(name) = name {
11036 log::info!("stopping language server {name}");
11037 self.languages
11038 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11039 cx.notify();
11040
11041 return cx.spawn(async move |lsp_store, cx| {
11042 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11043 lsp_store
11044 .update(cx, |lsp_store, cx| {
11045 lsp_store
11046 .languages
11047 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11048 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11049 cx.notify();
11050 })
11051 .ok();
11052 });
11053 }
11054
11055 if server_state.is_some() {
11056 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11057 }
11058 Task::ready(())
11059 }
11060
11061 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11062 self.shutdown_all_language_servers(cx).detach();
11063 }
11064
11065 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11066 if let Some((client, project_id)) = self.upstream_client() {
11067 let request = client.request(proto::StopLanguageServers {
11068 project_id,
11069 buffer_ids: Vec::new(),
11070 also_servers: Vec::new(),
11071 all: true,
11072 });
11073 cx.background_spawn(async move {
11074 request.await.ok();
11075 })
11076 } else {
11077 let Some(local) = self.as_local_mut() else {
11078 return Task::ready(());
11079 };
11080 let language_servers_to_stop = local
11081 .language_server_ids
11082 .values()
11083 .map(|state| state.id)
11084 .collect();
11085 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11086 let tasks = language_servers_to_stop
11087 .into_iter()
11088 .map(|server| self.stop_local_language_server(server, cx))
11089 .collect::<Vec<_>>();
11090 cx.background_spawn(async move {
11091 futures::future::join_all(tasks).await;
11092 })
11093 }
11094 }
11095
11096 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11097 let buffers = self.buffer_store.read(cx).buffers().collect();
11098 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11099 }
11100
11101 pub fn restart_language_servers_for_buffers(
11102 &mut self,
11103 buffers: Vec<Entity<Buffer>>,
11104 only_restart_servers: HashSet<LanguageServerSelector>,
11105 cx: &mut Context<Self>,
11106 ) {
11107 if let Some((client, project_id)) = self.upstream_client() {
11108 let request = client.request(proto::RestartLanguageServers {
11109 project_id,
11110 buffer_ids: buffers
11111 .into_iter()
11112 .map(|b| b.read(cx).remote_id().to_proto())
11113 .collect(),
11114 only_servers: only_restart_servers
11115 .into_iter()
11116 .map(|selector| {
11117 let selector = match selector {
11118 LanguageServerSelector::Id(language_server_id) => {
11119 proto::language_server_selector::Selector::ServerId(
11120 language_server_id.to_proto(),
11121 )
11122 }
11123 LanguageServerSelector::Name(language_server_name) => {
11124 proto::language_server_selector::Selector::Name(
11125 language_server_name.to_string(),
11126 )
11127 }
11128 };
11129 proto::LanguageServerSelector {
11130 selector: Some(selector),
11131 }
11132 })
11133 .collect(),
11134 all: false,
11135 });
11136 cx.background_spawn(request).detach_and_log_err(cx);
11137 } else {
11138 let stop_task = if only_restart_servers.is_empty() {
11139 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11140 } else {
11141 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11142 };
11143 cx.spawn(async move |lsp_store, cx| {
11144 stop_task.await;
11145 lsp_store.update(cx, |lsp_store, cx| {
11146 for buffer in buffers {
11147 lsp_store.register_buffer_with_language_servers(
11148 &buffer,
11149 only_restart_servers.clone(),
11150 true,
11151 cx,
11152 );
11153 }
11154 })
11155 })
11156 .detach();
11157 }
11158 }
11159
11160 pub fn stop_language_servers_for_buffers(
11161 &mut self,
11162 buffers: Vec<Entity<Buffer>>,
11163 also_stop_servers: HashSet<LanguageServerSelector>,
11164 cx: &mut Context<Self>,
11165 ) -> Task<Result<()>> {
11166 if let Some((client, project_id)) = self.upstream_client() {
11167 let request = client.request(proto::StopLanguageServers {
11168 project_id,
11169 buffer_ids: buffers
11170 .into_iter()
11171 .map(|b| b.read(cx).remote_id().to_proto())
11172 .collect(),
11173 also_servers: also_stop_servers
11174 .into_iter()
11175 .map(|selector| {
11176 let selector = match selector {
11177 LanguageServerSelector::Id(language_server_id) => {
11178 proto::language_server_selector::Selector::ServerId(
11179 language_server_id.to_proto(),
11180 )
11181 }
11182 LanguageServerSelector::Name(language_server_name) => {
11183 proto::language_server_selector::Selector::Name(
11184 language_server_name.to_string(),
11185 )
11186 }
11187 };
11188 proto::LanguageServerSelector {
11189 selector: Some(selector),
11190 }
11191 })
11192 .collect(),
11193 all: false,
11194 });
11195 cx.background_spawn(async move {
11196 let _ = request.await?;
11197 Ok(())
11198 })
11199 } else {
11200 let task =
11201 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11202 cx.background_spawn(async move {
11203 task.await;
11204 Ok(())
11205 })
11206 }
11207 }
11208
11209 fn stop_local_language_servers_for_buffers(
11210 &mut self,
11211 buffers: &[Entity<Buffer>],
11212 also_stop_servers: HashSet<LanguageServerSelector>,
11213 cx: &mut Context<Self>,
11214 ) -> Task<()> {
11215 let Some(local) = self.as_local_mut() else {
11216 return Task::ready(());
11217 };
11218 let mut language_server_names_to_stop = BTreeSet::default();
11219 let mut language_servers_to_stop = also_stop_servers
11220 .into_iter()
11221 .flat_map(|selector| match selector {
11222 LanguageServerSelector::Id(id) => Some(id),
11223 LanguageServerSelector::Name(name) => {
11224 language_server_names_to_stop.insert(name);
11225 None
11226 }
11227 })
11228 .collect::<BTreeSet<_>>();
11229
11230 let mut covered_worktrees = HashSet::default();
11231 for buffer in buffers {
11232 buffer.update(cx, |buffer, cx| {
11233 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11234 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11235 && covered_worktrees.insert(worktree_id)
11236 {
11237 language_server_names_to_stop.retain(|name| {
11238 let old_ids_count = language_servers_to_stop.len();
11239 let all_language_servers_with_this_name = local
11240 .language_server_ids
11241 .iter()
11242 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11243 language_servers_to_stop.extend(all_language_servers_with_this_name);
11244 old_ids_count == language_servers_to_stop.len()
11245 });
11246 }
11247 });
11248 }
11249 for name in language_server_names_to_stop {
11250 language_servers_to_stop.extend(
11251 local
11252 .language_server_ids
11253 .iter()
11254 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11255 );
11256 }
11257
11258 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11259 let tasks = language_servers_to_stop
11260 .into_iter()
11261 .map(|server| self.stop_local_language_server(server, cx))
11262 .collect::<Vec<_>>();
11263
11264 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11265 }
11266
11267 #[cfg(any(test, feature = "test-support"))]
11268 pub fn update_diagnostics(
11269 &mut self,
11270 server_id: LanguageServerId,
11271 diagnostics: lsp::PublishDiagnosticsParams,
11272 result_id: Option<SharedString>,
11273 source_kind: DiagnosticSourceKind,
11274 disk_based_sources: &[String],
11275 cx: &mut Context<Self>,
11276 ) -> Result<()> {
11277 self.merge_lsp_diagnostics(
11278 source_kind,
11279 vec![DocumentDiagnosticsUpdate {
11280 diagnostics,
11281 result_id,
11282 server_id,
11283 disk_based_sources: Cow::Borrowed(disk_based_sources),
11284 registration_id: None,
11285 }],
11286 |_, _, _| false,
11287 cx,
11288 )
11289 }
11290
11291 pub fn merge_lsp_diagnostics(
11292 &mut self,
11293 source_kind: DiagnosticSourceKind,
11294 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11295 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11296 cx: &mut Context<Self>,
11297 ) -> Result<()> {
11298 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11299 let updates = lsp_diagnostics
11300 .into_iter()
11301 .filter_map(|update| {
11302 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11303 Some(DocumentDiagnosticsUpdate {
11304 diagnostics: self.lsp_to_document_diagnostics(
11305 abs_path,
11306 source_kind,
11307 update.server_id,
11308 update.diagnostics,
11309 &update.disk_based_sources,
11310 update.registration_id.clone(),
11311 ),
11312 result_id: update.result_id,
11313 server_id: update.server_id,
11314 disk_based_sources: update.disk_based_sources,
11315 registration_id: update.registration_id,
11316 })
11317 })
11318 .collect();
11319 self.merge_diagnostic_entries(updates, merge, cx)?;
11320 Ok(())
11321 }
11322
11323 fn lsp_to_document_diagnostics(
11324 &mut self,
11325 document_abs_path: PathBuf,
11326 source_kind: DiagnosticSourceKind,
11327 server_id: LanguageServerId,
11328 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11329 disk_based_sources: &[String],
11330 registration_id: Option<SharedString>,
11331 ) -> DocumentDiagnostics {
11332 let mut diagnostics = Vec::default();
11333 let mut primary_diagnostic_group_ids = HashMap::default();
11334 let mut sources_by_group_id = HashMap::default();
11335 let mut supporting_diagnostics = HashMap::default();
11336
11337 let adapter = self.language_server_adapter_for_id(server_id);
11338
11339 // Ensure that primary diagnostics are always the most severe
11340 lsp_diagnostics
11341 .diagnostics
11342 .sort_by_key(|item| item.severity);
11343
11344 for diagnostic in &lsp_diagnostics.diagnostics {
11345 let source = diagnostic.source.as_ref();
11346 let range = range_from_lsp(diagnostic.range);
11347 let is_supporting = diagnostic
11348 .related_information
11349 .as_ref()
11350 .is_some_and(|infos| {
11351 infos.iter().any(|info| {
11352 primary_diagnostic_group_ids.contains_key(&(
11353 source,
11354 diagnostic.code.clone(),
11355 range_from_lsp(info.location.range),
11356 ))
11357 })
11358 });
11359
11360 let is_unnecessary = diagnostic
11361 .tags
11362 .as_ref()
11363 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11364
11365 let underline = self
11366 .language_server_adapter_for_id(server_id)
11367 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11368
11369 if is_supporting {
11370 supporting_diagnostics.insert(
11371 (source, diagnostic.code.clone(), range),
11372 (diagnostic.severity, is_unnecessary),
11373 );
11374 } else {
11375 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11376 let is_disk_based =
11377 source.is_some_and(|source| disk_based_sources.contains(source));
11378
11379 sources_by_group_id.insert(group_id, source);
11380 primary_diagnostic_group_ids
11381 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11382
11383 diagnostics.push(DiagnosticEntry {
11384 range,
11385 diagnostic: Diagnostic {
11386 source: diagnostic.source.clone(),
11387 source_kind,
11388 code: diagnostic.code.clone(),
11389 code_description: diagnostic
11390 .code_description
11391 .as_ref()
11392 .and_then(|d| d.href.clone()),
11393 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11394 markdown: adapter.as_ref().and_then(|adapter| {
11395 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11396 }),
11397 message: diagnostic.message.trim().to_string(),
11398 group_id,
11399 is_primary: true,
11400 is_disk_based,
11401 is_unnecessary,
11402 underline,
11403 data: diagnostic.data.clone(),
11404 registration_id: registration_id.clone(),
11405 },
11406 });
11407 if let Some(infos) = &diagnostic.related_information {
11408 for info in infos {
11409 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11410 let range = range_from_lsp(info.location.range);
11411 diagnostics.push(DiagnosticEntry {
11412 range,
11413 diagnostic: Diagnostic {
11414 source: diagnostic.source.clone(),
11415 source_kind,
11416 code: diagnostic.code.clone(),
11417 code_description: diagnostic
11418 .code_description
11419 .as_ref()
11420 .and_then(|d| d.href.clone()),
11421 severity: DiagnosticSeverity::INFORMATION,
11422 markdown: adapter.as_ref().and_then(|adapter| {
11423 adapter.diagnostic_message_to_markdown(&info.message)
11424 }),
11425 message: info.message.trim().to_string(),
11426 group_id,
11427 is_primary: false,
11428 is_disk_based,
11429 is_unnecessary: false,
11430 underline,
11431 data: diagnostic.data.clone(),
11432 registration_id: registration_id.clone(),
11433 },
11434 });
11435 }
11436 }
11437 }
11438 }
11439 }
11440
11441 for entry in &mut diagnostics {
11442 let diagnostic = &mut entry.diagnostic;
11443 if !diagnostic.is_primary {
11444 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11445 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11446 source,
11447 diagnostic.code.clone(),
11448 entry.range.clone(),
11449 )) {
11450 if let Some(severity) = severity {
11451 diagnostic.severity = severity;
11452 }
11453 diagnostic.is_unnecessary = is_unnecessary;
11454 }
11455 }
11456 }
11457
11458 DocumentDiagnostics {
11459 diagnostics,
11460 document_abs_path,
11461 version: lsp_diagnostics.version,
11462 }
11463 }
11464
11465 fn insert_newly_running_language_server(
11466 &mut self,
11467 adapter: Arc<CachedLspAdapter>,
11468 language_server: Arc<LanguageServer>,
11469 server_id: LanguageServerId,
11470 key: LanguageServerSeed,
11471 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11472 cx: &mut Context<Self>,
11473 ) {
11474 let Some(local) = self.as_local_mut() else {
11475 return;
11476 };
11477 // If the language server for this key doesn't match the server id, don't store the
11478 // server. Which will cause it to be dropped, killing the process
11479 if local
11480 .language_server_ids
11481 .get(&key)
11482 .map(|state| state.id != server_id)
11483 .unwrap_or(false)
11484 {
11485 return;
11486 }
11487
11488 // Update language_servers collection with Running variant of LanguageServerState
11489 // indicating that the server is up and running and ready
11490 let workspace_folders = workspace_folders.lock().clone();
11491 language_server.set_workspace_folders(workspace_folders);
11492
11493 let workspace_diagnostics_refresh_tasks = language_server
11494 .capabilities()
11495 .diagnostic_provider
11496 .and_then(|provider| {
11497 local
11498 .language_server_dynamic_registrations
11499 .entry(server_id)
11500 .or_default()
11501 .diagnostics
11502 .entry(None)
11503 .or_insert(provider.clone());
11504 let workspace_refresher =
11505 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11506
11507 Some((None, workspace_refresher))
11508 })
11509 .into_iter()
11510 .collect();
11511 local.language_servers.insert(
11512 server_id,
11513 LanguageServerState::Running {
11514 workspace_diagnostics_refresh_tasks,
11515 adapter: adapter.clone(),
11516 server: language_server.clone(),
11517 simulate_disk_based_diagnostics_completion: None,
11518 },
11519 );
11520 local
11521 .languages
11522 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11523 if let Some(file_ops_caps) = language_server
11524 .capabilities()
11525 .workspace
11526 .as_ref()
11527 .and_then(|ws| ws.file_operations.as_ref())
11528 {
11529 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11530 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11531 if did_rename_caps.or(will_rename_caps).is_some() {
11532 let watcher = RenamePathsWatchedForServer::default()
11533 .with_did_rename_patterns(did_rename_caps)
11534 .with_will_rename_patterns(will_rename_caps);
11535 local
11536 .language_server_paths_watched_for_rename
11537 .insert(server_id, watcher);
11538 }
11539 }
11540
11541 self.language_server_statuses.insert(
11542 server_id,
11543 LanguageServerStatus {
11544 name: language_server.name(),
11545 server_version: language_server.version(),
11546 server_readable_version: language_server.readable_version(),
11547 pending_work: Default::default(),
11548 has_pending_diagnostic_updates: false,
11549 progress_tokens: Default::default(),
11550 worktree: Some(key.worktree_id),
11551 binary: Some(language_server.binary().clone()),
11552 configuration: Some(language_server.configuration().clone()),
11553 workspace_folders: language_server.workspace_folders(),
11554 process_id: language_server.process_id(),
11555 },
11556 );
11557
11558 cx.emit(LspStoreEvent::LanguageServerAdded(
11559 server_id,
11560 language_server.name(),
11561 Some(key.worktree_id),
11562 ));
11563
11564 let server_capabilities = language_server.capabilities();
11565 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11566 downstream_client
11567 .send(proto::StartLanguageServer {
11568 project_id: *project_id,
11569 server: Some(proto::LanguageServer {
11570 id: server_id.to_proto(),
11571 name: language_server.name().to_string(),
11572 worktree_id: Some(key.worktree_id.to_proto()),
11573 }),
11574 capabilities: serde_json::to_string(&server_capabilities)
11575 .expect("serializing server LSP capabilities"),
11576 })
11577 .log_err();
11578 }
11579 self.lsp_server_capabilities
11580 .insert(server_id, server_capabilities);
11581
11582 // Tell the language server about every open buffer in the worktree that matches the language.
11583 // Also check for buffers in worktrees that reused this server
11584 let mut worktrees_using_server = vec![key.worktree_id];
11585 if let Some(local) = self.as_local() {
11586 // Find all worktrees that have this server in their language server tree
11587 for (worktree_id, servers) in &local.lsp_tree.instances {
11588 if *worktree_id != key.worktree_id {
11589 for server_map in servers.roots.values() {
11590 if server_map
11591 .values()
11592 .any(|(node, _)| node.id() == Some(server_id))
11593 {
11594 worktrees_using_server.push(*worktree_id);
11595 }
11596 }
11597 }
11598 }
11599 }
11600
11601 let mut buffer_paths_registered = Vec::new();
11602 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11603 let mut lsp_adapters = HashMap::default();
11604 for buffer_handle in buffer_store.buffers() {
11605 let buffer = buffer_handle.read(cx);
11606 let file = match File::from_dyn(buffer.file()) {
11607 Some(file) => file,
11608 None => continue,
11609 };
11610 let language = match buffer.language() {
11611 Some(language) => language,
11612 None => continue,
11613 };
11614
11615 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11616 || !lsp_adapters
11617 .entry(language.name())
11618 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11619 .iter()
11620 .any(|a| a.name == key.name)
11621 {
11622 continue;
11623 }
11624 // didOpen
11625 let file = match file.as_local() {
11626 Some(file) => file,
11627 None => continue,
11628 };
11629
11630 let local = self.as_local_mut().unwrap();
11631
11632 let buffer_id = buffer.remote_id();
11633 if local.registered_buffers.contains_key(&buffer_id) {
11634 let abs_path = file.abs_path(cx);
11635 let uri = match lsp::Uri::from_file_path(&abs_path) {
11636 Ok(uri) => uri,
11637 Err(()) => {
11638 log::error!("failed to convert path to URI: {:?}", abs_path);
11639 continue;
11640 }
11641 };
11642
11643 let versions = local
11644 .buffer_snapshots
11645 .entry(buffer_id)
11646 .or_default()
11647 .entry(server_id)
11648 .and_modify(|_| {
11649 assert!(
11650 false,
11651 "There should not be an existing snapshot for a newly inserted buffer"
11652 )
11653 })
11654 .or_insert_with(|| {
11655 vec![LspBufferSnapshot {
11656 version: 0,
11657 snapshot: buffer.text_snapshot(),
11658 }]
11659 });
11660
11661 let snapshot = versions.last().unwrap();
11662 let version = snapshot.version;
11663 let initial_snapshot = &snapshot.snapshot;
11664 language_server.register_buffer(
11665 uri,
11666 adapter.language_id(&language.name()),
11667 version,
11668 initial_snapshot.text(),
11669 );
11670 buffer_paths_registered.push((buffer_id, abs_path));
11671 local
11672 .buffers_opened_in_servers
11673 .entry(buffer_id)
11674 .or_default()
11675 .insert(server_id);
11676 }
11677 buffer_handle.update(cx, |buffer, cx| {
11678 buffer.set_completion_triggers(
11679 server_id,
11680 language_server
11681 .capabilities()
11682 .completion_provider
11683 .as_ref()
11684 .and_then(|provider| {
11685 provider
11686 .trigger_characters
11687 .as_ref()
11688 .map(|characters| characters.iter().cloned().collect())
11689 })
11690 .unwrap_or_default(),
11691 cx,
11692 )
11693 });
11694 }
11695 });
11696
11697 for (buffer_id, abs_path) in buffer_paths_registered {
11698 cx.emit(LspStoreEvent::LanguageServerUpdate {
11699 language_server_id: server_id,
11700 name: Some(adapter.name()),
11701 message: proto::update_language_server::Variant::RegisteredForBuffer(
11702 proto::RegisteredForBuffer {
11703 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11704 buffer_id: buffer_id.to_proto(),
11705 },
11706 ),
11707 });
11708 }
11709
11710 cx.notify();
11711 }
11712
11713 pub fn language_servers_running_disk_based_diagnostics(
11714 &self,
11715 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11716 self.language_server_statuses
11717 .iter()
11718 .filter_map(|(id, status)| {
11719 if status.has_pending_diagnostic_updates {
11720 Some(*id)
11721 } else {
11722 None
11723 }
11724 })
11725 }
11726
11727 pub(crate) fn cancel_language_server_work_for_buffers(
11728 &mut self,
11729 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11730 cx: &mut Context<Self>,
11731 ) {
11732 if let Some((client, project_id)) = self.upstream_client() {
11733 let request = client.request(proto::CancelLanguageServerWork {
11734 project_id,
11735 work: Some(proto::cancel_language_server_work::Work::Buffers(
11736 proto::cancel_language_server_work::Buffers {
11737 buffer_ids: buffers
11738 .into_iter()
11739 .map(|b| b.read(cx).remote_id().to_proto())
11740 .collect(),
11741 },
11742 )),
11743 });
11744 cx.background_spawn(request).detach_and_log_err(cx);
11745 } else if let Some(local) = self.as_local() {
11746 let servers = buffers
11747 .into_iter()
11748 .flat_map(|buffer| {
11749 buffer.update(cx, |buffer, cx| {
11750 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11751 })
11752 })
11753 .collect::<HashSet<_>>();
11754 for server_id in servers {
11755 self.cancel_language_server_work(server_id, None, cx);
11756 }
11757 }
11758 }
11759
11760 pub(crate) fn cancel_language_server_work(
11761 &mut self,
11762 server_id: LanguageServerId,
11763 token_to_cancel: Option<ProgressToken>,
11764 cx: &mut Context<Self>,
11765 ) {
11766 if let Some(local) = self.as_local() {
11767 let status = self.language_server_statuses.get(&server_id);
11768 let server = local.language_servers.get(&server_id);
11769 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11770 {
11771 for (token, progress) in &status.pending_work {
11772 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11773 && token != token_to_cancel
11774 {
11775 continue;
11776 }
11777 if progress.is_cancellable {
11778 server
11779 .notify::<lsp::notification::WorkDoneProgressCancel>(
11780 WorkDoneProgressCancelParams {
11781 token: token.to_lsp(),
11782 },
11783 )
11784 .ok();
11785 }
11786 }
11787 }
11788 } else if let Some((client, project_id)) = self.upstream_client() {
11789 let request = client.request(proto::CancelLanguageServerWork {
11790 project_id,
11791 work: Some(
11792 proto::cancel_language_server_work::Work::LanguageServerWork(
11793 proto::cancel_language_server_work::LanguageServerWork {
11794 language_server_id: server_id.to_proto(),
11795 token: token_to_cancel.map(|token| token.to_proto()),
11796 },
11797 ),
11798 ),
11799 });
11800 cx.background_spawn(request).detach_and_log_err(cx);
11801 }
11802 }
11803
11804 fn register_supplementary_language_server(
11805 &mut self,
11806 id: LanguageServerId,
11807 name: LanguageServerName,
11808 server: Arc<LanguageServer>,
11809 cx: &mut Context<Self>,
11810 ) {
11811 if let Some(local) = self.as_local_mut() {
11812 local
11813 .supplementary_language_servers
11814 .insert(id, (name.clone(), server));
11815 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11816 }
11817 }
11818
11819 fn unregister_supplementary_language_server(
11820 &mut self,
11821 id: LanguageServerId,
11822 cx: &mut Context<Self>,
11823 ) {
11824 if let Some(local) = self.as_local_mut() {
11825 local.supplementary_language_servers.remove(&id);
11826 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11827 }
11828 }
11829
11830 pub(crate) fn supplementary_language_servers(
11831 &self,
11832 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11833 self.as_local().into_iter().flat_map(|local| {
11834 local
11835 .supplementary_language_servers
11836 .iter()
11837 .map(|(id, (name, _))| (*id, name.clone()))
11838 })
11839 }
11840
11841 pub fn language_server_adapter_for_id(
11842 &self,
11843 id: LanguageServerId,
11844 ) -> Option<Arc<CachedLspAdapter>> {
11845 self.as_local()
11846 .and_then(|local| local.language_servers.get(&id))
11847 .and_then(|language_server_state| match language_server_state {
11848 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11849 _ => None,
11850 })
11851 }
11852
11853 pub(super) fn update_local_worktree_language_servers(
11854 &mut self,
11855 worktree_handle: &Entity<Worktree>,
11856 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11857 cx: &mut Context<Self>,
11858 ) {
11859 if changes.is_empty() {
11860 return;
11861 }
11862
11863 let Some(local) = self.as_local() else { return };
11864
11865 local.prettier_store.update(cx, |prettier_store, cx| {
11866 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11867 });
11868
11869 let worktree_id = worktree_handle.read(cx).id();
11870 let mut language_server_ids = local
11871 .language_server_ids
11872 .iter()
11873 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11874 .collect::<Vec<_>>();
11875 language_server_ids.sort();
11876 language_server_ids.dedup();
11877
11878 // let abs_path = worktree_handle.read(cx).abs_path();
11879 for server_id in &language_server_ids {
11880 if let Some(LanguageServerState::Running { server, .. }) =
11881 local.language_servers.get(server_id)
11882 && let Some(watched_paths) = local
11883 .language_server_watched_paths
11884 .get(server_id)
11885 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11886 {
11887 let params = lsp::DidChangeWatchedFilesParams {
11888 changes: changes
11889 .iter()
11890 .filter_map(|(path, _, change)| {
11891 if !watched_paths.is_match(path.as_std_path()) {
11892 return None;
11893 }
11894 let typ = match change {
11895 PathChange::Loaded => return None,
11896 PathChange::Added => lsp::FileChangeType::CREATED,
11897 PathChange::Removed => lsp::FileChangeType::DELETED,
11898 PathChange::Updated => lsp::FileChangeType::CHANGED,
11899 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11900 };
11901 let uri = lsp::Uri::from_file_path(
11902 worktree_handle.read(cx).absolutize(&path),
11903 )
11904 .ok()?;
11905 Some(lsp::FileEvent { uri, typ })
11906 })
11907 .collect(),
11908 };
11909 if !params.changes.is_empty() {
11910 server
11911 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11912 .ok();
11913 }
11914 }
11915 }
11916 for (path, _, _) in changes {
11917 if let Some(file_name) = path.file_name()
11918 && local.watched_manifest_filenames.contains(file_name)
11919 {
11920 self.request_workspace_config_refresh();
11921 break;
11922 }
11923 }
11924 }
11925
11926 pub fn wait_for_remote_buffer(
11927 &mut self,
11928 id: BufferId,
11929 cx: &mut Context<Self>,
11930 ) -> Task<Result<Entity<Buffer>>> {
11931 self.buffer_store.update(cx, |buffer_store, cx| {
11932 buffer_store.wait_for_remote_buffer(id, cx)
11933 })
11934 }
11935
11936 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11937 let mut result = proto::Symbol {
11938 language_server_name: symbol.language_server_name.0.to_string(),
11939 source_worktree_id: symbol.source_worktree_id.to_proto(),
11940 language_server_id: symbol.source_language_server_id.to_proto(),
11941 name: symbol.name.clone(),
11942 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11943 start: Some(proto::PointUtf16 {
11944 row: symbol.range.start.0.row,
11945 column: symbol.range.start.0.column,
11946 }),
11947 end: Some(proto::PointUtf16 {
11948 row: symbol.range.end.0.row,
11949 column: symbol.range.end.0.column,
11950 }),
11951 worktree_id: Default::default(),
11952 path: Default::default(),
11953 signature: Default::default(),
11954 container_name: symbol.container_name.clone(),
11955 };
11956 match &symbol.path {
11957 SymbolLocation::InProject(path) => {
11958 result.worktree_id = path.worktree_id.to_proto();
11959 result.path = path.path.to_proto();
11960 }
11961 SymbolLocation::OutsideProject {
11962 abs_path,
11963 signature,
11964 } => {
11965 result.path = abs_path.to_string_lossy().into_owned();
11966 result.signature = signature.to_vec();
11967 }
11968 }
11969 result
11970 }
11971
11972 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11973 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11974 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11975 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11976
11977 let path = if serialized_symbol.signature.is_empty() {
11978 SymbolLocation::InProject(ProjectPath {
11979 worktree_id,
11980 path: RelPath::from_proto(&serialized_symbol.path)
11981 .context("invalid symbol path")?,
11982 })
11983 } else {
11984 SymbolLocation::OutsideProject {
11985 abs_path: Path::new(&serialized_symbol.path).into(),
11986 signature: serialized_symbol
11987 .signature
11988 .try_into()
11989 .map_err(|_| anyhow!("invalid signature"))?,
11990 }
11991 };
11992
11993 let start = serialized_symbol.start.context("invalid start")?;
11994 let end = serialized_symbol.end.context("invalid end")?;
11995 Ok(CoreSymbol {
11996 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11997 source_worktree_id,
11998 source_language_server_id: LanguageServerId::from_proto(
11999 serialized_symbol.language_server_id,
12000 ),
12001 path,
12002 name: serialized_symbol.name,
12003 range: Unclipped(PointUtf16::new(start.row, start.column))
12004 ..Unclipped(PointUtf16::new(end.row, end.column)),
12005 kind,
12006 container_name: serialized_symbol.container_name,
12007 })
12008 }
12009
12010 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12011 let mut serialized_completion = proto::Completion {
12012 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12013 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12014 new_text: completion.new_text.clone(),
12015 ..proto::Completion::default()
12016 };
12017 match &completion.source {
12018 CompletionSource::Lsp {
12019 insert_range,
12020 server_id,
12021 lsp_completion,
12022 lsp_defaults,
12023 resolved,
12024 } => {
12025 let (old_insert_start, old_insert_end) = insert_range
12026 .as_ref()
12027 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12028 .unzip();
12029
12030 serialized_completion.old_insert_start = old_insert_start;
12031 serialized_completion.old_insert_end = old_insert_end;
12032 serialized_completion.source = proto::completion::Source::Lsp as i32;
12033 serialized_completion.server_id = server_id.0 as u64;
12034 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12035 serialized_completion.lsp_defaults = lsp_defaults
12036 .as_deref()
12037 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12038 serialized_completion.resolved = *resolved;
12039 }
12040 CompletionSource::BufferWord {
12041 word_range,
12042 resolved,
12043 } => {
12044 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12045 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12046 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12047 serialized_completion.resolved = *resolved;
12048 }
12049 CompletionSource::Custom => {
12050 serialized_completion.source = proto::completion::Source::Custom as i32;
12051 serialized_completion.resolved = true;
12052 }
12053 CompletionSource::Dap { sort_text } => {
12054 serialized_completion.source = proto::completion::Source::Dap as i32;
12055 serialized_completion.sort_text = Some(sort_text.clone());
12056 }
12057 }
12058
12059 serialized_completion
12060 }
12061
12062 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12063 let old_replace_start = completion
12064 .old_replace_start
12065 .and_then(deserialize_anchor)
12066 .context("invalid old start")?;
12067 let old_replace_end = completion
12068 .old_replace_end
12069 .and_then(deserialize_anchor)
12070 .context("invalid old end")?;
12071 let insert_range = {
12072 match completion.old_insert_start.zip(completion.old_insert_end) {
12073 Some((start, end)) => {
12074 let start = deserialize_anchor(start).context("invalid insert old start")?;
12075 let end = deserialize_anchor(end).context("invalid insert old end")?;
12076 Some(start..end)
12077 }
12078 None => None,
12079 }
12080 };
12081 Ok(CoreCompletion {
12082 replace_range: old_replace_start..old_replace_end,
12083 new_text: completion.new_text,
12084 source: match proto::completion::Source::from_i32(completion.source) {
12085 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12086 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12087 insert_range,
12088 server_id: LanguageServerId::from_proto(completion.server_id),
12089 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12090 lsp_defaults: completion
12091 .lsp_defaults
12092 .as_deref()
12093 .map(serde_json::from_slice)
12094 .transpose()?,
12095 resolved: completion.resolved,
12096 },
12097 Some(proto::completion::Source::BufferWord) => {
12098 let word_range = completion
12099 .buffer_word_start
12100 .and_then(deserialize_anchor)
12101 .context("invalid buffer word start")?
12102 ..completion
12103 .buffer_word_end
12104 .and_then(deserialize_anchor)
12105 .context("invalid buffer word end")?;
12106 CompletionSource::BufferWord {
12107 word_range,
12108 resolved: completion.resolved,
12109 }
12110 }
12111 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12112 sort_text: completion
12113 .sort_text
12114 .context("expected sort text to exist")?,
12115 },
12116 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12117 },
12118 })
12119 }
12120
12121 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12122 let (kind, lsp_action) = match &action.lsp_action {
12123 LspAction::Action(code_action) => (
12124 proto::code_action::Kind::Action as i32,
12125 serde_json::to_vec(code_action).unwrap(),
12126 ),
12127 LspAction::Command(command) => (
12128 proto::code_action::Kind::Command as i32,
12129 serde_json::to_vec(command).unwrap(),
12130 ),
12131 LspAction::CodeLens(code_lens) => (
12132 proto::code_action::Kind::CodeLens as i32,
12133 serde_json::to_vec(code_lens).unwrap(),
12134 ),
12135 };
12136
12137 proto::CodeAction {
12138 server_id: action.server_id.0 as u64,
12139 start: Some(serialize_anchor(&action.range.start)),
12140 end: Some(serialize_anchor(&action.range.end)),
12141 lsp_action,
12142 kind,
12143 resolved: action.resolved,
12144 }
12145 }
12146
12147 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12148 let start = action
12149 .start
12150 .and_then(deserialize_anchor)
12151 .context("invalid start")?;
12152 let end = action
12153 .end
12154 .and_then(deserialize_anchor)
12155 .context("invalid end")?;
12156 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12157 Some(proto::code_action::Kind::Action) => {
12158 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12159 }
12160 Some(proto::code_action::Kind::Command) => {
12161 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12162 }
12163 Some(proto::code_action::Kind::CodeLens) => {
12164 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12165 }
12166 None => anyhow::bail!("Unknown action kind {}", action.kind),
12167 };
12168 Ok(CodeAction {
12169 server_id: LanguageServerId(action.server_id as usize),
12170 range: start..end,
12171 resolved: action.resolved,
12172 lsp_action,
12173 })
12174 }
12175
12176 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12177 match &formatting_result {
12178 Ok(_) => self.last_formatting_failure = None,
12179 Err(error) => {
12180 let error_string = format!("{error:#}");
12181 log::error!("Formatting failed: {error_string}");
12182 self.last_formatting_failure
12183 .replace(error_string.lines().join(" "));
12184 }
12185 }
12186 }
12187
12188 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12189 self.lsp_server_capabilities.remove(&for_server);
12190 self.semantic_token_config.remove_server_data(for_server);
12191 for lsp_data in self.lsp_data.values_mut() {
12192 lsp_data.remove_server_data(for_server);
12193 }
12194 if let Some(local) = self.as_local_mut() {
12195 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12196 local
12197 .workspace_pull_diagnostics_result_ids
12198 .remove(&for_server);
12199 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12200 buffer_servers.remove(&for_server);
12201 }
12202 }
12203 }
12204
12205 pub fn result_id_for_buffer_pull(
12206 &self,
12207 server_id: LanguageServerId,
12208 buffer_id: BufferId,
12209 registration_id: &Option<SharedString>,
12210 cx: &App,
12211 ) -> Option<SharedString> {
12212 let abs_path = self
12213 .buffer_store
12214 .read(cx)
12215 .get(buffer_id)
12216 .and_then(|b| File::from_dyn(b.read(cx).file()))
12217 .map(|f| f.abs_path(cx))?;
12218 self.as_local()?
12219 .buffer_pull_diagnostics_result_ids
12220 .get(&server_id)?
12221 .get(registration_id)?
12222 .get(&abs_path)?
12223 .clone()
12224 }
12225
12226 /// Gets all result_ids for a workspace diagnostics pull request.
12227 /// 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.
12228 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12229 pub fn result_ids_for_workspace_refresh(
12230 &self,
12231 server_id: LanguageServerId,
12232 registration_id: &Option<SharedString>,
12233 ) -> HashMap<PathBuf, SharedString> {
12234 let Some(local) = self.as_local() else {
12235 return HashMap::default();
12236 };
12237 local
12238 .workspace_pull_diagnostics_result_ids
12239 .get(&server_id)
12240 .into_iter()
12241 .filter_map(|diagnostics| diagnostics.get(registration_id))
12242 .flatten()
12243 .filter_map(|(abs_path, result_id)| {
12244 let result_id = local
12245 .buffer_pull_diagnostics_result_ids
12246 .get(&server_id)
12247 .and_then(|buffer_ids_result_ids| {
12248 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12249 })
12250 .cloned()
12251 .flatten()
12252 .or_else(|| result_id.clone())?;
12253 Some((abs_path.clone(), result_id))
12254 })
12255 .collect()
12256 }
12257
12258 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12259 if let Some(LanguageServerState::Running {
12260 workspace_diagnostics_refresh_tasks,
12261 ..
12262 }) = self
12263 .as_local_mut()
12264 .and_then(|local| local.language_servers.get_mut(&server_id))
12265 {
12266 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12267 diagnostics.refresh_tx.try_send(()).ok();
12268 }
12269 }
12270 }
12271
12272 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12273 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12274 /// which requires refreshing both workspace and document diagnostics.
12275 pub fn pull_document_diagnostics_for_server(
12276 &mut self,
12277 server_id: LanguageServerId,
12278 source_buffer_id: Option<BufferId>,
12279 cx: &mut Context<Self>,
12280 ) -> Shared<Task<()>> {
12281 let Some(local) = self.as_local_mut() else {
12282 return Task::ready(()).shared();
12283 };
12284 let mut buffers_to_refresh = HashSet::default();
12285 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12286 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12287 buffers_to_refresh.insert(*buffer_id);
12288 }
12289 }
12290
12291 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12292 }
12293
12294 pub fn pull_document_diagnostics_for_buffer_edit(
12295 &mut self,
12296 buffer_id: BufferId,
12297 cx: &mut Context<Self>,
12298 ) {
12299 let Some(local) = self.as_local_mut() else {
12300 return;
12301 };
12302 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12303 else {
12304 return;
12305 };
12306 for server_id in languages_servers {
12307 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12308 }
12309 }
12310
12311 fn apply_workspace_diagnostic_report(
12312 &mut self,
12313 server_id: LanguageServerId,
12314 report: lsp::WorkspaceDiagnosticReportResult,
12315 registration_id: Option<SharedString>,
12316 cx: &mut Context<Self>,
12317 ) {
12318 let mut workspace_diagnostics =
12319 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12320 report,
12321 server_id,
12322 registration_id,
12323 );
12324 workspace_diagnostics.retain(|d| match &d.diagnostics {
12325 LspPullDiagnostics::Response {
12326 server_id,
12327 registration_id,
12328 ..
12329 } => self.diagnostic_registration_exists(*server_id, registration_id),
12330 LspPullDiagnostics::Default => false,
12331 });
12332 let mut unchanged_buffers = HashMap::default();
12333 let workspace_diagnostics_updates = workspace_diagnostics
12334 .into_iter()
12335 .filter_map(
12336 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12337 LspPullDiagnostics::Response {
12338 server_id,
12339 uri,
12340 diagnostics,
12341 registration_id,
12342 } => Some((
12343 server_id,
12344 uri,
12345 diagnostics,
12346 workspace_diagnostics.version,
12347 registration_id,
12348 )),
12349 LspPullDiagnostics::Default => None,
12350 },
12351 )
12352 .fold(
12353 HashMap::default(),
12354 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12355 let (result_id, diagnostics) = match diagnostics {
12356 PulledDiagnostics::Unchanged { result_id } => {
12357 unchanged_buffers
12358 .entry(new_registration_id.clone())
12359 .or_insert_with(HashSet::default)
12360 .insert(uri.clone());
12361 (Some(result_id), Vec::new())
12362 }
12363 PulledDiagnostics::Changed {
12364 result_id,
12365 diagnostics,
12366 } => (result_id, diagnostics),
12367 };
12368 let disk_based_sources = Cow::Owned(
12369 self.language_server_adapter_for_id(server_id)
12370 .as_ref()
12371 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12372 .unwrap_or(&[])
12373 .to_vec(),
12374 );
12375
12376 let Some(abs_path) = uri.to_file_path().ok() else {
12377 return acc;
12378 };
12379 let Some((worktree, relative_path)) =
12380 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12381 else {
12382 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12383 return acc;
12384 };
12385 let worktree_id = worktree.read(cx).id();
12386 let project_path = ProjectPath {
12387 worktree_id,
12388 path: relative_path,
12389 };
12390 if let Some(local_lsp_store) = self.as_local_mut() {
12391 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12392 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12393 }
12394 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12395 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12396 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12397 acc.entry(server_id)
12398 .or_insert_with(HashMap::default)
12399 .entry(new_registration_id.clone())
12400 .or_insert_with(Vec::new)
12401 .push(DocumentDiagnosticsUpdate {
12402 server_id,
12403 diagnostics: lsp::PublishDiagnosticsParams {
12404 uri,
12405 diagnostics,
12406 version,
12407 },
12408 result_id: result_id.map(SharedString::new),
12409 disk_based_sources,
12410 registration_id: new_registration_id,
12411 });
12412 }
12413 acc
12414 },
12415 );
12416
12417 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12418 for (registration_id, diagnostic_updates) in diagnostic_updates {
12419 self.merge_lsp_diagnostics(
12420 DiagnosticSourceKind::Pulled,
12421 diagnostic_updates,
12422 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12423 DiagnosticSourceKind::Pulled => {
12424 old_diagnostic.registration_id != registration_id
12425 || unchanged_buffers
12426 .get(&old_diagnostic.registration_id)
12427 .is_some_and(|unchanged_buffers| {
12428 unchanged_buffers.contains(&document_uri)
12429 })
12430 }
12431 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12432 },
12433 cx,
12434 )
12435 .log_err();
12436 }
12437 }
12438 }
12439
12440 fn register_server_capabilities(
12441 &mut self,
12442 server_id: LanguageServerId,
12443 params: lsp::RegistrationParams,
12444 cx: &mut Context<Self>,
12445 ) -> anyhow::Result<()> {
12446 let server = self
12447 .language_server_for_id(server_id)
12448 .with_context(|| format!("no server {server_id} found"))?;
12449 for reg in params.registrations {
12450 match reg.method.as_str() {
12451 "workspace/didChangeWatchedFiles" => {
12452 if let Some(options) = reg.register_options {
12453 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12454 let caps = serde_json::from_value(options)?;
12455 local_lsp_store
12456 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12457 true
12458 } else {
12459 false
12460 };
12461 if notify {
12462 notify_server_capabilities_updated(&server, cx);
12463 }
12464 }
12465 }
12466 "workspace/didChangeConfiguration" => {
12467 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12468 }
12469 "workspace/didChangeWorkspaceFolders" => {
12470 // In this case register options is an empty object, we can ignore it
12471 let caps = lsp::WorkspaceFoldersServerCapabilities {
12472 supported: Some(true),
12473 change_notifications: Some(OneOf::Right(reg.id)),
12474 };
12475 server.update_capabilities(|capabilities| {
12476 capabilities
12477 .workspace
12478 .get_or_insert_default()
12479 .workspace_folders = Some(caps);
12480 });
12481 notify_server_capabilities_updated(&server, cx);
12482 }
12483 "workspace/symbol" => {
12484 let options = parse_register_capabilities(reg)?;
12485 server.update_capabilities(|capabilities| {
12486 capabilities.workspace_symbol_provider = Some(options);
12487 });
12488 notify_server_capabilities_updated(&server, cx);
12489 }
12490 "workspace/fileOperations" => {
12491 if let Some(options) = reg.register_options {
12492 let caps = serde_json::from_value(options)?;
12493 server.update_capabilities(|capabilities| {
12494 capabilities
12495 .workspace
12496 .get_or_insert_default()
12497 .file_operations = Some(caps);
12498 });
12499 notify_server_capabilities_updated(&server, cx);
12500 }
12501 }
12502 "workspace/executeCommand" => {
12503 if let Some(options) = reg.register_options {
12504 let options = serde_json::from_value(options)?;
12505 server.update_capabilities(|capabilities| {
12506 capabilities.execute_command_provider = Some(options);
12507 });
12508 notify_server_capabilities_updated(&server, cx);
12509 }
12510 }
12511 "textDocument/rangeFormatting" => {
12512 let options = parse_register_capabilities(reg)?;
12513 server.update_capabilities(|capabilities| {
12514 capabilities.document_range_formatting_provider = Some(options);
12515 });
12516 notify_server_capabilities_updated(&server, cx);
12517 }
12518 "textDocument/onTypeFormatting" => {
12519 if let Some(options) = reg
12520 .register_options
12521 .map(serde_json::from_value)
12522 .transpose()?
12523 {
12524 server.update_capabilities(|capabilities| {
12525 capabilities.document_on_type_formatting_provider = Some(options);
12526 });
12527 notify_server_capabilities_updated(&server, cx);
12528 }
12529 }
12530 "textDocument/formatting" => {
12531 let options = parse_register_capabilities(reg)?;
12532 server.update_capabilities(|capabilities| {
12533 capabilities.document_formatting_provider = Some(options);
12534 });
12535 notify_server_capabilities_updated(&server, cx);
12536 }
12537 "textDocument/rename" => {
12538 let options = parse_register_capabilities(reg)?;
12539 server.update_capabilities(|capabilities| {
12540 capabilities.rename_provider = Some(options);
12541 });
12542 notify_server_capabilities_updated(&server, cx);
12543 }
12544 "textDocument/inlayHint" => {
12545 let options = parse_register_capabilities(reg)?;
12546 server.update_capabilities(|capabilities| {
12547 capabilities.inlay_hint_provider = Some(options);
12548 });
12549 notify_server_capabilities_updated(&server, cx);
12550 }
12551 "textDocument/documentSymbol" => {
12552 let options = parse_register_capabilities(reg)?;
12553 server.update_capabilities(|capabilities| {
12554 capabilities.document_symbol_provider = Some(options);
12555 });
12556 notify_server_capabilities_updated(&server, cx);
12557 }
12558 "textDocument/codeAction" => {
12559 let options = parse_register_capabilities(reg)?;
12560 let provider = match options {
12561 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12562 OneOf::Right(caps) => caps,
12563 };
12564 server.update_capabilities(|capabilities| {
12565 capabilities.code_action_provider = Some(provider);
12566 });
12567 notify_server_capabilities_updated(&server, cx);
12568 }
12569 "textDocument/definition" => {
12570 let options = parse_register_capabilities(reg)?;
12571 server.update_capabilities(|capabilities| {
12572 capabilities.definition_provider = Some(options);
12573 });
12574 notify_server_capabilities_updated(&server, cx);
12575 }
12576 "textDocument/completion" => {
12577 if let Some(caps) = reg
12578 .register_options
12579 .map(serde_json::from_value::<CompletionOptions>)
12580 .transpose()?
12581 {
12582 server.update_capabilities(|capabilities| {
12583 capabilities.completion_provider = Some(caps.clone());
12584 });
12585
12586 if let Some(local) = self.as_local() {
12587 let mut buffers_with_language_server = Vec::new();
12588 for handle in self.buffer_store.read(cx).buffers() {
12589 let buffer_id = handle.read(cx).remote_id();
12590 if local
12591 .buffers_opened_in_servers
12592 .get(&buffer_id)
12593 .filter(|s| s.contains(&server_id))
12594 .is_some()
12595 {
12596 buffers_with_language_server.push(handle);
12597 }
12598 }
12599 let triggers = caps
12600 .trigger_characters
12601 .unwrap_or_default()
12602 .into_iter()
12603 .collect::<BTreeSet<_>>();
12604 for handle in buffers_with_language_server {
12605 let triggers = triggers.clone();
12606 let _ = handle.update(cx, move |buffer, cx| {
12607 buffer.set_completion_triggers(server_id, triggers, cx);
12608 });
12609 }
12610 }
12611 notify_server_capabilities_updated(&server, cx);
12612 }
12613 }
12614 "textDocument/hover" => {
12615 let options = parse_register_capabilities(reg)?;
12616 let provider = match options {
12617 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12618 OneOf::Right(caps) => caps,
12619 };
12620 server.update_capabilities(|capabilities| {
12621 capabilities.hover_provider = Some(provider);
12622 });
12623 notify_server_capabilities_updated(&server, cx);
12624 }
12625 "textDocument/signatureHelp" => {
12626 if let Some(caps) = reg
12627 .register_options
12628 .map(serde_json::from_value)
12629 .transpose()?
12630 {
12631 server.update_capabilities(|capabilities| {
12632 capabilities.signature_help_provider = Some(caps);
12633 });
12634 notify_server_capabilities_updated(&server, cx);
12635 }
12636 }
12637 "textDocument/didChange" => {
12638 if let Some(sync_kind) = reg
12639 .register_options
12640 .and_then(|opts| opts.get("syncKind").cloned())
12641 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12642 .transpose()?
12643 {
12644 server.update_capabilities(|capabilities| {
12645 let mut sync_options =
12646 Self::take_text_document_sync_options(capabilities);
12647 sync_options.change = Some(sync_kind);
12648 capabilities.text_document_sync =
12649 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12650 });
12651 notify_server_capabilities_updated(&server, cx);
12652 }
12653 }
12654 "textDocument/didSave" => {
12655 if let Some(include_text) = reg
12656 .register_options
12657 .map(|opts| {
12658 let transpose = opts
12659 .get("includeText")
12660 .cloned()
12661 .map(serde_json::from_value::<Option<bool>>)
12662 .transpose();
12663 match transpose {
12664 Ok(value) => Ok(value.flatten()),
12665 Err(e) => Err(e),
12666 }
12667 })
12668 .transpose()?
12669 {
12670 server.update_capabilities(|capabilities| {
12671 let mut sync_options =
12672 Self::take_text_document_sync_options(capabilities);
12673 sync_options.save =
12674 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12675 include_text,
12676 }));
12677 capabilities.text_document_sync =
12678 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12679 });
12680 notify_server_capabilities_updated(&server, cx);
12681 }
12682 }
12683 "textDocument/codeLens" => {
12684 if let Some(caps) = reg
12685 .register_options
12686 .map(serde_json::from_value)
12687 .transpose()?
12688 {
12689 server.update_capabilities(|capabilities| {
12690 capabilities.code_lens_provider = Some(caps);
12691 });
12692 notify_server_capabilities_updated(&server, cx);
12693 }
12694 }
12695 "textDocument/diagnostic" => {
12696 if let Some(caps) = reg
12697 .register_options
12698 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12699 .transpose()?
12700 {
12701 let local = self
12702 .as_local_mut()
12703 .context("Expected LSP Store to be local")?;
12704 let state = local
12705 .language_servers
12706 .get_mut(&server_id)
12707 .context("Could not obtain Language Servers state")?;
12708 local
12709 .language_server_dynamic_registrations
12710 .entry(server_id)
12711 .or_default()
12712 .diagnostics
12713 .insert(Some(reg.id.clone()), caps.clone());
12714
12715 let supports_workspace_diagnostics =
12716 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12717 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12718 diagnostic_options.workspace_diagnostics
12719 }
12720 DiagnosticServerCapabilities::RegistrationOptions(
12721 diagnostic_registration_options,
12722 ) => {
12723 diagnostic_registration_options
12724 .diagnostic_options
12725 .workspace_diagnostics
12726 }
12727 };
12728
12729 if supports_workspace_diagnostics(&caps) {
12730 if let LanguageServerState::Running {
12731 workspace_diagnostics_refresh_tasks,
12732 ..
12733 } = state
12734 && let Some(task) = lsp_workspace_diagnostics_refresh(
12735 Some(reg.id.clone()),
12736 caps.clone(),
12737 server.clone(),
12738 cx,
12739 )
12740 {
12741 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12742 }
12743 }
12744
12745 server.update_capabilities(|capabilities| {
12746 capabilities.diagnostic_provider = Some(caps);
12747 });
12748
12749 notify_server_capabilities_updated(&server, cx);
12750
12751 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12752 }
12753 }
12754 "textDocument/documentColor" => {
12755 let options = parse_register_capabilities(reg)?;
12756 let provider = match options {
12757 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12758 OneOf::Right(caps) => caps,
12759 };
12760 server.update_capabilities(|capabilities| {
12761 capabilities.color_provider = Some(provider);
12762 });
12763 notify_server_capabilities_updated(&server, cx);
12764 }
12765 "textDocument/foldingRange" => {
12766 let options = parse_register_capabilities(reg)?;
12767 let provider = match options {
12768 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12769 OneOf::Right(caps) => caps,
12770 };
12771 server.update_capabilities(|capabilities| {
12772 capabilities.folding_range_provider = Some(provider);
12773 });
12774 notify_server_capabilities_updated(&server, cx);
12775 }
12776 _ => log::warn!("unhandled capability registration: {reg:?}"),
12777 }
12778 }
12779
12780 Ok(())
12781 }
12782
12783 fn unregister_server_capabilities(
12784 &mut self,
12785 server_id: LanguageServerId,
12786 params: lsp::UnregistrationParams,
12787 cx: &mut Context<Self>,
12788 ) -> anyhow::Result<()> {
12789 let server = self
12790 .language_server_for_id(server_id)
12791 .with_context(|| format!("no server {server_id} found"))?;
12792 for unreg in params.unregisterations.iter() {
12793 match unreg.method.as_str() {
12794 "workspace/didChangeWatchedFiles" => {
12795 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12796 local_lsp_store
12797 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12798 true
12799 } else {
12800 false
12801 };
12802 if notify {
12803 notify_server_capabilities_updated(&server, cx);
12804 }
12805 }
12806 "workspace/didChangeConfiguration" => {
12807 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12808 }
12809 "workspace/didChangeWorkspaceFolders" => {
12810 server.update_capabilities(|capabilities| {
12811 capabilities
12812 .workspace
12813 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12814 workspace_folders: None,
12815 file_operations: None,
12816 })
12817 .workspace_folders = None;
12818 });
12819 notify_server_capabilities_updated(&server, cx);
12820 }
12821 "workspace/symbol" => {
12822 server.update_capabilities(|capabilities| {
12823 capabilities.workspace_symbol_provider = None
12824 });
12825 notify_server_capabilities_updated(&server, cx);
12826 }
12827 "workspace/fileOperations" => {
12828 server.update_capabilities(|capabilities| {
12829 capabilities
12830 .workspace
12831 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12832 workspace_folders: None,
12833 file_operations: None,
12834 })
12835 .file_operations = None;
12836 });
12837 notify_server_capabilities_updated(&server, cx);
12838 }
12839 "workspace/executeCommand" => {
12840 server.update_capabilities(|capabilities| {
12841 capabilities.execute_command_provider = None;
12842 });
12843 notify_server_capabilities_updated(&server, cx);
12844 }
12845 "textDocument/rangeFormatting" => {
12846 server.update_capabilities(|capabilities| {
12847 capabilities.document_range_formatting_provider = None
12848 });
12849 notify_server_capabilities_updated(&server, cx);
12850 }
12851 "textDocument/onTypeFormatting" => {
12852 server.update_capabilities(|capabilities| {
12853 capabilities.document_on_type_formatting_provider = None;
12854 });
12855 notify_server_capabilities_updated(&server, cx);
12856 }
12857 "textDocument/formatting" => {
12858 server.update_capabilities(|capabilities| {
12859 capabilities.document_formatting_provider = None;
12860 });
12861 notify_server_capabilities_updated(&server, cx);
12862 }
12863 "textDocument/rename" => {
12864 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12865 notify_server_capabilities_updated(&server, cx);
12866 }
12867 "textDocument/codeAction" => {
12868 server.update_capabilities(|capabilities| {
12869 capabilities.code_action_provider = None;
12870 });
12871 notify_server_capabilities_updated(&server, cx);
12872 }
12873 "textDocument/definition" => {
12874 server.update_capabilities(|capabilities| {
12875 capabilities.definition_provider = None;
12876 });
12877 notify_server_capabilities_updated(&server, cx);
12878 }
12879 "textDocument/completion" => {
12880 server.update_capabilities(|capabilities| {
12881 capabilities.completion_provider = None;
12882 });
12883 notify_server_capabilities_updated(&server, cx);
12884 }
12885 "textDocument/hover" => {
12886 server.update_capabilities(|capabilities| {
12887 capabilities.hover_provider = None;
12888 });
12889 notify_server_capabilities_updated(&server, cx);
12890 }
12891 "textDocument/signatureHelp" => {
12892 server.update_capabilities(|capabilities| {
12893 capabilities.signature_help_provider = None;
12894 });
12895 notify_server_capabilities_updated(&server, cx);
12896 }
12897 "textDocument/didChange" => {
12898 server.update_capabilities(|capabilities| {
12899 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12900 sync_options.change = None;
12901 capabilities.text_document_sync =
12902 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12903 });
12904 notify_server_capabilities_updated(&server, cx);
12905 }
12906 "textDocument/didSave" => {
12907 server.update_capabilities(|capabilities| {
12908 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12909 sync_options.save = None;
12910 capabilities.text_document_sync =
12911 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12912 });
12913 notify_server_capabilities_updated(&server, cx);
12914 }
12915 "textDocument/codeLens" => {
12916 server.update_capabilities(|capabilities| {
12917 capabilities.code_lens_provider = None;
12918 });
12919 notify_server_capabilities_updated(&server, cx);
12920 }
12921 "textDocument/diagnostic" => {
12922 let local = self
12923 .as_local_mut()
12924 .context("Expected LSP Store to be local")?;
12925
12926 let state = local
12927 .language_servers
12928 .get_mut(&server_id)
12929 .context("Could not obtain Language Servers state")?;
12930 let registrations = local
12931 .language_server_dynamic_registrations
12932 .get_mut(&server_id)
12933 .with_context(|| {
12934 format!("Expected dynamic registration to exist for server {server_id}")
12935 })?;
12936 registrations.diagnostics
12937 .remove(&Some(unreg.id.clone()))
12938 .with_context(|| format!(
12939 "Attempted to unregister non-existent diagnostic registration with ID {}",
12940 unreg.id)
12941 )?;
12942 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12943
12944 if let LanguageServerState::Running {
12945 workspace_diagnostics_refresh_tasks,
12946 ..
12947 } = state
12948 {
12949 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12950 }
12951
12952 self.clear_unregistered_diagnostics(
12953 server_id,
12954 SharedString::from(unreg.id.clone()),
12955 cx,
12956 )?;
12957
12958 if removed_last_diagnostic_provider {
12959 server.update_capabilities(|capabilities| {
12960 debug_assert!(capabilities.diagnostic_provider.is_some());
12961 capabilities.diagnostic_provider = None;
12962 });
12963 }
12964
12965 notify_server_capabilities_updated(&server, cx);
12966 }
12967 "textDocument/documentColor" => {
12968 server.update_capabilities(|capabilities| {
12969 capabilities.color_provider = None;
12970 });
12971 notify_server_capabilities_updated(&server, cx);
12972 }
12973 "textDocument/foldingRange" => {
12974 server.update_capabilities(|capabilities| {
12975 capabilities.folding_range_provider = None;
12976 });
12977 notify_server_capabilities_updated(&server, cx);
12978 }
12979 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12980 }
12981 }
12982
12983 Ok(())
12984 }
12985
12986 fn clear_unregistered_diagnostics(
12987 &mut self,
12988 server_id: LanguageServerId,
12989 cleared_registration_id: SharedString,
12990 cx: &mut Context<Self>,
12991 ) -> anyhow::Result<()> {
12992 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12993
12994 self.buffer_store.update(cx, |buffer_store, cx| {
12995 for buffer_handle in buffer_store.buffers() {
12996 let buffer = buffer_handle.read(cx);
12997 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12998 let Some(abs_path) = abs_path else {
12999 continue;
13000 };
13001 affected_abs_paths.insert(abs_path);
13002 }
13003 });
13004
13005 let local = self.as_local().context("Expected LSP Store to be local")?;
13006 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13007 let Some(worktree) = self
13008 .worktree_store
13009 .read(cx)
13010 .worktree_for_id(*worktree_id, cx)
13011 else {
13012 continue;
13013 };
13014
13015 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13016 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13017 let has_matching_registration =
13018 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13019 entry.diagnostic.registration_id.as_ref()
13020 == Some(&cleared_registration_id)
13021 });
13022 if has_matching_registration {
13023 let abs_path = worktree.read(cx).absolutize(rel_path);
13024 affected_abs_paths.insert(abs_path);
13025 }
13026 }
13027 }
13028 }
13029
13030 if affected_abs_paths.is_empty() {
13031 return Ok(());
13032 }
13033
13034 // Send a fake diagnostic update which clears the state for the registration ID
13035 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13036 affected_abs_paths
13037 .into_iter()
13038 .map(|abs_path| DocumentDiagnosticsUpdate {
13039 diagnostics: DocumentDiagnostics {
13040 diagnostics: Vec::new(),
13041 document_abs_path: abs_path,
13042 version: None,
13043 },
13044 result_id: None,
13045 registration_id: Some(cleared_registration_id.clone()),
13046 server_id,
13047 disk_based_sources: Cow::Borrowed(&[]),
13048 })
13049 .collect();
13050
13051 let merge_registration_id = cleared_registration_id.clone();
13052 self.merge_diagnostic_entries(
13053 clears,
13054 move |_, diagnostic, _| {
13055 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13056 diagnostic.registration_id != Some(merge_registration_id.clone())
13057 } else {
13058 true
13059 }
13060 },
13061 cx,
13062 )?;
13063
13064 Ok(())
13065 }
13066
13067 async fn deduplicate_range_based_lsp_requests<T>(
13068 lsp_store: &Entity<Self>,
13069 server_id: Option<LanguageServerId>,
13070 lsp_request_id: LspRequestId,
13071 proto_request: &T::ProtoRequest,
13072 range: Range<Anchor>,
13073 cx: &mut AsyncApp,
13074 ) -> Result<()>
13075 where
13076 T: LspCommand,
13077 T::ProtoRequest: proto::LspRequestMessage,
13078 {
13079 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13080 let version = deserialize_version(proto_request.buffer_version());
13081 let buffer = lsp_store.update(cx, |this, cx| {
13082 this.buffer_store.read(cx).get_existing(buffer_id)
13083 })?;
13084 buffer
13085 .update(cx, |buffer, _| buffer.wait_for_version(version))
13086 .await?;
13087 lsp_store.update(cx, |lsp_store, cx| {
13088 let buffer_snapshot = buffer.read(cx).snapshot();
13089 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13090 let chunks_queried_for = lsp_data
13091 .inlay_hints
13092 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13093 .collect::<Vec<_>>();
13094 match chunks_queried_for.as_slice() {
13095 &[chunk] => {
13096 let key = LspKey {
13097 request_type: TypeId::of::<T>(),
13098 server_queried: server_id,
13099 };
13100 let previous_request = lsp_data
13101 .chunk_lsp_requests
13102 .entry(key)
13103 .or_default()
13104 .insert(chunk, lsp_request_id);
13105 if let Some((previous_request, running_requests)) =
13106 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13107 {
13108 running_requests.remove(&previous_request);
13109 }
13110 }
13111 _ambiguous_chunks => {
13112 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13113 // there, a buffer version-based check will be performed and outdated requests discarded.
13114 }
13115 }
13116 anyhow::Ok(())
13117 })?;
13118
13119 Ok(())
13120 }
13121
13122 async fn query_lsp_locally<T>(
13123 lsp_store: Entity<Self>,
13124 for_server_id: Option<LanguageServerId>,
13125 sender_id: proto::PeerId,
13126 lsp_request_id: LspRequestId,
13127 proto_request: T::ProtoRequest,
13128 position: Option<Anchor>,
13129 cx: &mut AsyncApp,
13130 ) -> Result<()>
13131 where
13132 T: LspCommand + Clone,
13133 T::ProtoRequest: proto::LspRequestMessage,
13134 <T::ProtoRequest as proto::RequestMessage>::Response:
13135 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13136 {
13137 let (buffer_version, buffer) =
13138 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13139 let request =
13140 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13141 let key = LspKey {
13142 request_type: TypeId::of::<T>(),
13143 server_queried: for_server_id,
13144 };
13145 lsp_store.update(cx, |lsp_store, cx| {
13146 let request_task = match for_server_id {
13147 Some(server_id) => {
13148 let server_task = lsp_store.request_lsp(
13149 buffer.clone(),
13150 LanguageServerToQuery::Other(server_id),
13151 request.clone(),
13152 cx,
13153 );
13154 cx.background_spawn(async move {
13155 let mut responses = Vec::new();
13156 match server_task.await {
13157 Ok(response) => responses.push((server_id, response)),
13158 // rust-analyzer likes to error with this when its still loading up
13159 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13160 Err(e) => log::error!(
13161 "Error handling response for request {request:?}: {e:#}"
13162 ),
13163 }
13164 responses
13165 })
13166 }
13167 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13168 };
13169 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13170 if T::ProtoRequest::stop_previous_requests() {
13171 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13172 lsp_requests.clear();
13173 }
13174 }
13175 lsp_data.lsp_requests.entry(key).or_default().insert(
13176 lsp_request_id,
13177 cx.spawn(async move |lsp_store, cx| {
13178 let response = request_task.await;
13179 lsp_store
13180 .update(cx, |lsp_store, cx| {
13181 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13182 {
13183 let response = response
13184 .into_iter()
13185 .map(|(server_id, response)| {
13186 (
13187 server_id.to_proto(),
13188 T::response_to_proto(
13189 response,
13190 lsp_store,
13191 sender_id,
13192 &buffer_version,
13193 cx,
13194 )
13195 .into(),
13196 )
13197 })
13198 .collect::<HashMap<_, _>>();
13199 match client.send_lsp_response::<T::ProtoRequest>(
13200 project_id,
13201 lsp_request_id,
13202 response,
13203 ) {
13204 Ok(()) => {}
13205 Err(e) => {
13206 log::error!("Failed to send LSP response: {e:#}",)
13207 }
13208 }
13209 }
13210 })
13211 .ok();
13212 }),
13213 );
13214 });
13215 Ok(())
13216 }
13217
13218 async fn wait_for_buffer_version<T>(
13219 lsp_store: &Entity<Self>,
13220 proto_request: &T::ProtoRequest,
13221 cx: &mut AsyncApp,
13222 ) -> Result<(Global, Entity<Buffer>)>
13223 where
13224 T: LspCommand,
13225 T::ProtoRequest: proto::LspRequestMessage,
13226 {
13227 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13228 let version = deserialize_version(proto_request.buffer_version());
13229 let buffer = lsp_store.update(cx, |this, cx| {
13230 this.buffer_store.read(cx).get_existing(buffer_id)
13231 })?;
13232 buffer
13233 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13234 .await?;
13235 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13236 Ok((buffer_version, buffer))
13237 }
13238
13239 fn take_text_document_sync_options(
13240 capabilities: &mut lsp::ServerCapabilities,
13241 ) -> lsp::TextDocumentSyncOptions {
13242 match capabilities.text_document_sync.take() {
13243 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13244 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13245 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13246 sync_options.change = Some(sync_kind);
13247 sync_options
13248 }
13249 None => lsp::TextDocumentSyncOptions::default(),
13250 }
13251 }
13252
13253 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13254 self.downstream_client.clone()
13255 }
13256
13257 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13258 self.worktree_store.clone()
13259 }
13260
13261 /// Gets what's stored in the LSP data for the given buffer.
13262 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13263 self.lsp_data.get_mut(&buffer_id)
13264 }
13265
13266 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13267 /// new [`BufferLspData`] will be created to replace the previous state.
13268 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13269 let (buffer_id, buffer_version) =
13270 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13271 let lsp_data = self
13272 .lsp_data
13273 .entry(buffer_id)
13274 .or_insert_with(|| BufferLspData::new(buffer, cx));
13275 if buffer_version.changed_since(&lsp_data.buffer_version) {
13276 // To send delta requests for semantic tokens, the previous tokens
13277 // need to be kept between buffer changes.
13278 let semantic_tokens = lsp_data.semantic_tokens.take();
13279 *lsp_data = BufferLspData::new(buffer, cx);
13280 lsp_data.semantic_tokens = semantic_tokens;
13281 }
13282 lsp_data
13283 }
13284}
13285
13286// Registration with registerOptions as null, should fallback to true.
13287// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13288fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13289 reg: lsp::Registration,
13290) -> Result<OneOf<bool, T>> {
13291 Ok(match reg.register_options {
13292 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13293 None => OneOf::Left(true),
13294 })
13295}
13296
13297fn subscribe_to_binary_statuses(
13298 languages: &Arc<LanguageRegistry>,
13299 cx: &mut Context<'_, LspStore>,
13300) -> Task<()> {
13301 let mut server_statuses = languages.language_server_binary_statuses();
13302 cx.spawn(async move |lsp_store, cx| {
13303 while let Some((server_name, binary_status)) = server_statuses.next().await {
13304 if lsp_store
13305 .update(cx, |_, cx| {
13306 let mut message = None;
13307 let binary_status = match binary_status {
13308 BinaryStatus::None => proto::ServerBinaryStatus::None,
13309 BinaryStatus::CheckingForUpdate => {
13310 proto::ServerBinaryStatus::CheckingForUpdate
13311 }
13312 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13313 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13314 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13315 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13316 BinaryStatus::Failed { error } => {
13317 message = Some(error);
13318 proto::ServerBinaryStatus::Failed
13319 }
13320 };
13321 cx.emit(LspStoreEvent::LanguageServerUpdate {
13322 // Binary updates are about the binary that might not have any language server id at that point.
13323 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13324 language_server_id: LanguageServerId(0),
13325 name: Some(server_name),
13326 message: proto::update_language_server::Variant::StatusUpdate(
13327 proto::StatusUpdate {
13328 message,
13329 status: Some(proto::status_update::Status::Binary(
13330 binary_status as i32,
13331 )),
13332 },
13333 ),
13334 });
13335 })
13336 .is_err()
13337 {
13338 break;
13339 }
13340 }
13341 })
13342}
13343
13344fn lsp_workspace_diagnostics_refresh(
13345 registration_id: Option<String>,
13346 options: DiagnosticServerCapabilities,
13347 server: Arc<LanguageServer>,
13348 cx: &mut Context<'_, LspStore>,
13349) -> Option<WorkspaceRefreshTask> {
13350 let identifier = workspace_diagnostic_identifier(&options)?;
13351 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13352
13353 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13354 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13355 refresh_tx.try_send(()).ok();
13356
13357 let request_timeout = ProjectSettings::get_global(cx)
13358 .global_lsp_settings
13359 .get_request_timeout();
13360
13361 // 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.
13362 // This allows users to increase the duration if need be
13363 let timeout = if request_timeout != Duration::ZERO {
13364 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13365 } else {
13366 request_timeout
13367 };
13368
13369 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13370 let mut attempts = 0;
13371 let max_attempts = 50;
13372 let mut requests = 0;
13373
13374 loop {
13375 let Some(()) = refresh_rx.recv().await else {
13376 return;
13377 };
13378
13379 'request: loop {
13380 requests += 1;
13381 if attempts > max_attempts {
13382 log::error!(
13383 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13384 );
13385 return;
13386 }
13387 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13388 cx.background_executor()
13389 .timer(Duration::from_millis(backoff_millis))
13390 .await;
13391 attempts += 1;
13392
13393 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13394 lsp_store
13395 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13396 .into_iter()
13397 .filter_map(|(abs_path, result_id)| {
13398 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13399 Some(lsp::PreviousResultId {
13400 uri,
13401 value: result_id.to_string(),
13402 })
13403 })
13404 .collect()
13405 }) else {
13406 return;
13407 };
13408
13409 let token = if let Some(registration_id) = ®istration_id {
13410 format!(
13411 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13412 server.server_id(),
13413 )
13414 } else {
13415 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13416 };
13417
13418 progress_rx.try_recv().ok();
13419 let timer = server.request_timer(timeout).fuse();
13420 let progress = pin!(progress_rx.recv().fuse());
13421 let response_result = server
13422 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13423 lsp::WorkspaceDiagnosticParams {
13424 previous_result_ids,
13425 identifier: identifier.clone(),
13426 work_done_progress_params: Default::default(),
13427 partial_result_params: lsp::PartialResultParams {
13428 partial_result_token: Some(lsp::ProgressToken::String(token)),
13429 },
13430 },
13431 select(timer, progress).then(|either| match either {
13432 Either::Left((message, ..)) => ready(message).left_future(),
13433 Either::Right(..) => pending::<String>().right_future(),
13434 }),
13435 )
13436 .await;
13437
13438 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13439 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13440 match response_result {
13441 ConnectionResult::Timeout => {
13442 log::error!("Timeout during workspace diagnostics pull");
13443 continue 'request;
13444 }
13445 ConnectionResult::ConnectionReset => {
13446 log::error!("Server closed a workspace diagnostics pull request");
13447 continue 'request;
13448 }
13449 ConnectionResult::Result(Err(e)) => {
13450 log::error!("Error during workspace diagnostics pull: {e:#}");
13451 break 'request;
13452 }
13453 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13454 attempts = 0;
13455 if lsp_store
13456 .update(cx, |lsp_store, cx| {
13457 lsp_store.apply_workspace_diagnostic_report(
13458 server.server_id(),
13459 pulled_diagnostics,
13460 registration_id_shared.clone(),
13461 cx,
13462 )
13463 })
13464 .is_err()
13465 {
13466 return;
13467 }
13468 break 'request;
13469 }
13470 }
13471 }
13472 }
13473 });
13474
13475 Some(WorkspaceRefreshTask {
13476 refresh_tx,
13477 progress_tx,
13478 task: workspace_query_language_server,
13479 })
13480}
13481
13482fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13483 match &options {
13484 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13485 .identifier
13486 .as_deref()
13487 .map(SharedString::new),
13488 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13489 let diagnostic_options = ®istration_options.diagnostic_options;
13490 diagnostic_options
13491 .identifier
13492 .as_deref()
13493 .map(SharedString::new)
13494 }
13495 }
13496}
13497
13498fn workspace_diagnostic_identifier(
13499 options: &DiagnosticServerCapabilities,
13500) -> Option<Option<String>> {
13501 match &options {
13502 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13503 if !diagnostic_options.workspace_diagnostics {
13504 return None;
13505 }
13506 Some(diagnostic_options.identifier.clone())
13507 }
13508 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13509 let diagnostic_options = ®istration_options.diagnostic_options;
13510 if !diagnostic_options.workspace_diagnostics {
13511 return None;
13512 }
13513 Some(diagnostic_options.identifier.clone())
13514 }
13515 }
13516}
13517
13518fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13519 let CompletionSource::BufferWord {
13520 word_range,
13521 resolved,
13522 } = &mut completion.source
13523 else {
13524 return;
13525 };
13526 if *resolved {
13527 return;
13528 }
13529
13530 if completion.new_text
13531 != snapshot
13532 .text_for_range(word_range.clone())
13533 .collect::<String>()
13534 {
13535 return;
13536 }
13537
13538 let mut offset = 0;
13539 for chunk in snapshot.chunks(
13540 word_range.clone(),
13541 LanguageAwareStyling {
13542 tree_sitter: true,
13543 diagnostics: true,
13544 },
13545 ) {
13546 let end_offset = offset + chunk.text.len();
13547 if let Some(highlight_id) = chunk.syntax_highlight_id {
13548 completion
13549 .label
13550 .runs
13551 .push((offset..end_offset, highlight_id));
13552 }
13553 offset = end_offset;
13554 }
13555 *resolved = true;
13556}
13557
13558impl EventEmitter<LspStoreEvent> for LspStore {}
13559
13560fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13561 hover
13562 .contents
13563 .retain(|hover_block| !hover_block.text.trim().is_empty());
13564 if hover.contents.is_empty() {
13565 None
13566 } else {
13567 Some(hover)
13568 }
13569}
13570
13571async fn populate_labels_for_completions(
13572 new_completions: Vec<CoreCompletion>,
13573 language: Option<Arc<Language>>,
13574 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13575) -> Vec<Completion> {
13576 let lsp_completions = new_completions
13577 .iter()
13578 .filter_map(|new_completion| {
13579 new_completion
13580 .source
13581 .lsp_completion(true)
13582 .map(|lsp_completion| lsp_completion.into_owned())
13583 })
13584 .collect::<Vec<_>>();
13585
13586 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13587 lsp_adapter
13588 .labels_for_completions(&lsp_completions, language)
13589 .await
13590 .log_err()
13591 .unwrap_or_default()
13592 } else {
13593 Vec::new()
13594 }
13595 .into_iter()
13596 .fuse();
13597
13598 let mut completions = Vec::new();
13599 for completion in new_completions {
13600 match completion.source.lsp_completion(true) {
13601 Some(lsp_completion) => {
13602 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13603
13604 let mut label = labels.next().flatten().unwrap_or_else(|| {
13605 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13606 });
13607 ensure_uniform_list_compatible_label(&mut label);
13608 completions.push(Completion {
13609 label,
13610 documentation,
13611 replace_range: completion.replace_range,
13612 new_text: completion.new_text,
13613 insert_text_mode: lsp_completion.insert_text_mode,
13614 source: completion.source,
13615 icon_path: None,
13616 confirm: None,
13617 match_start: None,
13618 snippet_deduplication_key: None,
13619 });
13620 }
13621 None => {
13622 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13623 ensure_uniform_list_compatible_label(&mut label);
13624 completions.push(Completion {
13625 label,
13626 documentation: None,
13627 replace_range: completion.replace_range,
13628 new_text: completion.new_text,
13629 source: completion.source,
13630 insert_text_mode: None,
13631 icon_path: None,
13632 confirm: None,
13633 match_start: None,
13634 snippet_deduplication_key: None,
13635 });
13636 }
13637 }
13638 }
13639 completions
13640}
13641
13642#[derive(Debug)]
13643pub enum LanguageServerToQuery {
13644 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13645 FirstCapable,
13646 /// Query a specific language server.
13647 Other(LanguageServerId),
13648}
13649
13650#[derive(Default)]
13651struct RenamePathsWatchedForServer {
13652 did_rename: Vec<RenameActionPredicate>,
13653 will_rename: Vec<RenameActionPredicate>,
13654}
13655
13656impl RenamePathsWatchedForServer {
13657 fn with_did_rename_patterns(
13658 mut self,
13659 did_rename: Option<&FileOperationRegistrationOptions>,
13660 ) -> Self {
13661 if let Some(did_rename) = did_rename {
13662 self.did_rename = did_rename
13663 .filters
13664 .iter()
13665 .filter_map(|filter| filter.try_into().log_err())
13666 .collect();
13667 }
13668 self
13669 }
13670 fn with_will_rename_patterns(
13671 mut self,
13672 will_rename: Option<&FileOperationRegistrationOptions>,
13673 ) -> Self {
13674 if let Some(will_rename) = will_rename {
13675 self.will_rename = will_rename
13676 .filters
13677 .iter()
13678 .filter_map(|filter| filter.try_into().log_err())
13679 .collect();
13680 }
13681 self
13682 }
13683
13684 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13685 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13686 }
13687 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13688 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13689 }
13690}
13691
13692impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13693 type Error = globset::Error;
13694 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13695 Ok(Self {
13696 kind: ops.pattern.matches.clone(),
13697 glob: GlobBuilder::new(&ops.pattern.glob)
13698 .case_insensitive(
13699 ops.pattern
13700 .options
13701 .as_ref()
13702 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13703 )
13704 .build()?
13705 .compile_matcher(),
13706 })
13707 }
13708}
13709struct RenameActionPredicate {
13710 glob: GlobMatcher,
13711 kind: Option<FileOperationPatternKind>,
13712}
13713
13714impl RenameActionPredicate {
13715 // Returns true if language server should be notified
13716 fn eval(&self, path: &str, is_dir: bool) -> bool {
13717 self.kind.as_ref().is_none_or(|kind| {
13718 let expected_kind = if is_dir {
13719 FileOperationPatternKind::Folder
13720 } else {
13721 FileOperationPatternKind::File
13722 };
13723 kind == &expected_kind
13724 }) && self.glob.is_match(path)
13725 }
13726}
13727
13728#[derive(Default)]
13729struct LanguageServerWatchedPaths {
13730 worktree_paths: HashMap<WorktreeId, GlobSet>,
13731 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13732}
13733
13734#[derive(Default)]
13735struct LanguageServerWatchedPathsBuilder {
13736 worktree_paths: HashMap<WorktreeId, GlobSet>,
13737 abs_paths: HashMap<Arc<Path>, GlobSet>,
13738}
13739
13740impl LanguageServerWatchedPathsBuilder {
13741 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13742 self.worktree_paths.insert(worktree_id, glob_set);
13743 }
13744 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13745 self.abs_paths.insert(path, glob_set);
13746 }
13747 fn build(
13748 self,
13749 fs: Arc<dyn Fs>,
13750 language_server_id: LanguageServerId,
13751 cx: &mut Context<LspStore>,
13752 ) -> LanguageServerWatchedPaths {
13753 let lsp_store = cx.weak_entity();
13754
13755 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13756 let abs_paths = self
13757 .abs_paths
13758 .into_iter()
13759 .map(|(abs_path, globset)| {
13760 let task = cx.spawn({
13761 let abs_path = abs_path.clone();
13762 let fs = fs.clone();
13763
13764 let lsp_store = lsp_store.clone();
13765 async move |_, cx| {
13766 maybe!(async move {
13767 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13768 while let Some(update) = push_updates.0.next().await {
13769 let action = lsp_store
13770 .update(cx, |this, _| {
13771 let Some(local) = this.as_local() else {
13772 return ControlFlow::Break(());
13773 };
13774 let Some(watcher) = local
13775 .language_server_watched_paths
13776 .get(&language_server_id)
13777 else {
13778 return ControlFlow::Break(());
13779 };
13780 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13781 "Watched abs path is not registered with a watcher",
13782 );
13783 let matching_entries = update
13784 .into_iter()
13785 .filter(|event| globs.is_match(&event.path))
13786 .collect::<Vec<_>>();
13787 this.lsp_notify_abs_paths_changed(
13788 language_server_id,
13789 matching_entries,
13790 );
13791 ControlFlow::Continue(())
13792 })
13793 .ok()?;
13794
13795 if action.is_break() {
13796 break;
13797 }
13798 }
13799 Some(())
13800 })
13801 .await;
13802 }
13803 });
13804 (abs_path, (globset, task))
13805 })
13806 .collect();
13807 LanguageServerWatchedPaths {
13808 worktree_paths: self.worktree_paths,
13809 abs_paths,
13810 }
13811 }
13812}
13813
13814struct LspBufferSnapshot {
13815 version: i32,
13816 snapshot: TextBufferSnapshot,
13817}
13818
13819/// A prompt requested by LSP server.
13820#[derive(Clone, Debug)]
13821pub struct LanguageServerPromptRequest {
13822 pub id: usize,
13823 pub level: PromptLevel,
13824 pub message: String,
13825 pub actions: Vec<MessageActionItem>,
13826 pub lsp_name: String,
13827 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13828}
13829
13830impl LanguageServerPromptRequest {
13831 pub fn new(
13832 level: PromptLevel,
13833 message: String,
13834 actions: Vec<MessageActionItem>,
13835 lsp_name: String,
13836 response_channel: smol::channel::Sender<MessageActionItem>,
13837 ) -> Self {
13838 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13839 LanguageServerPromptRequest {
13840 id,
13841 level,
13842 message,
13843 actions,
13844 lsp_name,
13845 response_channel,
13846 }
13847 }
13848 pub async fn respond(self, index: usize) -> Option<()> {
13849 if let Some(response) = self.actions.into_iter().nth(index) {
13850 self.response_channel.send(response).await.ok()
13851 } else {
13852 None
13853 }
13854 }
13855
13856 #[cfg(any(test, feature = "test-support"))]
13857 pub fn test(
13858 level: PromptLevel,
13859 message: String,
13860 actions: Vec<MessageActionItem>,
13861 lsp_name: String,
13862 ) -> Self {
13863 let (tx, _rx) = smol::channel::unbounded();
13864 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13865 }
13866}
13867impl PartialEq for LanguageServerPromptRequest {
13868 fn eq(&self, other: &Self) -> bool {
13869 self.message == other.message && self.actions == other.actions
13870 }
13871}
13872
13873#[derive(Clone, Debug, PartialEq)]
13874pub enum LanguageServerLogType {
13875 Log(MessageType),
13876 Trace { verbose_info: Option<String> },
13877 Rpc { received: bool },
13878}
13879
13880impl LanguageServerLogType {
13881 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13882 match self {
13883 Self::Log(log_type) => {
13884 use proto::log_message::LogLevel;
13885 let level = match *log_type {
13886 MessageType::ERROR => LogLevel::Error,
13887 MessageType::WARNING => LogLevel::Warning,
13888 MessageType::INFO => LogLevel::Info,
13889 MessageType::LOG => LogLevel::Log,
13890 other => {
13891 log::warn!("Unknown lsp log message type: {other:?}");
13892 LogLevel::Log
13893 }
13894 };
13895 proto::language_server_log::LogType::Log(proto::LogMessage {
13896 level: level as i32,
13897 })
13898 }
13899 Self::Trace { verbose_info } => {
13900 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13901 verbose_info: verbose_info.to_owned(),
13902 })
13903 }
13904 Self::Rpc { received } => {
13905 let kind = if *received {
13906 proto::rpc_message::Kind::Received
13907 } else {
13908 proto::rpc_message::Kind::Sent
13909 };
13910 let kind = kind as i32;
13911 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13912 }
13913 }
13914 }
13915
13916 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13917 use proto::log_message::LogLevel;
13918 use proto::rpc_message;
13919 match log_type {
13920 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13921 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13922 LogLevel::Error => MessageType::ERROR,
13923 LogLevel::Warning => MessageType::WARNING,
13924 LogLevel::Info => MessageType::INFO,
13925 LogLevel::Log => MessageType::LOG,
13926 },
13927 ),
13928 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13929 verbose_info: trace_message.verbose_info,
13930 },
13931 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13932 received: match rpc_message::Kind::from_i32(message.kind)
13933 .unwrap_or(rpc_message::Kind::Received)
13934 {
13935 rpc_message::Kind::Received => true,
13936 rpc_message::Kind::Sent => false,
13937 },
13938 },
13939 }
13940 }
13941}
13942
13943pub struct WorkspaceRefreshTask {
13944 refresh_tx: mpsc::Sender<()>,
13945 progress_tx: mpsc::Sender<()>,
13946 #[allow(dead_code)]
13947 task: Task<()>,
13948}
13949
13950pub enum LanguageServerState {
13951 Starting {
13952 startup: Task<Option<Arc<LanguageServer>>>,
13953 /// List of language servers that will be added to the workspace once it's initialization completes.
13954 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13955 },
13956
13957 Running {
13958 adapter: Arc<CachedLspAdapter>,
13959 server: Arc<LanguageServer>,
13960 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13961 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13962 },
13963}
13964
13965impl LanguageServerState {
13966 fn add_workspace_folder(&self, uri: Uri) {
13967 match self {
13968 LanguageServerState::Starting {
13969 pending_workspace_folders,
13970 ..
13971 } => {
13972 pending_workspace_folders.lock().insert(uri);
13973 }
13974 LanguageServerState::Running { server, .. } => {
13975 server.add_workspace_folder(uri);
13976 }
13977 }
13978 }
13979 fn _remove_workspace_folder(&self, uri: Uri) {
13980 match self {
13981 LanguageServerState::Starting {
13982 pending_workspace_folders,
13983 ..
13984 } => {
13985 pending_workspace_folders.lock().remove(&uri);
13986 }
13987 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13988 }
13989 }
13990}
13991
13992impl std::fmt::Debug for LanguageServerState {
13993 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13994 match self {
13995 LanguageServerState::Starting { .. } => {
13996 f.debug_struct("LanguageServerState::Starting").finish()
13997 }
13998 LanguageServerState::Running { .. } => {
13999 f.debug_struct("LanguageServerState::Running").finish()
14000 }
14001 }
14002 }
14003}
14004
14005#[derive(Clone, Debug, Serialize)]
14006pub struct LanguageServerProgress {
14007 pub is_disk_based_diagnostics_progress: bool,
14008 pub is_cancellable: bool,
14009 pub title: Option<String>,
14010 pub message: Option<String>,
14011 pub percentage: Option<usize>,
14012 #[serde(skip_serializing)]
14013 pub last_update_at: Instant,
14014}
14015
14016#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14017pub struct DiagnosticSummary {
14018 pub error_count: usize,
14019 pub warning_count: usize,
14020}
14021
14022impl DiagnosticSummary {
14023 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14024 let mut this = Self {
14025 error_count: 0,
14026 warning_count: 0,
14027 };
14028
14029 for entry in diagnostics {
14030 if entry.diagnostic.is_primary {
14031 match entry.diagnostic.severity {
14032 DiagnosticSeverity::ERROR => this.error_count += 1,
14033 DiagnosticSeverity::WARNING => this.warning_count += 1,
14034 _ => {}
14035 }
14036 }
14037 }
14038
14039 this
14040 }
14041
14042 pub fn is_empty(&self) -> bool {
14043 self.error_count == 0 && self.warning_count == 0
14044 }
14045
14046 pub fn to_proto(
14047 self,
14048 language_server_id: LanguageServerId,
14049 path: &RelPath,
14050 ) -> proto::DiagnosticSummary {
14051 proto::DiagnosticSummary {
14052 path: path.to_proto(),
14053 language_server_id: language_server_id.0 as u64,
14054 error_count: self.error_count as u32,
14055 warning_count: self.warning_count as u32,
14056 }
14057 }
14058}
14059
14060#[derive(Clone, Debug)]
14061pub enum CompletionDocumentation {
14062 /// There is no documentation for this completion.
14063 Undocumented,
14064 /// A single line of documentation.
14065 SingleLine(SharedString),
14066 /// Multiple lines of plain text documentation.
14067 MultiLinePlainText(SharedString),
14068 /// Markdown documentation.
14069 MultiLineMarkdown(SharedString),
14070 /// Both single line and multiple lines of plain text documentation.
14071 SingleLineAndMultiLinePlainText {
14072 single_line: SharedString,
14073 plain_text: Option<SharedString>,
14074 },
14075}
14076
14077impl CompletionDocumentation {
14078 #[cfg(any(test, feature = "test-support"))]
14079 pub fn text(&self) -> SharedString {
14080 match self {
14081 CompletionDocumentation::Undocumented => "".into(),
14082 CompletionDocumentation::SingleLine(s) => s.clone(),
14083 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14084 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14085 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14086 single_line.clone()
14087 }
14088 }
14089 }
14090}
14091
14092impl From<lsp::Documentation> for CompletionDocumentation {
14093 fn from(docs: lsp::Documentation) -> Self {
14094 match docs {
14095 lsp::Documentation::String(text) => {
14096 if text.lines().count() <= 1 {
14097 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14098 } else {
14099 CompletionDocumentation::MultiLinePlainText(text.into())
14100 }
14101 }
14102
14103 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14104 lsp::MarkupKind::PlainText => {
14105 if value.lines().count() <= 1 {
14106 CompletionDocumentation::SingleLine(value.into())
14107 } else {
14108 CompletionDocumentation::MultiLinePlainText(value.into())
14109 }
14110 }
14111
14112 lsp::MarkupKind::Markdown => {
14113 CompletionDocumentation::MultiLineMarkdown(value.into())
14114 }
14115 },
14116 }
14117 }
14118}
14119
14120pub enum ResolvedHint {
14121 Resolved(InlayHint),
14122 Resolving(Shared<Task<()>>),
14123}
14124
14125pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14126 glob.components()
14127 .take_while(|component| match component {
14128 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14129 _ => true,
14130 })
14131 .collect()
14132}
14133
14134pub struct SshLspAdapter {
14135 name: LanguageServerName,
14136 binary: LanguageServerBinary,
14137 initialization_options: Option<String>,
14138 code_action_kinds: Option<Vec<CodeActionKind>>,
14139}
14140
14141impl SshLspAdapter {
14142 pub fn new(
14143 name: LanguageServerName,
14144 binary: LanguageServerBinary,
14145 initialization_options: Option<String>,
14146 code_action_kinds: Option<String>,
14147 ) -> Self {
14148 Self {
14149 name,
14150 binary,
14151 initialization_options,
14152 code_action_kinds: code_action_kinds
14153 .as_ref()
14154 .and_then(|c| serde_json::from_str(c).ok()),
14155 }
14156 }
14157}
14158
14159impl LspInstaller for SshLspAdapter {
14160 type BinaryVersion = ();
14161 async fn check_if_user_installed(
14162 &self,
14163 _: &dyn LspAdapterDelegate,
14164 _: Option<Toolchain>,
14165 _: &AsyncApp,
14166 ) -> Option<LanguageServerBinary> {
14167 Some(self.binary.clone())
14168 }
14169
14170 async fn cached_server_binary(
14171 &self,
14172 _: PathBuf,
14173 _: &dyn LspAdapterDelegate,
14174 ) -> Option<LanguageServerBinary> {
14175 None
14176 }
14177
14178 async fn fetch_latest_server_version(
14179 &self,
14180 _: &dyn LspAdapterDelegate,
14181 _: bool,
14182 _: &mut AsyncApp,
14183 ) -> Result<()> {
14184 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14185 }
14186
14187 async fn fetch_server_binary(
14188 &self,
14189 _: (),
14190 _: PathBuf,
14191 _: &dyn LspAdapterDelegate,
14192 ) -> Result<LanguageServerBinary> {
14193 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14194 }
14195}
14196
14197#[async_trait(?Send)]
14198impl LspAdapter for SshLspAdapter {
14199 fn name(&self) -> LanguageServerName {
14200 self.name.clone()
14201 }
14202
14203 async fn initialization_options(
14204 self: Arc<Self>,
14205 _: &Arc<dyn LspAdapterDelegate>,
14206 _: &mut AsyncApp,
14207 ) -> Result<Option<serde_json::Value>> {
14208 let Some(options) = &self.initialization_options else {
14209 return Ok(None);
14210 };
14211 let result = serde_json::from_str(options)?;
14212 Ok(result)
14213 }
14214
14215 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14216 self.code_action_kinds.clone()
14217 }
14218}
14219
14220pub fn language_server_settings<'a>(
14221 delegate: &'a dyn LspAdapterDelegate,
14222 language: &LanguageServerName,
14223 cx: &'a App,
14224) -> Option<&'a LspSettings> {
14225 language_server_settings_for(
14226 SettingsLocation {
14227 worktree_id: delegate.worktree_id(),
14228 path: RelPath::empty(),
14229 },
14230 language,
14231 cx,
14232 )
14233}
14234
14235pub fn language_server_settings_for<'a>(
14236 location: SettingsLocation<'a>,
14237 language: &LanguageServerName,
14238 cx: &'a App,
14239) -> Option<&'a LspSettings> {
14240 ProjectSettings::get(Some(location), cx).lsp.get(language)
14241}
14242
14243pub struct LocalLspAdapterDelegate {
14244 lsp_store: WeakEntity<LspStore>,
14245 worktree: worktree::Snapshot,
14246 fs: Arc<dyn Fs>,
14247 http_client: Arc<dyn HttpClient>,
14248 language_registry: Arc<LanguageRegistry>,
14249 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14250}
14251
14252impl LocalLspAdapterDelegate {
14253 pub fn new(
14254 language_registry: Arc<LanguageRegistry>,
14255 environment: &Entity<ProjectEnvironment>,
14256 lsp_store: WeakEntity<LspStore>,
14257 worktree: &Entity<Worktree>,
14258 http_client: Arc<dyn HttpClient>,
14259 fs: Arc<dyn Fs>,
14260 cx: &mut App,
14261 ) -> Arc<Self> {
14262 let load_shell_env_task =
14263 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14264
14265 Arc::new(Self {
14266 lsp_store,
14267 worktree: worktree.read(cx).snapshot(),
14268 fs,
14269 http_client,
14270 language_registry,
14271 load_shell_env_task,
14272 })
14273 }
14274
14275 pub fn from_local_lsp(
14276 local: &LocalLspStore,
14277 worktree: &Entity<Worktree>,
14278 cx: &mut App,
14279 ) -> Arc<Self> {
14280 Self::new(
14281 local.languages.clone(),
14282 &local.environment,
14283 local.weak.clone(),
14284 worktree,
14285 local.http_client.clone(),
14286 local.fs.clone(),
14287 cx,
14288 )
14289 }
14290}
14291
14292#[async_trait]
14293impl LspAdapterDelegate for LocalLspAdapterDelegate {
14294 fn show_notification(&self, message: &str, cx: &mut App) {
14295 self.lsp_store
14296 .update(cx, |_, cx| {
14297 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14298 })
14299 .ok();
14300 }
14301
14302 fn http_client(&self) -> Arc<dyn HttpClient> {
14303 self.http_client.clone()
14304 }
14305
14306 fn worktree_id(&self) -> WorktreeId {
14307 self.worktree.id()
14308 }
14309
14310 fn worktree_root_path(&self) -> &Path {
14311 self.worktree.abs_path().as_ref()
14312 }
14313
14314 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14315 self.worktree.resolve_relative_path(path)
14316 }
14317
14318 async fn shell_env(&self) -> HashMap<String, String> {
14319 let task = self.load_shell_env_task.clone();
14320 task.await.unwrap_or_default()
14321 }
14322
14323 async fn npm_package_installed_version(
14324 &self,
14325 package_name: &str,
14326 ) -> Result<Option<(PathBuf, Version)>> {
14327 let local_package_directory = self.worktree_root_path();
14328 let node_modules_directory = local_package_directory.join("node_modules");
14329
14330 if let Some(version) =
14331 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14332 {
14333 return Ok(Some((node_modules_directory, version)));
14334 }
14335 let Some(npm) = self.which("npm".as_ref()).await else {
14336 log::warn!(
14337 "Failed to find npm executable for {:?}",
14338 local_package_directory
14339 );
14340 return Ok(None);
14341 };
14342
14343 let env = self.shell_env().await;
14344 let output = util::command::new_command(&npm)
14345 .args(["root", "-g"])
14346 .envs(env)
14347 .current_dir(local_package_directory)
14348 .output()
14349 .await?;
14350 let global_node_modules =
14351 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14352
14353 if let Some(version) =
14354 read_package_installed_version(global_node_modules.clone(), package_name).await?
14355 {
14356 return Ok(Some((global_node_modules, version)));
14357 }
14358 return Ok(None);
14359 }
14360
14361 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14362 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14363 if self.fs.is_file(&worktree_abs_path).await {
14364 worktree_abs_path.pop();
14365 }
14366
14367 let env = self.shell_env().await;
14368
14369 let shell_path = env.get("PATH").cloned();
14370
14371 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14372 }
14373
14374 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14375 let mut working_dir = self.worktree_root_path().to_path_buf();
14376 if self.fs.is_file(&working_dir).await {
14377 working_dir.pop();
14378 }
14379 let output = util::command::new_command(&command.path)
14380 .args(command.arguments)
14381 .envs(command.env.clone().unwrap_or_default())
14382 .current_dir(working_dir)
14383 .output()
14384 .await?;
14385
14386 anyhow::ensure!(
14387 output.status.success(),
14388 "{}, stdout: {:?}, stderr: {:?}",
14389 output.status,
14390 String::from_utf8_lossy(&output.stdout),
14391 String::from_utf8_lossy(&output.stderr)
14392 );
14393 Ok(())
14394 }
14395
14396 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14397 self.language_registry
14398 .update_lsp_binary_status(server_name, status);
14399 }
14400
14401 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14402 self.language_registry
14403 .all_lsp_adapters()
14404 .into_iter()
14405 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14406 .collect()
14407 }
14408
14409 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14410 let dir = self.language_registry.language_server_download_dir(name)?;
14411
14412 if !dir.exists() {
14413 smol::fs::create_dir_all(&dir)
14414 .await
14415 .context("failed to create container directory")
14416 .log_err()?;
14417 }
14418
14419 Some(dir)
14420 }
14421
14422 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14423 let entry = self
14424 .worktree
14425 .entry_for_path(path)
14426 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14427 let abs_path = self.worktree.absolutize(&entry.path);
14428 self.fs.load(&abs_path).await
14429 }
14430}
14431
14432async fn populate_labels_for_symbols(
14433 symbols: Vec<CoreSymbol>,
14434 language_registry: &Arc<LanguageRegistry>,
14435 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14436 output: &mut Vec<Symbol>,
14437) {
14438 #[allow(clippy::mutable_key_type)]
14439 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14440
14441 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14442 for symbol in symbols {
14443 let Some(file_name) = symbol.path.file_name() else {
14444 continue;
14445 };
14446 let language = language_registry
14447 .load_language_for_file_path(Path::new(file_name))
14448 .await
14449 .ok()
14450 .or_else(|| {
14451 unknown_paths.insert(file_name.into());
14452 None
14453 });
14454 symbols_by_language
14455 .entry(language)
14456 .or_default()
14457 .push(symbol);
14458 }
14459
14460 for unknown_path in unknown_paths {
14461 log::info!("no language found for symbol in file {unknown_path:?}");
14462 }
14463
14464 let mut label_params = Vec::new();
14465 for (language, mut symbols) in symbols_by_language {
14466 label_params.clear();
14467 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14468 name: mem::take(&mut symbol.name),
14469 kind: symbol.kind,
14470 container_name: symbol.container_name.take(),
14471 }));
14472
14473 let mut labels = Vec::new();
14474 if let Some(language) = language {
14475 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14476 language_registry
14477 .lsp_adapters(&language.name())
14478 .first()
14479 .cloned()
14480 });
14481 if let Some(lsp_adapter) = lsp_adapter {
14482 labels = lsp_adapter
14483 .labels_for_symbols(&label_params, &language)
14484 .await
14485 .log_err()
14486 .unwrap_or_default();
14487 }
14488 }
14489
14490 for (
14491 (
14492 symbol,
14493 language::Symbol {
14494 name,
14495 container_name,
14496 ..
14497 },
14498 ),
14499 label,
14500 ) in symbols
14501 .into_iter()
14502 .zip(label_params.drain(..))
14503 .zip(labels.into_iter().chain(iter::repeat(None)))
14504 {
14505 output.push(Symbol {
14506 language_server_name: symbol.language_server_name,
14507 source_worktree_id: symbol.source_worktree_id,
14508 source_language_server_id: symbol.source_language_server_id,
14509 path: symbol.path,
14510 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14511 name,
14512 kind: symbol.kind,
14513 range: symbol.range,
14514 container_name,
14515 });
14516 }
14517 }
14518}
14519
14520pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14521 text.lines()
14522 .map(|line| line.trim())
14523 .filter(|line| !line.is_empty())
14524 .join(separator)
14525}
14526
14527fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14528 match server.capabilities().text_document_sync.as_ref()? {
14529 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14530 // Server wants didSave but didn't specify includeText.
14531 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14532 // Server doesn't want didSave at all.
14533 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14534 // Server provided SaveOptions.
14535 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14536 Some(save_options.include_text.unwrap_or(false))
14537 }
14538 },
14539 // We do not have any save info. Kind affects didChange only.
14540 lsp::TextDocumentSyncCapability::Kind(_) => None,
14541 }
14542}
14543
14544/// Completion items are displayed in a `UniformList`.
14545/// Usually, those items are single-line strings, but in LSP responses,
14546/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14547/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14548/// 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,
14549/// breaking the completions menu presentation.
14550///
14551/// 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.
14552pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14553 let mut new_text = String::with_capacity(label.text.len());
14554 let mut offset_map = vec![0; label.text.len() + 1];
14555 let mut last_char_was_space = false;
14556 let mut new_idx = 0;
14557 let chars = label.text.char_indices().fuse();
14558 let mut newlines_removed = false;
14559
14560 for (idx, c) in chars {
14561 offset_map[idx] = new_idx;
14562
14563 match c {
14564 '\n' if last_char_was_space => {
14565 newlines_removed = true;
14566 }
14567 '\t' | ' ' if last_char_was_space => {}
14568 '\n' if !last_char_was_space => {
14569 new_text.push(' ');
14570 new_idx += 1;
14571 last_char_was_space = true;
14572 newlines_removed = true;
14573 }
14574 ' ' | '\t' => {
14575 new_text.push(' ');
14576 new_idx += 1;
14577 last_char_was_space = true;
14578 }
14579 _ => {
14580 new_text.push(c);
14581 new_idx += c.len_utf8();
14582 last_char_was_space = false;
14583 }
14584 }
14585 }
14586 offset_map[label.text.len()] = new_idx;
14587
14588 // Only modify the label if newlines were removed.
14589 if !newlines_removed {
14590 return;
14591 }
14592
14593 let last_index = new_idx;
14594 let mut run_ranges_errors = Vec::new();
14595 label.runs.retain_mut(|(range, _)| {
14596 match offset_map.get(range.start) {
14597 Some(&start) => range.start = start,
14598 None => {
14599 run_ranges_errors.push(range.clone());
14600 return false;
14601 }
14602 }
14603
14604 match offset_map.get(range.end) {
14605 Some(&end) => range.end = end,
14606 None => {
14607 run_ranges_errors.push(range.clone());
14608 range.end = last_index;
14609 }
14610 }
14611 true
14612 });
14613 if !run_ranges_errors.is_empty() {
14614 log::error!(
14615 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14616 label.text
14617 );
14618 }
14619
14620 let mut wrong_filter_range = None;
14621 if label.filter_range == (0..label.text.len()) {
14622 label.filter_range = 0..new_text.len();
14623 } else {
14624 let mut original_filter_range = Some(label.filter_range.clone());
14625 match offset_map.get(label.filter_range.start) {
14626 Some(&start) => label.filter_range.start = start,
14627 None => {
14628 wrong_filter_range = original_filter_range.take();
14629 label.filter_range.start = last_index;
14630 }
14631 }
14632
14633 match offset_map.get(label.filter_range.end) {
14634 Some(&end) => label.filter_range.end = end,
14635 None => {
14636 wrong_filter_range = original_filter_range.take();
14637 label.filter_range.end = last_index;
14638 }
14639 }
14640 }
14641 if let Some(wrong_filter_range) = wrong_filter_range {
14642 log::error!(
14643 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14644 label.text
14645 );
14646 }
14647
14648 label.text = new_text;
14649}
14650
14651/// Apply edits to the buffer that will become part of the formatting transaction.
14652/// Fails if the buffer has been edited since the start of that transaction.
14653fn extend_formatting_transaction(
14654 buffer: &FormattableBuffer,
14655 formatting_transaction_id: text::TransactionId,
14656 cx: &mut AsyncApp,
14657 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14658) -> anyhow::Result<()> {
14659 buffer.handle.update(cx, |buffer, cx| {
14660 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14661 if last_transaction_id != Some(formatting_transaction_id) {
14662 anyhow::bail!("Buffer edited while formatting. Aborting")
14663 }
14664 buffer.start_transaction();
14665 operation(buffer, cx);
14666 if let Some(transaction_id) = buffer.end_transaction(cx) {
14667 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14668 }
14669 Ok(())
14670 })
14671}