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 cx.emit(LspStoreEvent::RefreshCodeLens);
1090 this.downstream_client.as_ref().map(|(client, project_id)| {
1091 client.send(proto::RefreshCodeLens {
1092 project_id: *project_id,
1093 })
1094 })
1095 })?
1096 .transpose()?;
1097 Ok(())
1098 }
1099 }
1100 })
1101 .detach();
1102
1103 language_server
1104 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1105 let lsp_store = lsp_store.clone();
1106 let request_id = Arc::new(AtomicUsize::new(0));
1107 move |(), cx| {
1108 let lsp_store = lsp_store.clone();
1109 let request_id = request_id.clone();
1110 let mut cx = cx.clone();
1111 async move {
1112 lsp_store
1113 .update(&mut cx, |lsp_store, cx| {
1114 let request_id =
1115 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1116 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1117 server_id,
1118 request_id,
1119 });
1120 lsp_store
1121 .downstream_client
1122 .as_ref()
1123 .map(|(client, project_id)| {
1124 client.send(proto::RefreshSemanticTokens {
1125 project_id: *project_id,
1126 server_id: server_id.to_proto(),
1127 request_id: request_id.map(|id| id as u64),
1128 })
1129 })
1130 })?
1131 .transpose()?;
1132 Ok(())
1133 }
1134 }
1135 })
1136 .detach();
1137
1138 language_server
1139 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1140 let this = lsp_store.clone();
1141 move |(), cx| {
1142 let this = this.clone();
1143 let mut cx = cx.clone();
1144 async move {
1145 this.update(&mut cx, |lsp_store, cx| {
1146 lsp_store.pull_workspace_diagnostics(server_id);
1147 lsp_store
1148 .downstream_client
1149 .as_ref()
1150 .map(|(client, project_id)| {
1151 client.send(proto::PullWorkspaceDiagnostics {
1152 project_id: *project_id,
1153 server_id: server_id.to_proto(),
1154 })
1155 })
1156 .transpose()?;
1157 anyhow::Ok(
1158 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1159 )
1160 })??
1161 .await;
1162 Ok(())
1163 }
1164 }
1165 })
1166 .detach();
1167
1168 language_server
1169 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1170 let this = lsp_store.clone();
1171 let name = name.to_string();
1172 let adapter = adapter.clone();
1173 move |params, cx| {
1174 let this = this.clone();
1175 let name = name.to_string();
1176 let adapter = adapter.clone();
1177 let mut cx = cx.clone();
1178 async move {
1179 let actions = params.actions.unwrap_or_default();
1180 let message = params.message.clone();
1181 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1182 let level = match params.typ {
1183 lsp::MessageType::ERROR => PromptLevel::Critical,
1184 lsp::MessageType::WARNING => PromptLevel::Warning,
1185 _ => PromptLevel::Info,
1186 };
1187 let request = LanguageServerPromptRequest::new(
1188 level,
1189 params.message,
1190 actions,
1191 name.clone(),
1192 tx,
1193 );
1194
1195 let did_update = this
1196 .update(&mut cx, |_, cx| {
1197 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1198 })
1199 .is_ok();
1200 if did_update {
1201 let response = rx.recv().await.ok();
1202 if let Some(ref selected_action) = response {
1203 let context = language::PromptResponseContext {
1204 message,
1205 selected_action: selected_action.clone(),
1206 };
1207 adapter.process_prompt_response(&context, &mut cx)
1208 }
1209
1210 Ok(response)
1211 } else {
1212 Ok(None)
1213 }
1214 }
1215 }
1216 })
1217 .detach();
1218 language_server
1219 .on_notification::<lsp::notification::ShowMessage, _>({
1220 let this = lsp_store.clone();
1221 let name = name.to_string();
1222 move |params, cx| {
1223 let this = this.clone();
1224 let name = name.to_string();
1225 let mut cx = cx.clone();
1226
1227 let (tx, _) = smol::channel::bounded(1);
1228 let level = match params.typ {
1229 lsp::MessageType::ERROR => PromptLevel::Critical,
1230 lsp::MessageType::WARNING => PromptLevel::Warning,
1231 _ => PromptLevel::Info,
1232 };
1233 let request =
1234 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1235
1236 let _ = this.update(&mut cx, |_, cx| {
1237 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1238 });
1239 }
1240 })
1241 .detach();
1242
1243 let disk_based_diagnostics_progress_token =
1244 adapter.disk_based_diagnostics_progress_token.clone();
1245
1246 language_server
1247 .on_notification::<lsp::notification::Progress, _>({
1248 let this = lsp_store.clone();
1249 move |params, cx| {
1250 if let Some(this) = this.upgrade() {
1251 this.update(cx, |this, cx| {
1252 this.on_lsp_progress(
1253 params,
1254 server_id,
1255 disk_based_diagnostics_progress_token.clone(),
1256 cx,
1257 );
1258 });
1259 }
1260 }
1261 })
1262 .detach();
1263
1264 language_server
1265 .on_notification::<lsp::notification::LogMessage, _>({
1266 let this = lsp_store.clone();
1267 move |params, cx| {
1268 if let Some(this) = this.upgrade() {
1269 this.update(cx, |_, cx| {
1270 cx.emit(LspStoreEvent::LanguageServerLog(
1271 server_id,
1272 LanguageServerLogType::Log(params.typ),
1273 params.message,
1274 ));
1275 });
1276 }
1277 }
1278 })
1279 .detach();
1280
1281 language_server
1282 .on_notification::<lsp::notification::LogTrace, _>({
1283 let this = lsp_store.clone();
1284 move |params, cx| {
1285 let mut cx = cx.clone();
1286 if let Some(this) = this.upgrade() {
1287 this.update(&mut cx, |_, cx| {
1288 cx.emit(LspStoreEvent::LanguageServerLog(
1289 server_id,
1290 LanguageServerLogType::Trace {
1291 verbose_info: params.verbose,
1292 },
1293 params.message,
1294 ));
1295 });
1296 }
1297 }
1298 })
1299 .detach();
1300
1301 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1302 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1303 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1304 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1305 }
1306
1307 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1308 let shutdown_futures = self
1309 .language_servers
1310 .drain()
1311 .map(|(_, server_state)| Self::shutdown_server(server_state))
1312 .collect::<Vec<_>>();
1313
1314 async move {
1315 join_all(shutdown_futures).await;
1316 }
1317 }
1318
1319 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1320 match server_state {
1321 LanguageServerState::Running { server, .. } => {
1322 if let Some(shutdown) = server.shutdown() {
1323 shutdown.await;
1324 }
1325 }
1326 LanguageServerState::Starting { startup, .. } => {
1327 if let Some(server) = startup.await
1328 && let Some(shutdown) = server.shutdown()
1329 {
1330 shutdown.await;
1331 }
1332 }
1333 }
1334 Ok(())
1335 }
1336
1337 fn language_servers_for_worktree(
1338 &self,
1339 worktree_id: WorktreeId,
1340 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1341 self.language_server_ids
1342 .iter()
1343 .filter_map(move |(seed, state)| {
1344 if seed.worktree_id != worktree_id {
1345 return None;
1346 }
1347
1348 if let Some(LanguageServerState::Running { server, .. }) =
1349 self.language_servers.get(&state.id)
1350 {
1351 Some(server)
1352 } else {
1353 None
1354 }
1355 })
1356 }
1357
1358 fn language_server_ids_for_project_path(
1359 &self,
1360 project_path: ProjectPath,
1361 language: &Language,
1362 cx: &mut App,
1363 ) -> Vec<LanguageServerId> {
1364 let Some(worktree) = self
1365 .worktree_store
1366 .read(cx)
1367 .worktree_for_id(project_path.worktree_id, cx)
1368 else {
1369 return Vec::new();
1370 };
1371 let delegate: Arc<dyn ManifestDelegate> =
1372 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1373
1374 self.lsp_tree
1375 .get(
1376 project_path,
1377 language.name(),
1378 language.manifest(),
1379 &delegate,
1380 cx,
1381 )
1382 .collect::<Vec<_>>()
1383 }
1384
1385 fn language_server_ids_for_buffer(
1386 &self,
1387 buffer: &Buffer,
1388 cx: &mut App,
1389 ) -> Vec<LanguageServerId> {
1390 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1391 let worktree_id = file.worktree_id(cx);
1392
1393 let path: Arc<RelPath> = file
1394 .path()
1395 .parent()
1396 .map(Arc::from)
1397 .unwrap_or_else(|| file.path().clone());
1398 let worktree_path = ProjectPath { worktree_id, path };
1399 self.language_server_ids_for_project_path(worktree_path, language, cx)
1400 } else {
1401 Vec::new()
1402 }
1403 }
1404
1405 fn language_servers_for_buffer<'a>(
1406 &'a self,
1407 buffer: &'a Buffer,
1408 cx: &'a mut App,
1409 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1410 self.language_server_ids_for_buffer(buffer, cx)
1411 .into_iter()
1412 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1413 LanguageServerState::Running {
1414 adapter, server, ..
1415 } => Some((adapter, server)),
1416 _ => None,
1417 })
1418 }
1419
1420 async fn execute_code_action_kind_locally(
1421 lsp_store: WeakEntity<LspStore>,
1422 mut buffers: Vec<Entity<Buffer>>,
1423 kind: CodeActionKind,
1424 push_to_history: bool,
1425 cx: &mut AsyncApp,
1426 ) -> anyhow::Result<ProjectTransaction> {
1427 // Do not allow multiple concurrent code actions requests for the
1428 // same buffer.
1429 lsp_store.update(cx, |this, cx| {
1430 let this = this.as_local_mut().unwrap();
1431 buffers.retain(|buffer| {
1432 this.buffers_being_formatted
1433 .insert(buffer.read(cx).remote_id())
1434 });
1435 })?;
1436 let _cleanup = defer({
1437 let this = lsp_store.clone();
1438 let mut cx = cx.clone();
1439 let buffers = &buffers;
1440 move || {
1441 this.update(&mut cx, |this, cx| {
1442 let this = this.as_local_mut().unwrap();
1443 for buffer in buffers {
1444 this.buffers_being_formatted
1445 .remove(&buffer.read(cx).remote_id());
1446 }
1447 })
1448 .ok();
1449 }
1450 });
1451 let mut project_transaction = ProjectTransaction::default();
1452
1453 for buffer in &buffers {
1454 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1455 buffer.update(cx, |buffer, cx| {
1456 lsp_store
1457 .as_local()
1458 .unwrap()
1459 .language_servers_for_buffer(buffer, cx)
1460 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1461 .collect::<Vec<_>>()
1462 })
1463 })?;
1464 for (_, language_server) in adapters_and_servers.iter() {
1465 let actions = Self::get_server_code_actions_from_action_kinds(
1466 &lsp_store,
1467 language_server.server_id(),
1468 vec![kind.clone()],
1469 buffer,
1470 cx,
1471 )
1472 .await?;
1473 Self::execute_code_actions_on_server(
1474 &lsp_store,
1475 language_server,
1476 actions,
1477 push_to_history,
1478 &mut project_transaction,
1479 cx,
1480 )
1481 .await?;
1482 }
1483 }
1484 Ok(project_transaction)
1485 }
1486
1487 async fn format_locally(
1488 lsp_store: WeakEntity<LspStore>,
1489 mut buffers: Vec<FormattableBuffer>,
1490 push_to_history: bool,
1491 trigger: FormatTrigger,
1492 logger: zlog::Logger,
1493 cx: &mut AsyncApp,
1494 ) -> anyhow::Result<ProjectTransaction> {
1495 // Do not allow multiple concurrent formatting requests for the
1496 // same buffer.
1497 lsp_store.update(cx, |this, cx| {
1498 let this = this.as_local_mut().unwrap();
1499 buffers.retain(|buffer| {
1500 this.buffers_being_formatted
1501 .insert(buffer.handle.read(cx).remote_id())
1502 });
1503 })?;
1504
1505 let _cleanup = defer({
1506 let this = lsp_store.clone();
1507 let mut cx = cx.clone();
1508 let buffers = &buffers;
1509 move || {
1510 this.update(&mut cx, |this, cx| {
1511 let this = this.as_local_mut().unwrap();
1512 for buffer in buffers {
1513 this.buffers_being_formatted
1514 .remove(&buffer.handle.read(cx).remote_id());
1515 }
1516 })
1517 .ok();
1518 }
1519 });
1520
1521 let mut project_transaction = ProjectTransaction::default();
1522
1523 for buffer in &buffers {
1524 zlog::debug!(
1525 logger =>
1526 "formatting buffer '{:?}'",
1527 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1528 );
1529 // Create an empty transaction to hold all of the formatting edits.
1530 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1531 // ensure no transactions created while formatting are
1532 // grouped with the previous transaction in the history
1533 // based on the transaction group interval
1534 buffer.finalize_last_transaction();
1535 buffer
1536 .start_transaction()
1537 .context("transaction already open")?;
1538 buffer.end_transaction(cx);
1539 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1540 buffer.finalize_last_transaction();
1541 anyhow::Ok(transaction_id)
1542 })?;
1543
1544 let result = Self::format_buffer_locally(
1545 lsp_store.clone(),
1546 buffer,
1547 formatting_transaction_id,
1548 trigger,
1549 logger,
1550 cx,
1551 )
1552 .await;
1553
1554 buffer.handle.update(cx, |buffer, cx| {
1555 let Some(formatting_transaction) =
1556 buffer.get_transaction(formatting_transaction_id).cloned()
1557 else {
1558 zlog::warn!(logger => "no formatting transaction");
1559 return;
1560 };
1561 if formatting_transaction.edit_ids.is_empty() {
1562 zlog::debug!(logger => "no changes made while formatting");
1563 buffer.forget_transaction(formatting_transaction_id);
1564 return;
1565 }
1566 if !push_to_history {
1567 zlog::trace!(logger => "forgetting format transaction");
1568 buffer.forget_transaction(formatting_transaction.id);
1569 }
1570 project_transaction
1571 .0
1572 .insert(cx.entity(), formatting_transaction);
1573 });
1574
1575 result?;
1576 }
1577
1578 Ok(project_transaction)
1579 }
1580
1581 async fn format_buffer_locally(
1582 lsp_store: WeakEntity<LspStore>,
1583 buffer: &FormattableBuffer,
1584 formatting_transaction_id: clock::Lamport,
1585 trigger: FormatTrigger,
1586 logger: zlog::Logger,
1587 cx: &mut AsyncApp,
1588 ) -> Result<()> {
1589 let (adapters_and_servers, settings, request_timeout) =
1590 lsp_store.update(cx, |lsp_store, cx| {
1591 buffer.handle.update(cx, |buffer, cx| {
1592 let adapters_and_servers = lsp_store
1593 .as_local()
1594 .unwrap()
1595 .language_servers_for_buffer(buffer, cx)
1596 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1597 .collect::<Vec<_>>();
1598 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1599 let request_timeout = ProjectSettings::get_global(cx)
1600 .global_lsp_settings
1601 .get_request_timeout();
1602 (adapters_and_servers, settings, request_timeout)
1603 })
1604 })?;
1605
1606 // handle whitespace formatting
1607 if settings.remove_trailing_whitespace_on_save {
1608 zlog::trace!(logger => "removing trailing whitespace");
1609 let diff = buffer
1610 .handle
1611 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1612 .await;
1613 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1614 buffer.apply_diff(diff, cx);
1615 })?;
1616 }
1617
1618 if settings.ensure_final_newline_on_save {
1619 zlog::trace!(logger => "ensuring final newline");
1620 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1621 buffer.ensure_final_newline(cx);
1622 })?;
1623 }
1624
1625 // Formatter for `code_actions_on_format` that runs before
1626 // the rest of the formatters
1627 let mut code_actions_on_format_formatters = None;
1628 let should_run_code_actions_on_format = !matches!(
1629 (trigger, &settings.format_on_save),
1630 (FormatTrigger::Save, &FormatOnSave::Off)
1631 );
1632 if should_run_code_actions_on_format {
1633 let have_code_actions_to_run_on_format = settings
1634 .code_actions_on_format
1635 .values()
1636 .any(|enabled| *enabled);
1637 if have_code_actions_to_run_on_format {
1638 zlog::trace!(logger => "going to run code actions on format");
1639 code_actions_on_format_formatters = Some(
1640 settings
1641 .code_actions_on_format
1642 .iter()
1643 .filter_map(|(action, enabled)| enabled.then_some(action))
1644 .cloned()
1645 .map(Formatter::CodeAction)
1646 .collect::<Vec<_>>(),
1647 );
1648 }
1649 }
1650
1651 let formatters = match (trigger, &settings.format_on_save) {
1652 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1653 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1654 settings.formatter.as_ref()
1655 }
1656 };
1657
1658 let formatters = code_actions_on_format_formatters
1659 .iter()
1660 .flatten()
1661 .chain(formatters);
1662
1663 for formatter in formatters {
1664 let formatter = if formatter == &Formatter::Auto {
1665 if settings.prettier.allowed {
1666 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1667 &Formatter::Prettier
1668 } else {
1669 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1670 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1671 }
1672 } else {
1673 formatter
1674 };
1675 if let Err(err) = Self::apply_formatter(
1676 formatter,
1677 &lsp_store,
1678 buffer,
1679 formatting_transaction_id,
1680 &adapters_and_servers,
1681 &settings,
1682 request_timeout,
1683 logger,
1684 cx,
1685 )
1686 .await
1687 {
1688 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1689 }
1690 }
1691
1692 Ok(())
1693 }
1694
1695 async fn apply_formatter(
1696 formatter: &Formatter,
1697 lsp_store: &WeakEntity<LspStore>,
1698 buffer: &FormattableBuffer,
1699 formatting_transaction_id: clock::Lamport,
1700 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1701 settings: &LanguageSettings,
1702 request_timeout: Duration,
1703 logger: zlog::Logger,
1704 cx: &mut AsyncApp,
1705 ) -> anyhow::Result<()> {
1706 match formatter {
1707 Formatter::None => {
1708 zlog::trace!(logger => "skipping formatter 'none'");
1709 return Ok(());
1710 }
1711 Formatter::Auto => {
1712 debug_panic!("Auto resolved above");
1713 return Ok(());
1714 }
1715 Formatter::Prettier => {
1716 let logger = zlog::scoped!(logger => "prettier");
1717 zlog::trace!(logger => "formatting");
1718 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1719
1720 // When selection ranges are provided (via FormatSelections), we pass the
1721 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1722 // After diffing, we filter the resulting edits to only keep those that
1723 // overlap with the original byte-level selection ranges.
1724 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1725 Some(ranges) if !ranges.is_empty() => {
1726 let (utf16_range, byte_ranges) =
1727 buffer.handle.read_with(cx, |buffer, _cx| {
1728 let snapshot = buffer.snapshot();
1729 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1730 let mut max_end_utf16 = OffsetUtf16(0);
1731 let mut byte_ranges = Vec::with_capacity(ranges.len());
1732 for range in ranges {
1733 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1734 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1735 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1736 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1737
1738 let start_byte = range.start.to_offset(&snapshot);
1739 let end_byte = range.end.to_offset(&snapshot);
1740 byte_ranges.push(start_byte..end_byte);
1741 }
1742 (min_start_utf16..max_end_utf16, byte_ranges)
1743 });
1744 (Some(utf16_range), Some(byte_ranges))
1745 }
1746 _ => (None, None),
1747 };
1748
1749 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1750 lsp_store.prettier_store().unwrap().downgrade()
1751 })?;
1752 let diff = prettier_store::format_with_prettier(
1753 &prettier,
1754 &buffer.handle,
1755 range_utf16,
1756 cx,
1757 )
1758 .await
1759 .transpose()?;
1760 let Some(mut diff) = diff else {
1761 zlog::trace!(logger => "No changes");
1762 return Ok(());
1763 };
1764
1765 if let Some(byte_ranges) = byte_ranges {
1766 diff.edits.retain(|(edit_range, _)| {
1767 byte_ranges.iter().any(|selection_range| {
1768 edit_range.start < selection_range.end
1769 && edit_range.end > selection_range.start
1770 })
1771 });
1772 if diff.edits.is_empty() {
1773 zlog::trace!(logger => "No changes within selection");
1774 return Ok(());
1775 }
1776 }
1777
1778 extend_formatting_transaction(
1779 buffer,
1780 formatting_transaction_id,
1781 cx,
1782 |buffer, cx| {
1783 buffer.apply_diff(diff, cx);
1784 },
1785 )?;
1786 }
1787 Formatter::External { command, arguments } => {
1788 let logger = zlog::scoped!(logger => "command");
1789
1790 if buffer.ranges.is_some() {
1791 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1792 return Ok(());
1793 }
1794
1795 zlog::trace!(logger => "formatting");
1796 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1797
1798 let diff =
1799 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1800 .await
1801 .with_context(|| {
1802 format!("Failed to format buffer via external command: {}", command)
1803 })?;
1804 let Some(diff) = diff else {
1805 zlog::trace!(logger => "No changes");
1806 return Ok(());
1807 };
1808
1809 extend_formatting_transaction(
1810 buffer,
1811 formatting_transaction_id,
1812 cx,
1813 |buffer, cx| {
1814 buffer.apply_diff(diff, cx);
1815 },
1816 )?;
1817 }
1818 Formatter::LanguageServer(specifier) => {
1819 let logger = zlog::scoped!(logger => "language-server");
1820 zlog::trace!(logger => "formatting");
1821 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1822
1823 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1824 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1825 return Ok(());
1826 };
1827
1828 let language_server = match specifier {
1829 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1830 adapters_and_servers.iter().find_map(|(adapter, server)| {
1831 if adapter.name.0.as_ref() == name {
1832 Some(server.clone())
1833 } else {
1834 None
1835 }
1836 })
1837 }
1838 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1839 .iter()
1840 .find(|(_, server)| Self::server_supports_formatting(server))
1841 .map(|(_, server)| server.clone()),
1842 };
1843
1844 let Some(language_server) = language_server else {
1845 log::debug!(
1846 "No language server found to format buffer '{:?}'. Skipping",
1847 buffer_path_abs.as_path().to_string_lossy()
1848 );
1849 return Ok(());
1850 };
1851
1852 zlog::trace!(
1853 logger =>
1854 "Formatting buffer '{:?}' using language server '{:?}'",
1855 buffer_path_abs.as_path().to_string_lossy(),
1856 language_server.name()
1857 );
1858
1859 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1860 zlog::trace!(logger => "formatting ranges");
1861 Self::format_ranges_via_lsp(
1862 &lsp_store,
1863 &buffer.handle,
1864 ranges,
1865 buffer_path_abs,
1866 &language_server,
1867 &settings,
1868 cx,
1869 )
1870 .await
1871 .context("Failed to format ranges via language server")?
1872 } else {
1873 zlog::trace!(logger => "formatting full");
1874 Self::format_via_lsp(
1875 &lsp_store,
1876 &buffer.handle,
1877 buffer_path_abs,
1878 &language_server,
1879 &settings,
1880 cx,
1881 )
1882 .await
1883 .context("failed to format via language server")?
1884 };
1885
1886 if edits.is_empty() {
1887 zlog::trace!(logger => "No changes");
1888 return Ok(());
1889 }
1890 extend_formatting_transaction(
1891 buffer,
1892 formatting_transaction_id,
1893 cx,
1894 |buffer, cx| {
1895 buffer.edit(edits, None, cx);
1896 },
1897 )?;
1898 }
1899 Formatter::CodeAction(code_action_name) => {
1900 let logger = zlog::scoped!(logger => "code-actions");
1901 zlog::trace!(logger => "formatting");
1902 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1903
1904 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1905 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1906 return Ok(());
1907 };
1908
1909 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1910 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1911
1912 let mut actions_and_servers = Vec::new();
1913
1914 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1915 let actions_result = Self::get_server_code_actions_from_action_kinds(
1916 &lsp_store,
1917 language_server.server_id(),
1918 vec![code_action_kind.clone()],
1919 &buffer.handle,
1920 cx,
1921 )
1922 .await
1923 .with_context(|| {
1924 format!(
1925 "Failed to resolve code action {:?} with language server {}",
1926 code_action_kind,
1927 language_server.name()
1928 )
1929 });
1930 let Ok(actions) = actions_result else {
1931 // note: it may be better to set result to the error and break formatters here
1932 // but for now we try to execute the actions that we can resolve and skip the rest
1933 zlog::error!(
1934 logger =>
1935 "Failed to resolve code action {:?} with language server {}",
1936 code_action_kind,
1937 language_server.name()
1938 );
1939 continue;
1940 };
1941 for action in actions {
1942 actions_and_servers.push((action, index));
1943 }
1944 }
1945
1946 if actions_and_servers.is_empty() {
1947 zlog::warn!(logger => "No code actions were resolved, continuing");
1948 return Ok(());
1949 }
1950
1951 'actions: for (mut action, server_index) in actions_and_servers {
1952 let server = &adapters_and_servers[server_index].1;
1953
1954 let describe_code_action = |action: &CodeAction| {
1955 format!(
1956 "code action '{}' with title \"{}\" on server {}",
1957 action
1958 .lsp_action
1959 .action_kind()
1960 .unwrap_or("unknown".into())
1961 .as_str(),
1962 action.lsp_action.title(),
1963 server.name(),
1964 )
1965 };
1966
1967 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1968
1969 if let Err(err) =
1970 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1971 {
1972 zlog::error!(
1973 logger =>
1974 "Failed to resolve {}. Error: {}",
1975 describe_code_action(&action),
1976 err
1977 );
1978 continue;
1979 }
1980
1981 if let Some(edit) = action.lsp_action.edit().cloned() {
1982 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1983 // but filters out and logs warnings for code actions that require unreasonably
1984 // difficult handling on our part, such as:
1985 // - applying edits that call commands
1986 // which can result in arbitrary workspace edits being sent from the server that
1987 // have no way of being tied back to the command that initiated them (i.e. we
1988 // can't know which edits are part of the format request, or if the server is done sending
1989 // actions in response to the command)
1990 // - actions that create/delete/modify/rename files other than the one we are formatting
1991 // as we then would need to handle such changes correctly in the local history as well
1992 // as the remote history through the ProjectTransaction
1993 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1994 // Supporting these actions is not impossible, but not supported as of yet.
1995 if edit.changes.is_none() && edit.document_changes.is_none() {
1996 zlog::trace!(
1997 logger =>
1998 "No changes for code action. Skipping {}",
1999 describe_code_action(&action),
2000 );
2001 continue;
2002 }
2003
2004 let mut operations = Vec::new();
2005 if let Some(document_changes) = edit.document_changes {
2006 match document_changes {
2007 lsp::DocumentChanges::Edits(edits) => operations.extend(
2008 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2009 ),
2010 lsp::DocumentChanges::Operations(ops) => operations = ops,
2011 }
2012 } else if let Some(changes) = edit.changes {
2013 operations.extend(changes.into_iter().map(|(uri, edits)| {
2014 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2015 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2016 uri,
2017 version: None,
2018 },
2019 edits: edits.into_iter().map(Edit::Plain).collect(),
2020 })
2021 }));
2022 }
2023
2024 let mut edits = Vec::with_capacity(operations.len());
2025
2026 if operations.is_empty() {
2027 zlog::trace!(
2028 logger =>
2029 "No changes for code action. Skipping {}",
2030 describe_code_action(&action),
2031 );
2032 continue;
2033 }
2034 for operation in operations {
2035 let op = match operation {
2036 lsp::DocumentChangeOperation::Edit(op) => op,
2037 lsp::DocumentChangeOperation::Op(_) => {
2038 zlog::warn!(
2039 logger =>
2040 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2041 describe_code_action(&action),
2042 );
2043 continue 'actions;
2044 }
2045 };
2046 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2047 zlog::warn!(
2048 logger =>
2049 "Failed to convert URI '{:?}' to file path. Skipping {}",
2050 &op.text_document.uri,
2051 describe_code_action(&action),
2052 );
2053 continue 'actions;
2054 };
2055 if &file_path != buffer_path_abs {
2056 zlog::warn!(
2057 logger =>
2058 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2059 file_path,
2060 buffer_path_abs,
2061 describe_code_action(&action),
2062 );
2063 continue 'actions;
2064 }
2065
2066 let mut lsp_edits = Vec::new();
2067 for edit in op.edits {
2068 match edit {
2069 Edit::Plain(edit) => {
2070 if !lsp_edits.contains(&edit) {
2071 lsp_edits.push(edit);
2072 }
2073 }
2074 Edit::Annotated(edit) => {
2075 if !lsp_edits.contains(&edit.text_edit) {
2076 lsp_edits.push(edit.text_edit);
2077 }
2078 }
2079 Edit::Snippet(_) => {
2080 zlog::warn!(
2081 logger =>
2082 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2083 describe_code_action(&action),
2084 );
2085 continue 'actions;
2086 }
2087 }
2088 }
2089 let edits_result = lsp_store
2090 .update(cx, |lsp_store, cx| {
2091 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2092 &buffer.handle,
2093 lsp_edits,
2094 server.server_id(),
2095 op.text_document.version,
2096 cx,
2097 )
2098 })?
2099 .await;
2100 let Ok(resolved_edits) = edits_result else {
2101 zlog::warn!(
2102 logger =>
2103 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2104 buffer_path_abs.as_path(),
2105 describe_code_action(&action),
2106 );
2107 continue 'actions;
2108 };
2109 edits.extend(resolved_edits);
2110 }
2111
2112 if edits.is_empty() {
2113 zlog::warn!(logger => "No edits resolved from LSP");
2114 continue;
2115 }
2116
2117 extend_formatting_transaction(
2118 buffer,
2119 formatting_transaction_id,
2120 cx,
2121 |buffer, cx| {
2122 zlog::info!(
2123 "Applying edits {edits:?}. Content: {:?}",
2124 buffer.text()
2125 );
2126 buffer.edit(edits, None, cx);
2127 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2128 },
2129 )?;
2130 }
2131
2132 let Some(command) = action.lsp_action.command() else {
2133 continue;
2134 };
2135
2136 zlog::warn!(
2137 logger =>
2138 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2139 &command.command,
2140 );
2141
2142 let server_capabilities = server.capabilities();
2143 let available_commands = server_capabilities
2144 .execute_command_provider
2145 .as_ref()
2146 .map(|options| options.commands.as_slice())
2147 .unwrap_or_default();
2148 if !available_commands.contains(&command.command) {
2149 zlog::warn!(
2150 logger =>
2151 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2152 command.command,
2153 server.name(),
2154 );
2155 continue;
2156 }
2157
2158 extend_formatting_transaction(
2159 buffer,
2160 formatting_transaction_id,
2161 cx,
2162 |_, _| {},
2163 )?;
2164 zlog::info!(logger => "Executing command {}", &command.command);
2165
2166 lsp_store.update(cx, |this, _| {
2167 this.as_local_mut()
2168 .unwrap()
2169 .last_workspace_edits_by_language_server
2170 .remove(&server.server_id());
2171 })?;
2172
2173 let execute_command_result = server
2174 .request::<lsp::request::ExecuteCommand>(
2175 lsp::ExecuteCommandParams {
2176 command: command.command.clone(),
2177 arguments: command.arguments.clone().unwrap_or_default(),
2178 ..Default::default()
2179 },
2180 request_timeout,
2181 )
2182 .await
2183 .into_response();
2184
2185 if execute_command_result.is_err() {
2186 zlog::error!(
2187 logger =>
2188 "Failed to execute command '{}' as part of {}",
2189 &command.command,
2190 describe_code_action(&action),
2191 );
2192 continue 'actions;
2193 }
2194
2195 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2196 this.as_local_mut()
2197 .unwrap()
2198 .last_workspace_edits_by_language_server
2199 .remove(&server.server_id())
2200 .unwrap_or_default()
2201 })?;
2202
2203 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2204 {
2205 zlog::trace!(
2206 logger =>
2207 "Successfully captured {} edits that resulted from command {}",
2208 transaction.edit_ids.len(),
2209 &command.command,
2210 );
2211 let transaction_id_project_transaction = transaction.id;
2212 buffer.handle.update(cx, |buffer, _| {
2213 // it may have been removed from history if push_to_history was
2214 // false in deserialize_workspace_edit. If so push it so we
2215 // can merge it with the format transaction
2216 // and pop the combined transaction off the history stack
2217 // later if push_to_history is false
2218 if buffer.get_transaction(transaction.id).is_none() {
2219 buffer.push_transaction(transaction, Instant::now());
2220 }
2221 buffer.merge_transactions(
2222 transaction_id_project_transaction,
2223 formatting_transaction_id,
2224 );
2225 });
2226 }
2227
2228 if project_transaction_command.0.is_empty() {
2229 continue;
2230 }
2231
2232 let mut extra_buffers = String::new();
2233 for buffer in project_transaction_command.0.keys() {
2234 buffer.read_with(cx, |b, cx| {
2235 let Some(path) = b.project_path(cx) else {
2236 return;
2237 };
2238
2239 if !extra_buffers.is_empty() {
2240 extra_buffers.push_str(", ");
2241 }
2242 extra_buffers.push_str(path.path.as_unix_str());
2243 });
2244 }
2245 zlog::warn!(
2246 logger =>
2247 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2248 &command.command,
2249 extra_buffers,
2250 );
2251 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2252 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2253 // add it so it's included, and merge it into the format transaction when its created later
2254 }
2255 }
2256 }
2257
2258 Ok(())
2259 }
2260
2261 pub async fn format_ranges_via_lsp(
2262 this: &WeakEntity<LspStore>,
2263 buffer_handle: &Entity<Buffer>,
2264 ranges: &[Range<Anchor>],
2265 abs_path: &Path,
2266 language_server: &Arc<LanguageServer>,
2267 settings: &LanguageSettings,
2268 cx: &mut AsyncApp,
2269 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2270 let capabilities = &language_server.capabilities();
2271 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2272 if range_formatting_provider == Some(&OneOf::Left(false)) {
2273 anyhow::bail!(
2274 "{} language server does not support range formatting",
2275 language_server.name()
2276 );
2277 }
2278
2279 let uri = file_path_to_lsp_url(abs_path)?;
2280 let text_document = lsp::TextDocumentIdentifier::new(uri);
2281
2282 let request_timeout = cx.update(|app| {
2283 ProjectSettings::get_global(app)
2284 .global_lsp_settings
2285 .get_request_timeout()
2286 });
2287 let lsp_edits = {
2288 let mut lsp_ranges = Vec::new();
2289 this.update(cx, |_this, cx| {
2290 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2291 // not have been sent to the language server. This seems like a fairly systemic
2292 // issue, though, the resolution probably is not specific to formatting.
2293 //
2294 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2295 // LSP.
2296 let snapshot = buffer_handle.read(cx).snapshot();
2297 for range in ranges {
2298 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2299 }
2300 anyhow::Ok(())
2301 })??;
2302
2303 let mut edits = None;
2304 for range in lsp_ranges {
2305 if let Some(mut edit) = language_server
2306 .request::<lsp::request::RangeFormatting>(
2307 lsp::DocumentRangeFormattingParams {
2308 text_document: text_document.clone(),
2309 range,
2310 options: lsp_command::lsp_formatting_options(settings),
2311 work_done_progress_params: Default::default(),
2312 },
2313 request_timeout,
2314 )
2315 .await
2316 .into_response()?
2317 {
2318 edits.get_or_insert_with(Vec::new).append(&mut edit);
2319 }
2320 }
2321 edits
2322 };
2323
2324 if let Some(lsp_edits) = lsp_edits {
2325 this.update(cx, |this, cx| {
2326 this.as_local_mut().unwrap().edits_from_lsp(
2327 buffer_handle,
2328 lsp_edits,
2329 language_server.server_id(),
2330 None,
2331 cx,
2332 )
2333 })?
2334 .await
2335 } else {
2336 Ok(Vec::with_capacity(0))
2337 }
2338 }
2339
2340 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2341 let capabilities = server.capabilities();
2342 let formatting = capabilities.document_formatting_provider.as_ref();
2343 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2344 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2345 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2346 }
2347
2348 async fn format_via_lsp(
2349 this: &WeakEntity<LspStore>,
2350 buffer: &Entity<Buffer>,
2351 abs_path: &Path,
2352 language_server: &Arc<LanguageServer>,
2353 settings: &LanguageSettings,
2354 cx: &mut AsyncApp,
2355 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2356 let logger = zlog::scoped!("lsp_format");
2357 zlog::debug!(logger => "Formatting via LSP");
2358
2359 let uri = file_path_to_lsp_url(abs_path)?;
2360 let text_document = lsp::TextDocumentIdentifier::new(uri);
2361 let capabilities = &language_server.capabilities();
2362
2363 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2364 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2365
2366 let request_timeout = cx.update(|app| {
2367 ProjectSettings::get_global(app)
2368 .global_lsp_settings
2369 .get_request_timeout()
2370 });
2371
2372 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2373 let _timer = zlog::time!(logger => "format-full");
2374 language_server
2375 .request::<lsp::request::Formatting>(
2376 lsp::DocumentFormattingParams {
2377 text_document,
2378 options: lsp_command::lsp_formatting_options(settings),
2379 work_done_progress_params: Default::default(),
2380 },
2381 request_timeout,
2382 )
2383 .await
2384 .into_response()?
2385 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2386 let _timer = zlog::time!(logger => "format-range");
2387 let buffer_start = lsp::Position::new(0, 0);
2388 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2389 language_server
2390 .request::<lsp::request::RangeFormatting>(
2391 lsp::DocumentRangeFormattingParams {
2392 text_document: text_document.clone(),
2393 range: lsp::Range::new(buffer_start, buffer_end),
2394 options: lsp_command::lsp_formatting_options(settings),
2395 work_done_progress_params: Default::default(),
2396 },
2397 request_timeout,
2398 )
2399 .await
2400 .into_response()?
2401 } else {
2402 None
2403 };
2404
2405 if let Some(lsp_edits) = lsp_edits {
2406 this.update(cx, |this, cx| {
2407 this.as_local_mut().unwrap().edits_from_lsp(
2408 buffer,
2409 lsp_edits,
2410 language_server.server_id(),
2411 None,
2412 cx,
2413 )
2414 })?
2415 .await
2416 } else {
2417 Ok(Vec::with_capacity(0))
2418 }
2419 }
2420
2421 async fn format_via_external_command(
2422 buffer: &FormattableBuffer,
2423 command: &str,
2424 arguments: Option<&[String]>,
2425 cx: &mut AsyncApp,
2426 ) -> Result<Option<Diff>> {
2427 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2428 let file = File::from_dyn(buffer.file())?;
2429 let worktree = file.worktree.read(cx);
2430 let mut worktree_path = worktree.abs_path().to_path_buf();
2431 if worktree.root_entry()?.is_file() {
2432 worktree_path.pop();
2433 }
2434 Some(worktree_path)
2435 });
2436
2437 use util::command::Stdio;
2438 let mut child = util::command::new_command(command);
2439
2440 if let Some(buffer_env) = buffer.env.as_ref() {
2441 child.envs(buffer_env);
2442 }
2443
2444 if let Some(working_dir_path) = working_dir_path {
2445 child.current_dir(working_dir_path);
2446 }
2447
2448 if let Some(arguments) = arguments {
2449 child.args(arguments.iter().map(|arg| {
2450 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2451 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2452 } else {
2453 arg.replace("{buffer_path}", "Untitled")
2454 }
2455 }));
2456 }
2457
2458 let mut child = child
2459 .stdin(Stdio::piped())
2460 .stdout(Stdio::piped())
2461 .stderr(Stdio::piped())
2462 .spawn()?;
2463
2464 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2465 let text = buffer
2466 .handle
2467 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2468 for chunk in text.chunks() {
2469 stdin.write_all(chunk.as_bytes()).await?;
2470 }
2471 stdin.flush().await?;
2472
2473 let output = child.output().await?;
2474 anyhow::ensure!(
2475 output.status.success(),
2476 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2477 output.status.code(),
2478 String::from_utf8_lossy(&output.stdout),
2479 String::from_utf8_lossy(&output.stderr),
2480 );
2481
2482 let stdout = String::from_utf8(output.stdout)?;
2483 Ok(Some(
2484 buffer
2485 .handle
2486 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2487 .await,
2488 ))
2489 }
2490
2491 async fn try_resolve_code_action(
2492 lang_server: &LanguageServer,
2493 action: &mut CodeAction,
2494 request_timeout: Duration,
2495 ) -> anyhow::Result<()> {
2496 match &mut action.lsp_action {
2497 LspAction::Action(lsp_action) => {
2498 if !action.resolved
2499 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2500 && lsp_action.data.is_some()
2501 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2502 {
2503 **lsp_action = lang_server
2504 .request::<lsp::request::CodeActionResolveRequest>(
2505 *lsp_action.clone(),
2506 request_timeout,
2507 )
2508 .await
2509 .into_response()?;
2510 }
2511 }
2512 LspAction::CodeLens(lens) => {
2513 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2514 *lens = lang_server
2515 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2516 .await
2517 .into_response()?;
2518 }
2519 }
2520 LspAction::Command(_) => {}
2521 }
2522
2523 action.resolved = true;
2524 anyhow::Ok(())
2525 }
2526
2527 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2528 let buffer = buffer_handle.read(cx);
2529
2530 let file = buffer.file().cloned();
2531
2532 let Some(file) = File::from_dyn(file.as_ref()) else {
2533 return;
2534 };
2535 if !file.is_local() {
2536 return;
2537 }
2538 let path = ProjectPath::from_file(file, cx);
2539 let worktree_id = file.worktree_id(cx);
2540 let language = buffer.language().cloned();
2541
2542 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2543 for (server_id, diagnostics) in
2544 diagnostics.get(file.path()).cloned().unwrap_or_default()
2545 {
2546 self.update_buffer_diagnostics(
2547 buffer_handle,
2548 server_id,
2549 None,
2550 None,
2551 None,
2552 Vec::new(),
2553 diagnostics,
2554 cx,
2555 )
2556 .log_err();
2557 }
2558 }
2559 let Some(language) = language else {
2560 return;
2561 };
2562 let Some(snapshot) = self
2563 .worktree_store
2564 .read(cx)
2565 .worktree_for_id(worktree_id, cx)
2566 .map(|worktree| worktree.read(cx).snapshot())
2567 else {
2568 return;
2569 };
2570 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2571
2572 for server_id in
2573 self.lsp_tree
2574 .get(path, language.name(), language.manifest(), &delegate, cx)
2575 {
2576 let server = self
2577 .language_servers
2578 .get(&server_id)
2579 .and_then(|server_state| {
2580 if let LanguageServerState::Running { server, .. } = server_state {
2581 Some(server.clone())
2582 } else {
2583 None
2584 }
2585 });
2586 let server = match server {
2587 Some(server) => server,
2588 None => continue,
2589 };
2590
2591 buffer_handle.update(cx, |buffer, cx| {
2592 buffer.set_completion_triggers(
2593 server.server_id(),
2594 server
2595 .capabilities()
2596 .completion_provider
2597 .as_ref()
2598 .and_then(|provider| {
2599 provider
2600 .trigger_characters
2601 .as_ref()
2602 .map(|characters| characters.iter().cloned().collect())
2603 })
2604 .unwrap_or_default(),
2605 cx,
2606 );
2607 });
2608 }
2609 }
2610
2611 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2612 buffer.update(cx, |buffer, cx| {
2613 let Some(language) = buffer.language() else {
2614 return;
2615 };
2616 let path = ProjectPath {
2617 worktree_id: old_file.worktree_id(cx),
2618 path: old_file.path.clone(),
2619 };
2620 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2621 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2622 buffer.set_completion_triggers(server_id, Default::default(), cx);
2623 }
2624 });
2625 }
2626
2627 fn update_buffer_diagnostics(
2628 &mut self,
2629 buffer: &Entity<Buffer>,
2630 server_id: LanguageServerId,
2631 registration_id: Option<Option<SharedString>>,
2632 result_id: Option<SharedString>,
2633 version: Option<i32>,
2634 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2635 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2636 cx: &mut Context<LspStore>,
2637 ) -> Result<()> {
2638 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2639 Ordering::Equal
2640 .then_with(|| b.is_primary.cmp(&a.is_primary))
2641 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2642 .then_with(|| a.severity.cmp(&b.severity))
2643 .then_with(|| a.message.cmp(&b.message))
2644 }
2645
2646 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2647 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2648 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2649
2650 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2651 Ordering::Equal
2652 .then_with(|| a.range.start.cmp(&b.range.start))
2653 .then_with(|| b.range.end.cmp(&a.range.end))
2654 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2655 });
2656
2657 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2658
2659 let edits_since_save = std::cell::LazyCell::new(|| {
2660 let saved_version = buffer.read(cx).saved_version();
2661 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2662 });
2663
2664 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2665
2666 for (new_diagnostic, entry) in diagnostics {
2667 let start;
2668 let end;
2669 if new_diagnostic && entry.diagnostic.is_disk_based {
2670 // Some diagnostics are based on files on disk instead of buffers'
2671 // current contents. Adjust these diagnostics' ranges to reflect
2672 // any unsaved edits.
2673 // Do not alter the reused ones though, as their coordinates were stored as anchors
2674 // and were properly adjusted on reuse.
2675 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2676 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2677 } else {
2678 start = entry.range.start;
2679 end = entry.range.end;
2680 }
2681
2682 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2683 ..snapshot.clip_point_utf16(end, Bias::Right);
2684
2685 // Expand empty ranges by one codepoint
2686 if range.start == range.end {
2687 // This will be go to the next boundary when being clipped
2688 range.end.column += 1;
2689 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2690 if range.start == range.end && range.end.column > 0 {
2691 range.start.column -= 1;
2692 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2693 }
2694 }
2695
2696 sanitized_diagnostics.push(DiagnosticEntry {
2697 range,
2698 diagnostic: entry.diagnostic,
2699 });
2700 }
2701 drop(edits_since_save);
2702
2703 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2704 buffer.update(cx, |buffer, cx| {
2705 if let Some(registration_id) = registration_id {
2706 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2707 self.buffer_pull_diagnostics_result_ids
2708 .entry(server_id)
2709 .or_default()
2710 .entry(registration_id)
2711 .or_default()
2712 .insert(abs_path, result_id);
2713 }
2714 }
2715
2716 buffer.update_diagnostics(server_id, set, cx)
2717 });
2718
2719 Ok(())
2720 }
2721
2722 fn register_language_server_for_invisible_worktree(
2723 &mut self,
2724 worktree: &Entity<Worktree>,
2725 language_server_id: LanguageServerId,
2726 cx: &mut App,
2727 ) {
2728 let worktree = worktree.read(cx);
2729 let worktree_id = worktree.id();
2730 debug_assert!(!worktree.is_visible());
2731 let Some(mut origin_seed) = self
2732 .language_server_ids
2733 .iter()
2734 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2735 else {
2736 return;
2737 };
2738 origin_seed.worktree_id = worktree_id;
2739 self.language_server_ids
2740 .entry(origin_seed)
2741 .or_insert_with(|| UnifiedLanguageServer {
2742 id: language_server_id,
2743 project_roots: Default::default(),
2744 });
2745 }
2746
2747 fn register_buffer_with_language_servers(
2748 &mut self,
2749 buffer_handle: &Entity<Buffer>,
2750 only_register_servers: HashSet<LanguageServerSelector>,
2751 cx: &mut Context<LspStore>,
2752 ) {
2753 let buffer = buffer_handle.read(cx);
2754 let buffer_id = buffer.remote_id();
2755
2756 let Some(file) = File::from_dyn(buffer.file()) else {
2757 return;
2758 };
2759 if !file.is_local() {
2760 return;
2761 }
2762
2763 let abs_path = file.abs_path(cx);
2764 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2765 return;
2766 };
2767 let initial_snapshot = buffer.text_snapshot();
2768 let worktree_id = file.worktree_id(cx);
2769
2770 let Some(language) = buffer.language().cloned() else {
2771 return;
2772 };
2773 let path: Arc<RelPath> = file
2774 .path()
2775 .parent()
2776 .map(Arc::from)
2777 .unwrap_or_else(|| file.path().clone());
2778 let Some(worktree) = self
2779 .worktree_store
2780 .read(cx)
2781 .worktree_for_id(worktree_id, cx)
2782 else {
2783 return;
2784 };
2785 let language_name = language.name();
2786 let (reused, delegate, servers) = self
2787 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2788 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2789 .unwrap_or_else(|| {
2790 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2791 let delegate: Arc<dyn ManifestDelegate> =
2792 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2793
2794 let servers = self
2795 .lsp_tree
2796 .walk(
2797 ProjectPath { worktree_id, path },
2798 language.name(),
2799 language.manifest(),
2800 &delegate,
2801 cx,
2802 )
2803 .collect::<Vec<_>>();
2804 (false, lsp_delegate, servers)
2805 });
2806 let servers_and_adapters = servers
2807 .into_iter()
2808 .filter_map(|server_node| {
2809 if reused && server_node.server_id().is_none() {
2810 return None;
2811 }
2812 if !only_register_servers.is_empty() {
2813 if let Some(server_id) = server_node.server_id()
2814 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2815 {
2816 return None;
2817 }
2818 if let Some(name) = server_node.name()
2819 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2820 {
2821 return None;
2822 }
2823 }
2824
2825 let server_id = server_node.server_id_or_init(|disposition| {
2826 let path = &disposition.path;
2827
2828 {
2829 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2830
2831 let server_id = self.get_or_insert_language_server(
2832 &worktree,
2833 delegate.clone(),
2834 disposition,
2835 &language_name,
2836 cx,
2837 );
2838
2839 if let Some(state) = self.language_servers.get(&server_id)
2840 && let Ok(uri) = uri
2841 {
2842 state.add_workspace_folder(uri);
2843 };
2844 server_id
2845 }
2846 })?;
2847 let server_state = self.language_servers.get(&server_id)?;
2848 if let LanguageServerState::Running {
2849 server, adapter, ..
2850 } = server_state
2851 {
2852 Some((server.clone(), adapter.clone()))
2853 } else {
2854 None
2855 }
2856 })
2857 .collect::<Vec<_>>();
2858 for (server, adapter) in servers_and_adapters {
2859 buffer_handle.update(cx, |buffer, cx| {
2860 buffer.set_completion_triggers(
2861 server.server_id(),
2862 server
2863 .capabilities()
2864 .completion_provider
2865 .as_ref()
2866 .and_then(|provider| {
2867 provider
2868 .trigger_characters
2869 .as_ref()
2870 .map(|characters| characters.iter().cloned().collect())
2871 })
2872 .unwrap_or_default(),
2873 cx,
2874 );
2875 });
2876
2877 let snapshot = LspBufferSnapshot {
2878 version: 0,
2879 snapshot: initial_snapshot.clone(),
2880 };
2881
2882 let mut registered = false;
2883 self.buffer_snapshots
2884 .entry(buffer_id)
2885 .or_default()
2886 .entry(server.server_id())
2887 .or_insert_with(|| {
2888 registered = true;
2889 server.register_buffer(
2890 uri.clone(),
2891 adapter.language_id(&language.name()),
2892 0,
2893 initial_snapshot.text(),
2894 );
2895
2896 vec![snapshot]
2897 });
2898
2899 self.buffers_opened_in_servers
2900 .entry(buffer_id)
2901 .or_default()
2902 .insert(server.server_id());
2903 if registered {
2904 cx.emit(LspStoreEvent::LanguageServerUpdate {
2905 language_server_id: server.server_id(),
2906 name: None,
2907 message: proto::update_language_server::Variant::RegisteredForBuffer(
2908 proto::RegisteredForBuffer {
2909 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2910 buffer_id: buffer_id.to_proto(),
2911 },
2912 ),
2913 });
2914 }
2915 }
2916 }
2917
2918 fn reuse_existing_language_server<'lang_name>(
2919 &self,
2920 server_tree: &LanguageServerTree,
2921 worktree: &Entity<Worktree>,
2922 language_name: &'lang_name LanguageName,
2923 cx: &mut App,
2924 ) -> Option<(
2925 Arc<LocalLspAdapterDelegate>,
2926 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2927 )> {
2928 if worktree.read(cx).is_visible() {
2929 return None;
2930 }
2931
2932 let worktree_store = self.worktree_store.read(cx);
2933 let servers = server_tree
2934 .instances
2935 .iter()
2936 .filter(|(worktree_id, _)| {
2937 worktree_store
2938 .worktree_for_id(**worktree_id, cx)
2939 .is_some_and(|worktree| worktree.read(cx).is_visible())
2940 })
2941 .flat_map(|(worktree_id, servers)| {
2942 servers
2943 .roots
2944 .iter()
2945 .flat_map(|(_, language_servers)| language_servers)
2946 .map(move |(_, (server_node, server_languages))| {
2947 (worktree_id, server_node, server_languages)
2948 })
2949 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2950 .map(|(worktree_id, server_node, _)| {
2951 (
2952 *worktree_id,
2953 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2954 )
2955 })
2956 })
2957 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2958 acc.entry(worktree_id)
2959 .or_insert_with(Vec::new)
2960 .push(server_node);
2961 acc
2962 })
2963 .into_values()
2964 .max_by_key(|servers| servers.len())?;
2965
2966 let worktree_id = worktree.read(cx).id();
2967 let apply = move |tree: &mut LanguageServerTree| {
2968 for server_node in &servers {
2969 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2970 }
2971 servers
2972 };
2973
2974 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2975 Some((delegate, apply))
2976 }
2977
2978 pub(crate) fn unregister_old_buffer_from_language_servers(
2979 &mut self,
2980 buffer: &Entity<Buffer>,
2981 old_file: &File,
2982 cx: &mut App,
2983 ) {
2984 let old_path = match old_file.as_local() {
2985 Some(local) => local.abs_path(cx),
2986 None => return,
2987 };
2988
2989 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2990 debug_panic!("{old_path:?} is not parseable as an URI");
2991 return;
2992 };
2993 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2994 }
2995
2996 pub(crate) fn unregister_buffer_from_language_servers(
2997 &mut self,
2998 buffer: &Entity<Buffer>,
2999 file_url: &lsp::Uri,
3000 cx: &mut App,
3001 ) {
3002 buffer.update(cx, |buffer, cx| {
3003 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3004
3005 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3006 if snapshots
3007 .as_mut()
3008 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3009 {
3010 language_server.unregister_buffer(file_url.clone());
3011 }
3012 }
3013 });
3014 }
3015
3016 fn buffer_snapshot_for_lsp_version(
3017 &mut self,
3018 buffer: &Entity<Buffer>,
3019 server_id: LanguageServerId,
3020 version: Option<i32>,
3021 cx: &App,
3022 ) -> Result<TextBufferSnapshot> {
3023 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3024
3025 if let Some(version) = version {
3026 let buffer_id = buffer.read(cx).remote_id();
3027 let snapshots = if let Some(snapshots) = self
3028 .buffer_snapshots
3029 .get_mut(&buffer_id)
3030 .and_then(|m| m.get_mut(&server_id))
3031 {
3032 snapshots
3033 } else if version == 0 {
3034 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3035 // We detect this case and treat it as if the version was `None`.
3036 return Ok(buffer.read(cx).text_snapshot());
3037 } else {
3038 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3039 };
3040
3041 let found_snapshot = snapshots
3042 .binary_search_by_key(&version, |e| e.version)
3043 .map(|ix| snapshots[ix].snapshot.clone())
3044 .map_err(|_| {
3045 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3046 })?;
3047
3048 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3049 Ok(found_snapshot)
3050 } else {
3051 Ok((buffer.read(cx)).text_snapshot())
3052 }
3053 }
3054
3055 async fn get_server_code_actions_from_action_kinds(
3056 lsp_store: &WeakEntity<LspStore>,
3057 language_server_id: LanguageServerId,
3058 code_action_kinds: Vec<lsp::CodeActionKind>,
3059 buffer: &Entity<Buffer>,
3060 cx: &mut AsyncApp,
3061 ) -> Result<Vec<CodeAction>> {
3062 let actions = lsp_store
3063 .update(cx, move |this, cx| {
3064 let request = GetCodeActions {
3065 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3066 kinds: Some(code_action_kinds),
3067 };
3068 let server = LanguageServerToQuery::Other(language_server_id);
3069 this.request_lsp(buffer.clone(), server, request, cx)
3070 })?
3071 .await?;
3072 Ok(actions)
3073 }
3074
3075 pub async fn execute_code_actions_on_server(
3076 lsp_store: &WeakEntity<LspStore>,
3077 language_server: &Arc<LanguageServer>,
3078 actions: Vec<CodeAction>,
3079 push_to_history: bool,
3080 project_transaction: &mut ProjectTransaction,
3081 cx: &mut AsyncApp,
3082 ) -> anyhow::Result<()> {
3083 let request_timeout = cx.update(|app| {
3084 ProjectSettings::get_global(app)
3085 .global_lsp_settings
3086 .get_request_timeout()
3087 });
3088
3089 for mut action in actions {
3090 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3091 .await
3092 .context("resolving a formatting code action")?;
3093
3094 if let Some(edit) = action.lsp_action.edit() {
3095 if edit.changes.is_none() && edit.document_changes.is_none() {
3096 continue;
3097 }
3098
3099 let new = Self::deserialize_workspace_edit(
3100 lsp_store.upgrade().context("project dropped")?,
3101 edit.clone(),
3102 push_to_history,
3103 language_server.clone(),
3104 cx,
3105 )
3106 .await?;
3107 project_transaction.0.extend(new.0);
3108 }
3109
3110 let Some(command) = action.lsp_action.command() else {
3111 continue;
3112 };
3113
3114 let server_capabilities = language_server.capabilities();
3115 let available_commands = server_capabilities
3116 .execute_command_provider
3117 .as_ref()
3118 .map(|options| options.commands.as_slice())
3119 .unwrap_or_default();
3120 if !available_commands.contains(&command.command) {
3121 log::warn!(
3122 "Cannot execute a command {} not listed in the language server capabilities",
3123 command.command
3124 );
3125 continue;
3126 }
3127
3128 lsp_store.update(cx, |lsp_store, _| {
3129 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3130 mode.last_workspace_edits_by_language_server
3131 .remove(&language_server.server_id());
3132 }
3133 })?;
3134
3135 language_server
3136 .request::<lsp::request::ExecuteCommand>(
3137 lsp::ExecuteCommandParams {
3138 command: command.command.clone(),
3139 arguments: command.arguments.clone().unwrap_or_default(),
3140 ..Default::default()
3141 },
3142 request_timeout,
3143 )
3144 .await
3145 .into_response()
3146 .context("execute command")?;
3147
3148 lsp_store.update(cx, |this, _| {
3149 if let LspStoreMode::Local(mode) = &mut this.mode {
3150 project_transaction.0.extend(
3151 mode.last_workspace_edits_by_language_server
3152 .remove(&language_server.server_id())
3153 .unwrap_or_default()
3154 .0,
3155 )
3156 }
3157 })?;
3158 }
3159 Ok(())
3160 }
3161
3162 pub async fn deserialize_text_edits(
3163 this: Entity<LspStore>,
3164 buffer_to_edit: Entity<Buffer>,
3165 edits: Vec<lsp::TextEdit>,
3166 push_to_history: bool,
3167 _: Arc<CachedLspAdapter>,
3168 language_server: Arc<LanguageServer>,
3169 cx: &mut AsyncApp,
3170 ) -> Result<Option<Transaction>> {
3171 let edits = this
3172 .update(cx, |this, cx| {
3173 this.as_local_mut().unwrap().edits_from_lsp(
3174 &buffer_to_edit,
3175 edits,
3176 language_server.server_id(),
3177 None,
3178 cx,
3179 )
3180 })
3181 .await?;
3182
3183 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3184 buffer.finalize_last_transaction();
3185 buffer.start_transaction();
3186 for (range, text) in edits {
3187 buffer.edit([(range, text)], None, cx);
3188 }
3189
3190 if buffer.end_transaction(cx).is_some() {
3191 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3192 if !push_to_history {
3193 buffer.forget_transaction(transaction.id);
3194 }
3195 Some(transaction)
3196 } else {
3197 None
3198 }
3199 });
3200
3201 Ok(transaction)
3202 }
3203
3204 #[allow(clippy::type_complexity)]
3205 pub fn edits_from_lsp(
3206 &mut self,
3207 buffer: &Entity<Buffer>,
3208 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3209 server_id: LanguageServerId,
3210 version: Option<i32>,
3211 cx: &mut Context<LspStore>,
3212 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3213 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3214 cx.background_spawn(async move {
3215 let snapshot = snapshot?;
3216 let mut lsp_edits = lsp_edits
3217 .into_iter()
3218 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3219 .collect::<Vec<_>>();
3220
3221 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3222
3223 let mut lsp_edits = lsp_edits.into_iter().peekable();
3224 let mut edits = Vec::new();
3225 while let Some((range, mut new_text)) = lsp_edits.next() {
3226 // Clip invalid ranges provided by the language server.
3227 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3228 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3229
3230 // Combine any LSP edits that are adjacent.
3231 //
3232 // Also, combine LSP edits that are separated from each other by only
3233 // a newline. This is important because for some code actions,
3234 // Rust-analyzer rewrites the entire buffer via a series of edits that
3235 // are separated by unchanged newline characters.
3236 //
3237 // In order for the diffing logic below to work properly, any edits that
3238 // cancel each other out must be combined into one.
3239 while let Some((next_range, next_text)) = lsp_edits.peek() {
3240 if next_range.start.0 > range.end {
3241 if next_range.start.0.row > range.end.row + 1
3242 || next_range.start.0.column > 0
3243 || snapshot.clip_point_utf16(
3244 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3245 Bias::Left,
3246 ) > range.end
3247 {
3248 break;
3249 }
3250 new_text.push('\n');
3251 }
3252 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3253 new_text.push_str(next_text);
3254 lsp_edits.next();
3255 }
3256
3257 // For multiline edits, perform a diff of the old and new text so that
3258 // we can identify the changes more precisely, preserving the locations
3259 // of any anchors positioned in the unchanged regions.
3260 if range.end.row > range.start.row {
3261 let offset = range.start.to_offset(&snapshot);
3262 let old_text = snapshot.text_for_range(range).collect::<String>();
3263 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3264 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3265 (
3266 snapshot.anchor_after(offset + range.start)
3267 ..snapshot.anchor_before(offset + range.end),
3268 replacement,
3269 )
3270 }));
3271 } else if range.end == range.start {
3272 let anchor = snapshot.anchor_after(range.start);
3273 edits.push((anchor..anchor, new_text.into()));
3274 } else {
3275 let edit_start = snapshot.anchor_after(range.start);
3276 let edit_end = snapshot.anchor_before(range.end);
3277 edits.push((edit_start..edit_end, new_text.into()));
3278 }
3279 }
3280
3281 Ok(edits)
3282 })
3283 }
3284
3285 pub(crate) async fn deserialize_workspace_edit(
3286 this: Entity<LspStore>,
3287 edit: lsp::WorkspaceEdit,
3288 push_to_history: bool,
3289 language_server: Arc<LanguageServer>,
3290 cx: &mut AsyncApp,
3291 ) -> Result<ProjectTransaction> {
3292 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3293
3294 let mut operations = Vec::new();
3295 if let Some(document_changes) = edit.document_changes {
3296 match document_changes {
3297 lsp::DocumentChanges::Edits(edits) => {
3298 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3299 }
3300 lsp::DocumentChanges::Operations(ops) => operations = ops,
3301 }
3302 } else if let Some(changes) = edit.changes {
3303 operations.extend(changes.into_iter().map(|(uri, edits)| {
3304 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3305 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3306 uri,
3307 version: None,
3308 },
3309 edits: edits.into_iter().map(Edit::Plain).collect(),
3310 })
3311 }));
3312 }
3313
3314 let mut project_transaction = ProjectTransaction::default();
3315 for operation in operations {
3316 match operation {
3317 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3318 let abs_path = op
3319 .uri
3320 .to_file_path()
3321 .map_err(|()| anyhow!("can't convert URI to path"))?;
3322
3323 if let Some(parent_path) = abs_path.parent() {
3324 fs.create_dir(parent_path).await?;
3325 }
3326 if abs_path.ends_with("/") {
3327 fs.create_dir(&abs_path).await?;
3328 } else {
3329 fs.create_file(
3330 &abs_path,
3331 op.options
3332 .map(|options| fs::CreateOptions {
3333 overwrite: options.overwrite.unwrap_or(false),
3334 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3335 })
3336 .unwrap_or_default(),
3337 )
3338 .await?;
3339 }
3340 }
3341
3342 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3343 let source_abs_path = op
3344 .old_uri
3345 .to_file_path()
3346 .map_err(|()| anyhow!("can't convert URI to path"))?;
3347 let target_abs_path = op
3348 .new_uri
3349 .to_file_path()
3350 .map_err(|()| anyhow!("can't convert URI to path"))?;
3351
3352 let options = fs::RenameOptions {
3353 overwrite: op
3354 .options
3355 .as_ref()
3356 .and_then(|options| options.overwrite)
3357 .unwrap_or(false),
3358 ignore_if_exists: op
3359 .options
3360 .as_ref()
3361 .and_then(|options| options.ignore_if_exists)
3362 .unwrap_or(false),
3363 create_parents: true,
3364 };
3365
3366 fs.rename(&source_abs_path, &target_abs_path, options)
3367 .await?;
3368 }
3369
3370 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3371 let abs_path = op
3372 .uri
3373 .to_file_path()
3374 .map_err(|()| anyhow!("can't convert URI to path"))?;
3375 let options = op
3376 .options
3377 .map(|options| fs::RemoveOptions {
3378 recursive: options.recursive.unwrap_or(false),
3379 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3380 })
3381 .unwrap_or_default();
3382 if abs_path.ends_with("/") {
3383 fs.remove_dir(&abs_path, options).await?;
3384 } else {
3385 fs.remove_file(&abs_path, options).await?;
3386 }
3387 }
3388
3389 lsp::DocumentChangeOperation::Edit(op) => {
3390 let buffer_to_edit = this
3391 .update(cx, |this, cx| {
3392 this.open_local_buffer_via_lsp(
3393 op.text_document.uri.clone(),
3394 language_server.server_id(),
3395 cx,
3396 )
3397 })
3398 .await?;
3399
3400 let edits = this
3401 .update(cx, |this, cx| {
3402 let path = buffer_to_edit.read(cx).project_path(cx);
3403 let active_entry = this.active_entry;
3404 let is_active_entry = path.is_some_and(|project_path| {
3405 this.worktree_store
3406 .read(cx)
3407 .entry_for_path(&project_path, cx)
3408 .is_some_and(|entry| Some(entry.id) == active_entry)
3409 });
3410 let local = this.as_local_mut().unwrap();
3411
3412 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3413 for edit in op.edits {
3414 match edit {
3415 Edit::Plain(edit) => {
3416 if !edits.contains(&edit) {
3417 edits.push(edit)
3418 }
3419 }
3420 Edit::Annotated(edit) => {
3421 if !edits.contains(&edit.text_edit) {
3422 edits.push(edit.text_edit)
3423 }
3424 }
3425 Edit::Snippet(edit) => {
3426 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3427 else {
3428 continue;
3429 };
3430
3431 if is_active_entry {
3432 snippet_edits.push((edit.range, snippet));
3433 } else {
3434 // Since this buffer is not focused, apply a normal edit.
3435 let new_edit = TextEdit {
3436 range: edit.range,
3437 new_text: snippet.text,
3438 };
3439 if !edits.contains(&new_edit) {
3440 edits.push(new_edit);
3441 }
3442 }
3443 }
3444 }
3445 }
3446 if !snippet_edits.is_empty() {
3447 let buffer_id = buffer_to_edit.read(cx).remote_id();
3448 let version = if let Some(buffer_version) = op.text_document.version
3449 {
3450 local
3451 .buffer_snapshot_for_lsp_version(
3452 &buffer_to_edit,
3453 language_server.server_id(),
3454 Some(buffer_version),
3455 cx,
3456 )
3457 .ok()
3458 .map(|snapshot| snapshot.version)
3459 } else {
3460 Some(buffer_to_edit.read(cx).saved_version().clone())
3461 };
3462
3463 let most_recent_edit =
3464 version.and_then(|version| version.most_recent());
3465 // Check if the edit that triggered that edit has been made by this participant.
3466
3467 if let Some(most_recent_edit) = most_recent_edit {
3468 cx.emit(LspStoreEvent::SnippetEdit {
3469 buffer_id,
3470 edits: snippet_edits,
3471 most_recent_edit,
3472 });
3473 }
3474 }
3475
3476 local.edits_from_lsp(
3477 &buffer_to_edit,
3478 edits,
3479 language_server.server_id(),
3480 op.text_document.version,
3481 cx,
3482 )
3483 })
3484 .await?;
3485
3486 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3487 buffer.finalize_last_transaction();
3488 buffer.start_transaction();
3489 for (range, text) in edits {
3490 buffer.edit([(range, text)], None, cx);
3491 }
3492
3493 buffer.end_transaction(cx).and_then(|transaction_id| {
3494 if push_to_history {
3495 buffer.finalize_last_transaction();
3496 buffer.get_transaction(transaction_id).cloned()
3497 } else {
3498 buffer.forget_transaction(transaction_id)
3499 }
3500 })
3501 });
3502 if let Some(transaction) = transaction {
3503 project_transaction.0.insert(buffer_to_edit, transaction);
3504 }
3505 }
3506 }
3507 }
3508
3509 Ok(project_transaction)
3510 }
3511
3512 async fn on_lsp_workspace_edit(
3513 this: WeakEntity<LspStore>,
3514 params: lsp::ApplyWorkspaceEditParams,
3515 server_id: LanguageServerId,
3516 cx: &mut AsyncApp,
3517 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3518 let this = this.upgrade().context("project project closed")?;
3519 let language_server = this
3520 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3521 .context("language server not found")?;
3522 let transaction = Self::deserialize_workspace_edit(
3523 this.clone(),
3524 params.edit,
3525 true,
3526 language_server.clone(),
3527 cx,
3528 )
3529 .await
3530 .log_err();
3531 this.update(cx, |this, cx| {
3532 if let Some(transaction) = transaction {
3533 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3534
3535 this.as_local_mut()
3536 .unwrap()
3537 .last_workspace_edits_by_language_server
3538 .insert(server_id, transaction);
3539 }
3540 });
3541 Ok(lsp::ApplyWorkspaceEditResponse {
3542 applied: true,
3543 failed_change: None,
3544 failure_reason: None,
3545 })
3546 }
3547
3548 fn remove_worktree(
3549 &mut self,
3550 id_to_remove: WorktreeId,
3551 cx: &mut Context<LspStore>,
3552 ) -> Vec<LanguageServerId> {
3553 self.restricted_worktrees_tasks.remove(&id_to_remove);
3554 self.diagnostics.remove(&id_to_remove);
3555 self.prettier_store.update(cx, |prettier_store, cx| {
3556 prettier_store.remove_worktree(id_to_remove, cx);
3557 });
3558
3559 let mut servers_to_remove = BTreeSet::default();
3560 let mut servers_to_preserve = HashSet::default();
3561 for (seed, state) in &self.language_server_ids {
3562 if seed.worktree_id == id_to_remove {
3563 servers_to_remove.insert(state.id);
3564 } else {
3565 servers_to_preserve.insert(state.id);
3566 }
3567 }
3568 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3569 self.language_server_ids
3570 .retain(|_, state| !servers_to_remove.contains(&state.id));
3571 for server_id_to_remove in &servers_to_remove {
3572 self.language_server_watched_paths
3573 .remove(server_id_to_remove);
3574 self.language_server_paths_watched_for_rename
3575 .remove(server_id_to_remove);
3576 self.last_workspace_edits_by_language_server
3577 .remove(server_id_to_remove);
3578 self.language_servers.remove(server_id_to_remove);
3579 self.buffer_pull_diagnostics_result_ids
3580 .remove(server_id_to_remove);
3581 self.workspace_pull_diagnostics_result_ids
3582 .remove(server_id_to_remove);
3583 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3584 buffer_servers.remove(server_id_to_remove);
3585 }
3586 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3587 }
3588 servers_to_remove.into_iter().collect()
3589 }
3590
3591 fn rebuild_watched_paths_inner<'a>(
3592 &'a self,
3593 language_server_id: LanguageServerId,
3594 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3595 cx: &mut Context<LspStore>,
3596 ) -> LanguageServerWatchedPathsBuilder {
3597 let worktrees = self
3598 .worktree_store
3599 .read(cx)
3600 .worktrees()
3601 .filter_map(|worktree| {
3602 self.language_servers_for_worktree(worktree.read(cx).id())
3603 .find(|server| server.server_id() == language_server_id)
3604 .map(|_| worktree)
3605 })
3606 .collect::<Vec<_>>();
3607
3608 let mut worktree_globs = HashMap::default();
3609 let mut abs_globs = HashMap::default();
3610 log::trace!(
3611 "Processing new watcher paths for language server with id {}",
3612 language_server_id
3613 );
3614
3615 for watcher in watchers {
3616 if let Some((worktree, literal_prefix, pattern)) =
3617 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3618 {
3619 worktree.update(cx, |worktree, _| {
3620 if let Some((tree, glob)) =
3621 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3622 {
3623 tree.add_path_prefix_to_scan(literal_prefix);
3624 worktree_globs
3625 .entry(tree.id())
3626 .or_insert_with(GlobSetBuilder::new)
3627 .add(glob);
3628 }
3629 });
3630 } else {
3631 let (path, pattern) = match &watcher.glob_pattern {
3632 lsp::GlobPattern::String(s) => {
3633 let watcher_path = SanitizedPath::new(s);
3634 let path = glob_literal_prefix(watcher_path.as_path());
3635 let pattern = watcher_path
3636 .as_path()
3637 .strip_prefix(&path)
3638 .map(|p| p.to_string_lossy().into_owned())
3639 .unwrap_or_else(|e| {
3640 debug_panic!(
3641 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3642 s,
3643 path.display(),
3644 e
3645 );
3646 watcher_path.as_path().to_string_lossy().into_owned()
3647 });
3648 (path, pattern)
3649 }
3650 lsp::GlobPattern::Relative(rp) => {
3651 let Ok(mut base_uri) = match &rp.base_uri {
3652 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3653 lsp::OneOf::Right(base_uri) => base_uri,
3654 }
3655 .to_file_path() else {
3656 continue;
3657 };
3658
3659 let path = glob_literal_prefix(Path::new(&rp.pattern));
3660 let pattern = Path::new(&rp.pattern)
3661 .strip_prefix(&path)
3662 .map(|p| p.to_string_lossy().into_owned())
3663 .unwrap_or_else(|e| {
3664 debug_panic!(
3665 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3666 rp.pattern,
3667 path.display(),
3668 e
3669 );
3670 rp.pattern.clone()
3671 });
3672 base_uri.push(path);
3673 (base_uri, pattern)
3674 }
3675 };
3676
3677 if let Some(glob) = Glob::new(&pattern).log_err() {
3678 if !path
3679 .components()
3680 .any(|c| matches!(c, path::Component::Normal(_)))
3681 {
3682 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3683 // rather than adding a new watcher for `/`.
3684 for worktree in &worktrees {
3685 worktree_globs
3686 .entry(worktree.read(cx).id())
3687 .or_insert_with(GlobSetBuilder::new)
3688 .add(glob.clone());
3689 }
3690 } else {
3691 abs_globs
3692 .entry(path.into())
3693 .or_insert_with(GlobSetBuilder::new)
3694 .add(glob);
3695 }
3696 }
3697 }
3698 }
3699
3700 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3701 for (worktree_id, builder) in worktree_globs {
3702 if let Ok(globset) = builder.build() {
3703 watch_builder.watch_worktree(worktree_id, globset);
3704 }
3705 }
3706 for (abs_path, builder) in abs_globs {
3707 if let Ok(globset) = builder.build() {
3708 watch_builder.watch_abs_path(abs_path, globset);
3709 }
3710 }
3711 watch_builder
3712 }
3713
3714 fn worktree_and_path_for_file_watcher(
3715 worktrees: &[Entity<Worktree>],
3716 watcher: &FileSystemWatcher,
3717 cx: &App,
3718 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3719 worktrees.iter().find_map(|worktree| {
3720 let tree = worktree.read(cx);
3721 let worktree_root_path = tree.abs_path();
3722 let path_style = tree.path_style();
3723 match &watcher.glob_pattern {
3724 lsp::GlobPattern::String(s) => {
3725 let watcher_path = SanitizedPath::new(s);
3726 let relative = watcher_path
3727 .as_path()
3728 .strip_prefix(&worktree_root_path)
3729 .ok()?;
3730 let literal_prefix = glob_literal_prefix(relative);
3731 Some((
3732 worktree.clone(),
3733 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3734 relative.to_string_lossy().into_owned(),
3735 ))
3736 }
3737 lsp::GlobPattern::Relative(rp) => {
3738 let base_uri = match &rp.base_uri {
3739 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3740 lsp::OneOf::Right(base_uri) => base_uri,
3741 }
3742 .to_file_path()
3743 .ok()?;
3744 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3745 let mut literal_prefix = relative.to_owned();
3746 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3747 Some((
3748 worktree.clone(),
3749 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3750 rp.pattern.clone(),
3751 ))
3752 }
3753 }
3754 })
3755 }
3756
3757 fn rebuild_watched_paths(
3758 &mut self,
3759 language_server_id: LanguageServerId,
3760 cx: &mut Context<LspStore>,
3761 ) {
3762 let Some(registrations) = self
3763 .language_server_dynamic_registrations
3764 .get(&language_server_id)
3765 else {
3766 return;
3767 };
3768
3769 let watch_builder = self.rebuild_watched_paths_inner(
3770 language_server_id,
3771 registrations.did_change_watched_files.values().flatten(),
3772 cx,
3773 );
3774 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3775 self.language_server_watched_paths
3776 .insert(language_server_id, watcher);
3777
3778 cx.notify();
3779 }
3780
3781 fn on_lsp_did_change_watched_files(
3782 &mut self,
3783 language_server_id: LanguageServerId,
3784 registration_id: &str,
3785 params: DidChangeWatchedFilesRegistrationOptions,
3786 cx: &mut Context<LspStore>,
3787 ) {
3788 let registrations = self
3789 .language_server_dynamic_registrations
3790 .entry(language_server_id)
3791 .or_default();
3792
3793 registrations
3794 .did_change_watched_files
3795 .insert(registration_id.to_string(), params.watchers);
3796
3797 self.rebuild_watched_paths(language_server_id, cx);
3798 }
3799
3800 fn on_lsp_unregister_did_change_watched_files(
3801 &mut self,
3802 language_server_id: LanguageServerId,
3803 registration_id: &str,
3804 cx: &mut Context<LspStore>,
3805 ) {
3806 let registrations = self
3807 .language_server_dynamic_registrations
3808 .entry(language_server_id)
3809 .or_default();
3810
3811 if registrations
3812 .did_change_watched_files
3813 .remove(registration_id)
3814 .is_some()
3815 {
3816 log::info!(
3817 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3818 language_server_id,
3819 registration_id
3820 );
3821 } else {
3822 log::warn!(
3823 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3824 language_server_id,
3825 registration_id
3826 );
3827 }
3828
3829 self.rebuild_watched_paths(language_server_id, cx);
3830 }
3831
3832 async fn initialization_options_for_adapter(
3833 adapter: Arc<dyn LspAdapter>,
3834 delegate: &Arc<dyn LspAdapterDelegate>,
3835 cx: &mut AsyncApp,
3836 ) -> Result<Option<serde_json::Value>> {
3837 let Some(mut initialization_config) =
3838 adapter.clone().initialization_options(delegate, cx).await?
3839 else {
3840 return Ok(None);
3841 };
3842
3843 for other_adapter in delegate.registered_lsp_adapters() {
3844 if other_adapter.name() == adapter.name() {
3845 continue;
3846 }
3847 if let Ok(Some(target_config)) = other_adapter
3848 .clone()
3849 .additional_initialization_options(adapter.name(), delegate)
3850 .await
3851 {
3852 merge_json_value_into(target_config.clone(), &mut initialization_config);
3853 }
3854 }
3855
3856 Ok(Some(initialization_config))
3857 }
3858
3859 async fn workspace_configuration_for_adapter(
3860 adapter: Arc<dyn LspAdapter>,
3861 delegate: &Arc<dyn LspAdapterDelegate>,
3862 toolchain: Option<Toolchain>,
3863 requested_uri: Option<Uri>,
3864 cx: &mut AsyncApp,
3865 ) -> Result<serde_json::Value> {
3866 let mut workspace_config = adapter
3867 .clone()
3868 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3869 .await?;
3870
3871 for other_adapter in delegate.registered_lsp_adapters() {
3872 if other_adapter.name() == adapter.name() {
3873 continue;
3874 }
3875 if let Ok(Some(target_config)) = other_adapter
3876 .clone()
3877 .additional_workspace_configuration(adapter.name(), delegate, cx)
3878 .await
3879 {
3880 merge_json_value_into(target_config.clone(), &mut workspace_config);
3881 }
3882 }
3883
3884 Ok(workspace_config)
3885 }
3886
3887 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3888 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3889 Some(server.clone())
3890 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3891 Some(Arc::clone(server))
3892 } else {
3893 None
3894 }
3895 }
3896}
3897
3898fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3899 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3900 cx.emit(LspStoreEvent::LanguageServerUpdate {
3901 language_server_id: server.server_id(),
3902 name: Some(server.name()),
3903 message: proto::update_language_server::Variant::MetadataUpdated(
3904 proto::ServerMetadataUpdated {
3905 capabilities: Some(capabilities),
3906 binary: Some(proto::LanguageServerBinaryInfo {
3907 path: server.binary().path.to_string_lossy().into_owned(),
3908 arguments: server
3909 .binary()
3910 .arguments
3911 .iter()
3912 .map(|arg| arg.to_string_lossy().into_owned())
3913 .collect(),
3914 }),
3915 configuration: serde_json::to_string(server.configuration()).ok(),
3916 workspace_folders: server
3917 .workspace_folders()
3918 .iter()
3919 .map(|uri| uri.to_string())
3920 .collect(),
3921 },
3922 ),
3923 });
3924 }
3925}
3926
3927#[derive(Debug)]
3928pub struct FormattableBuffer {
3929 handle: Entity<Buffer>,
3930 abs_path: Option<PathBuf>,
3931 env: Option<HashMap<String, String>>,
3932 ranges: Option<Vec<Range<Anchor>>>,
3933}
3934
3935pub struct RemoteLspStore {
3936 upstream_client: Option<AnyProtoClient>,
3937 upstream_project_id: u64,
3938}
3939
3940pub(crate) enum LspStoreMode {
3941 Local(LocalLspStore), // ssh host and collab host
3942 Remote(RemoteLspStore), // collab guest
3943}
3944
3945impl LspStoreMode {
3946 fn is_local(&self) -> bool {
3947 matches!(self, LspStoreMode::Local(_))
3948 }
3949}
3950
3951pub struct LspStore {
3952 mode: LspStoreMode,
3953 last_formatting_failure: Option<String>,
3954 downstream_client: Option<(AnyProtoClient, u64)>,
3955 nonce: u128,
3956 buffer_store: Entity<BufferStore>,
3957 worktree_store: Entity<WorktreeStore>,
3958 pub languages: Arc<LanguageRegistry>,
3959 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3960 active_entry: Option<ProjectEntryId>,
3961 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3962 _maintain_buffer_languages: Task<()>,
3963 diagnostic_summaries:
3964 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3965 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3966 semantic_token_config: SemanticTokenConfig,
3967 lsp_data: HashMap<BufferId, BufferLspData>,
3968 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3969 next_hint_id: Arc<AtomicUsize>,
3970}
3971
3972#[derive(Debug)]
3973pub struct BufferLspData {
3974 buffer_version: Global,
3975 document_colors: Option<DocumentColorData>,
3976 code_lens: Option<CodeLensData>,
3977 semantic_tokens: Option<SemanticTokensData>,
3978 folding_ranges: Option<FoldingRangeData>,
3979 document_symbols: Option<DocumentSymbolsData>,
3980 inlay_hints: BufferInlayHints,
3981 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3982 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3983}
3984
3985#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3986struct LspKey {
3987 request_type: TypeId,
3988 server_queried: Option<LanguageServerId>,
3989}
3990
3991impl BufferLspData {
3992 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3993 Self {
3994 buffer_version: buffer.read(cx).version(),
3995 document_colors: None,
3996 code_lens: None,
3997 semantic_tokens: None,
3998 folding_ranges: None,
3999 document_symbols: None,
4000 inlay_hints: BufferInlayHints::new(buffer, cx),
4001 lsp_requests: HashMap::default(),
4002 chunk_lsp_requests: HashMap::default(),
4003 }
4004 }
4005
4006 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4007 if let Some(document_colors) = &mut self.document_colors {
4008 document_colors.remove_server_data(for_server);
4009 }
4010
4011 if let Some(code_lens) = &mut self.code_lens {
4012 code_lens.remove_server_data(for_server);
4013 }
4014
4015 self.inlay_hints.remove_server_data(for_server);
4016
4017 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4018 semantic_tokens.remove_server_data(for_server);
4019 }
4020
4021 if let Some(folding_ranges) = &mut self.folding_ranges {
4022 folding_ranges.ranges.remove(&for_server);
4023 }
4024
4025 if let Some(document_symbols) = &mut self.document_symbols {
4026 document_symbols.remove_server_data(for_server);
4027 }
4028 }
4029
4030 #[cfg(any(test, feature = "test-support"))]
4031 pub fn inlay_hints(&self) -> &BufferInlayHints {
4032 &self.inlay_hints
4033 }
4034}
4035
4036#[derive(Debug)]
4037pub enum LspStoreEvent {
4038 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4039 LanguageServerRemoved(LanguageServerId),
4040 LanguageServerUpdate {
4041 language_server_id: LanguageServerId,
4042 name: Option<LanguageServerName>,
4043 message: proto::update_language_server::Variant,
4044 },
4045 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4046 LanguageServerPrompt(LanguageServerPromptRequest),
4047 LanguageDetected {
4048 buffer: Entity<Buffer>,
4049 new_language: Option<Arc<Language>>,
4050 },
4051 Notification(String),
4052 RefreshInlayHints {
4053 server_id: LanguageServerId,
4054 request_id: Option<usize>,
4055 },
4056 RefreshSemanticTokens {
4057 server_id: LanguageServerId,
4058 request_id: Option<usize>,
4059 },
4060 RefreshCodeLens,
4061 DiagnosticsUpdated {
4062 server_id: LanguageServerId,
4063 paths: Vec<ProjectPath>,
4064 },
4065 DiskBasedDiagnosticsStarted {
4066 language_server_id: LanguageServerId,
4067 },
4068 DiskBasedDiagnosticsFinished {
4069 language_server_id: LanguageServerId,
4070 },
4071 SnippetEdit {
4072 buffer_id: BufferId,
4073 edits: Vec<(lsp::Range, Snippet)>,
4074 most_recent_edit: clock::Lamport,
4075 },
4076 WorkspaceEditApplied(ProjectTransaction),
4077}
4078
4079#[derive(Clone, Debug, Serialize)]
4080pub struct LanguageServerStatus {
4081 pub name: LanguageServerName,
4082 pub server_version: Option<SharedString>,
4083 pub server_readable_version: Option<SharedString>,
4084 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4085 pub has_pending_diagnostic_updates: bool,
4086 pub progress_tokens: HashSet<ProgressToken>,
4087 pub worktree: Option<WorktreeId>,
4088 pub binary: Option<LanguageServerBinary>,
4089 pub configuration: Option<Value>,
4090 pub workspace_folders: BTreeSet<Uri>,
4091 pub process_id: Option<u32>,
4092}
4093
4094#[derive(Clone, Debug)]
4095struct CoreSymbol {
4096 pub language_server_name: LanguageServerName,
4097 pub source_worktree_id: WorktreeId,
4098 pub source_language_server_id: LanguageServerId,
4099 pub path: SymbolLocation,
4100 pub name: String,
4101 pub kind: lsp::SymbolKind,
4102 pub range: Range<Unclipped<PointUtf16>>,
4103 pub container_name: Option<String>,
4104}
4105
4106#[derive(Clone, Debug, PartialEq, Eq)]
4107pub enum SymbolLocation {
4108 InProject(ProjectPath),
4109 OutsideProject {
4110 abs_path: Arc<Path>,
4111 signature: [u8; 32],
4112 },
4113}
4114
4115impl SymbolLocation {
4116 fn file_name(&self) -> Option<&str> {
4117 match self {
4118 Self::InProject(path) => path.path.file_name(),
4119 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4120 }
4121 }
4122}
4123
4124impl LspStore {
4125 pub fn init(client: &AnyProtoClient) {
4126 client.add_entity_request_handler(Self::handle_lsp_query);
4127 client.add_entity_message_handler(Self::handle_lsp_query_response);
4128 client.add_entity_request_handler(Self::handle_restart_language_servers);
4129 client.add_entity_request_handler(Self::handle_stop_language_servers);
4130 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4131 client.add_entity_message_handler(Self::handle_start_language_server);
4132 client.add_entity_message_handler(Self::handle_update_language_server);
4133 client.add_entity_message_handler(Self::handle_language_server_log);
4134 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4135 client.add_entity_request_handler(Self::handle_format_buffers);
4136 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4137 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4138 client.add_entity_request_handler(Self::handle_apply_code_action);
4139 client.add_entity_request_handler(Self::handle_get_project_symbols);
4140 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4141 client.add_entity_request_handler(Self::handle_get_color_presentation);
4142 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4143 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4144 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4145 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4146 client.add_entity_request_handler(Self::handle_on_type_formatting);
4147 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4148 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4149 client.add_entity_request_handler(Self::handle_rename_project_entry);
4150 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4151 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4152 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4153 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4154 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4155 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4156 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4157
4158 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4159 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4160 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4161 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4162 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4163 client.add_entity_request_handler(
4164 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4165 );
4166 client.add_entity_request_handler(
4167 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4168 );
4169 client.add_entity_request_handler(
4170 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4171 );
4172 }
4173
4174 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4175 match &self.mode {
4176 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4177 _ => None,
4178 }
4179 }
4180
4181 pub fn as_local(&self) -> Option<&LocalLspStore> {
4182 match &self.mode {
4183 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4184 _ => None,
4185 }
4186 }
4187
4188 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4189 match &mut self.mode {
4190 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4191 _ => None,
4192 }
4193 }
4194
4195 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4196 match &self.mode {
4197 LspStoreMode::Remote(RemoteLspStore {
4198 upstream_client: Some(upstream_client),
4199 upstream_project_id,
4200 ..
4201 }) => Some((upstream_client.clone(), *upstream_project_id)),
4202
4203 LspStoreMode::Remote(RemoteLspStore {
4204 upstream_client: None,
4205 ..
4206 }) => None,
4207 LspStoreMode::Local(_) => None,
4208 }
4209 }
4210
4211 pub fn new_local(
4212 buffer_store: Entity<BufferStore>,
4213 worktree_store: Entity<WorktreeStore>,
4214 prettier_store: Entity<PrettierStore>,
4215 toolchain_store: Entity<LocalToolchainStore>,
4216 environment: Entity<ProjectEnvironment>,
4217 manifest_tree: Entity<ManifestTree>,
4218 languages: Arc<LanguageRegistry>,
4219 http_client: Arc<dyn HttpClient>,
4220 fs: Arc<dyn Fs>,
4221 cx: &mut Context<Self>,
4222 ) -> Self {
4223 let yarn = YarnPathStore::new(fs.clone(), cx);
4224 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4225 .detach();
4226 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4227 .detach();
4228 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4229 .detach();
4230 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4231 .detach();
4232 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4233 .detach();
4234 subscribe_to_binary_statuses(&languages, cx).detach();
4235
4236 let _maintain_workspace_config = {
4237 let (sender, receiver) = watch::channel();
4238 (Self::maintain_workspace_config(receiver, cx), sender)
4239 };
4240
4241 Self {
4242 mode: LspStoreMode::Local(LocalLspStore {
4243 weak: cx.weak_entity(),
4244 worktree_store: worktree_store.clone(),
4245
4246 supplementary_language_servers: Default::default(),
4247 languages: languages.clone(),
4248 language_server_ids: Default::default(),
4249 language_servers: Default::default(),
4250 last_workspace_edits_by_language_server: Default::default(),
4251 language_server_watched_paths: Default::default(),
4252 language_server_paths_watched_for_rename: Default::default(),
4253 language_server_dynamic_registrations: Default::default(),
4254 buffers_being_formatted: Default::default(),
4255 buffers_to_refresh_hash_set: HashSet::default(),
4256 buffers_to_refresh_queue: VecDeque::new(),
4257 _background_diagnostics_worker: Task::ready(()).shared(),
4258 buffer_snapshots: Default::default(),
4259 prettier_store,
4260 environment,
4261 http_client,
4262 fs,
4263 yarn,
4264 next_diagnostic_group_id: Default::default(),
4265 diagnostics: Default::default(),
4266 _subscription: cx.on_app_quit(|this, _| {
4267 this.as_local_mut()
4268 .unwrap()
4269 .shutdown_language_servers_on_quit()
4270 }),
4271 lsp_tree: LanguageServerTree::new(
4272 manifest_tree,
4273 languages.clone(),
4274 toolchain_store.clone(),
4275 ),
4276 toolchain_store,
4277 registered_buffers: HashMap::default(),
4278 buffers_opened_in_servers: HashMap::default(),
4279 buffer_pull_diagnostics_result_ids: HashMap::default(),
4280 workspace_pull_diagnostics_result_ids: HashMap::default(),
4281 restricted_worktrees_tasks: HashMap::default(),
4282 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4283 .manifest_file_names(),
4284 }),
4285 last_formatting_failure: None,
4286 downstream_client: None,
4287 buffer_store,
4288 worktree_store,
4289 languages: languages.clone(),
4290 language_server_statuses: Default::default(),
4291 nonce: StdRng::from_os_rng().random(),
4292 diagnostic_summaries: HashMap::default(),
4293 lsp_server_capabilities: HashMap::default(),
4294 semantic_token_config: SemanticTokenConfig::new(cx),
4295 lsp_data: HashMap::default(),
4296 buffer_reload_tasks: HashMap::default(),
4297 next_hint_id: Arc::default(),
4298 active_entry: None,
4299 _maintain_workspace_config,
4300 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4301 }
4302 }
4303
4304 fn send_lsp_proto_request<R: LspCommand>(
4305 &self,
4306 buffer: Entity<Buffer>,
4307 client: AnyProtoClient,
4308 upstream_project_id: u64,
4309 request: R,
4310 cx: &mut Context<LspStore>,
4311 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4312 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4313 return Task::ready(Ok(R::Response::default()));
4314 }
4315 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4316 cx.spawn(async move |this, cx| {
4317 let response = client.request(message).await?;
4318 let this = this.upgrade().context("project dropped")?;
4319 request
4320 .response_from_proto(response, this, buffer, cx.clone())
4321 .await
4322 })
4323 }
4324
4325 pub(super) fn new_remote(
4326 buffer_store: Entity<BufferStore>,
4327 worktree_store: Entity<WorktreeStore>,
4328 languages: Arc<LanguageRegistry>,
4329 upstream_client: AnyProtoClient,
4330 project_id: u64,
4331 cx: &mut Context<Self>,
4332 ) -> Self {
4333 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4334 .detach();
4335 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4336 .detach();
4337 subscribe_to_binary_statuses(&languages, cx).detach();
4338 let _maintain_workspace_config = {
4339 let (sender, receiver) = watch::channel();
4340 (Self::maintain_workspace_config(receiver, cx), sender)
4341 };
4342 Self {
4343 mode: LspStoreMode::Remote(RemoteLspStore {
4344 upstream_client: Some(upstream_client),
4345 upstream_project_id: project_id,
4346 }),
4347 downstream_client: None,
4348 last_formatting_failure: None,
4349 buffer_store,
4350 worktree_store,
4351 languages: languages.clone(),
4352 language_server_statuses: Default::default(),
4353 nonce: StdRng::from_os_rng().random(),
4354 diagnostic_summaries: HashMap::default(),
4355 lsp_server_capabilities: HashMap::default(),
4356 semantic_token_config: SemanticTokenConfig::new(cx),
4357 next_hint_id: Arc::default(),
4358 lsp_data: HashMap::default(),
4359 buffer_reload_tasks: HashMap::default(),
4360 active_entry: None,
4361
4362 _maintain_workspace_config,
4363 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4364 }
4365 }
4366
4367 fn on_buffer_store_event(
4368 &mut self,
4369 _: Entity<BufferStore>,
4370 event: &BufferStoreEvent,
4371 cx: &mut Context<Self>,
4372 ) {
4373 match event {
4374 BufferStoreEvent::BufferAdded(buffer) => {
4375 self.on_buffer_added(buffer, cx).log_err();
4376 }
4377 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4378 let buffer_id = buffer.read(cx).remote_id();
4379 if let Some(local) = self.as_local_mut()
4380 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4381 {
4382 local.reset_buffer(buffer, old_file, cx);
4383
4384 if local.registered_buffers.contains_key(&buffer_id) {
4385 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4386 }
4387 }
4388
4389 self.detect_language_for_buffer(buffer, cx);
4390 if let Some(local) = self.as_local_mut() {
4391 local.initialize_buffer(buffer, cx);
4392 if local.registered_buffers.contains_key(&buffer_id) {
4393 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4394 }
4395 }
4396 }
4397 _ => {}
4398 }
4399 }
4400
4401 fn on_worktree_store_event(
4402 &mut self,
4403 _: Entity<WorktreeStore>,
4404 event: &WorktreeStoreEvent,
4405 cx: &mut Context<Self>,
4406 ) {
4407 match event {
4408 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4409 if !worktree.read(cx).is_local() {
4410 return;
4411 }
4412 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4413 worktree::Event::UpdatedEntries(changes) => {
4414 this.update_local_worktree_language_servers(&worktree, changes, cx);
4415 }
4416 worktree::Event::UpdatedGitRepositories(_)
4417 | worktree::Event::DeletedEntry(_)
4418 | worktree::Event::Deleted
4419 | worktree::Event::UpdatedRootRepoCommonDir => {}
4420 })
4421 .detach()
4422 }
4423 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4424 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4425 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4426 }
4427 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4428 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4429 }
4430 WorktreeStoreEvent::WorktreeReleased(..)
4431 | WorktreeStoreEvent::WorktreeOrderChanged
4432 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4433 | WorktreeStoreEvent::WorktreeDeletedEntry(..)
4434 | WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir(..) => {}
4435 }
4436 }
4437
4438 fn on_prettier_store_event(
4439 &mut self,
4440 _: Entity<PrettierStore>,
4441 event: &PrettierStoreEvent,
4442 cx: &mut Context<Self>,
4443 ) {
4444 match event {
4445 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4446 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4447 }
4448 PrettierStoreEvent::LanguageServerAdded {
4449 new_server_id,
4450 name,
4451 prettier_server,
4452 } => {
4453 self.register_supplementary_language_server(
4454 *new_server_id,
4455 name.clone(),
4456 prettier_server.clone(),
4457 cx,
4458 );
4459 }
4460 }
4461 }
4462
4463 fn on_toolchain_store_event(
4464 &mut self,
4465 _: Entity<LocalToolchainStore>,
4466 event: &ToolchainStoreEvent,
4467 _: &mut Context<Self>,
4468 ) {
4469 if let ToolchainStoreEvent::ToolchainActivated = event {
4470 self.request_workspace_config_refresh()
4471 }
4472 }
4473
4474 fn request_workspace_config_refresh(&mut self) {
4475 *self._maintain_workspace_config.1.borrow_mut() = ();
4476 }
4477
4478 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4479 self.as_local().map(|local| local.prettier_store.clone())
4480 }
4481
4482 fn on_buffer_event(
4483 &mut self,
4484 buffer: Entity<Buffer>,
4485 event: &language::BufferEvent,
4486 cx: &mut Context<Self>,
4487 ) {
4488 match event {
4489 language::BufferEvent::Edited { .. } => {
4490 self.on_buffer_edited(buffer, cx);
4491 }
4492
4493 language::BufferEvent::Saved => {
4494 self.on_buffer_saved(buffer, cx);
4495 }
4496
4497 language::BufferEvent::Reloaded => {
4498 self.on_buffer_reloaded(buffer, cx);
4499 }
4500
4501 _ => {}
4502 }
4503 }
4504
4505 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4506 buffer
4507 .read(cx)
4508 .set_language_registry(self.languages.clone());
4509
4510 cx.subscribe(buffer, |this, buffer, event, cx| {
4511 this.on_buffer_event(buffer, event, cx);
4512 })
4513 .detach();
4514
4515 self.parse_modeline(buffer, cx);
4516 self.detect_language_for_buffer(buffer, cx);
4517 if let Some(local) = self.as_local_mut() {
4518 local.initialize_buffer(buffer, cx);
4519 }
4520
4521 Ok(())
4522 }
4523
4524 pub fn refresh_background_diagnostics_for_buffers(
4525 &mut self,
4526 buffers: HashSet<BufferId>,
4527 cx: &mut Context<Self>,
4528 ) -> Shared<Task<()>> {
4529 let Some(local) = self.as_local_mut() else {
4530 return Task::ready(()).shared();
4531 };
4532 for buffer in buffers {
4533 if local.buffers_to_refresh_hash_set.insert(buffer) {
4534 local.buffers_to_refresh_queue.push_back(buffer);
4535 if local.buffers_to_refresh_queue.len() == 1 {
4536 local._background_diagnostics_worker =
4537 Self::background_diagnostics_worker(cx).shared();
4538 }
4539 }
4540 }
4541
4542 local._background_diagnostics_worker.clone()
4543 }
4544
4545 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4546 let buffer_store = self.buffer_store.clone();
4547 let local = self.as_local_mut()?;
4548 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4549 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4550 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4551 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4552 }
4553 }
4554 None
4555 }
4556
4557 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4558 cx.spawn(async move |this, cx| {
4559 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4560 task.await.log_err();
4561 }
4562 })
4563 }
4564
4565 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4566 if self.parse_modeline(&buffer, cx) {
4567 self.detect_language_for_buffer(&buffer, cx);
4568 }
4569
4570 let buffer_id = buffer.read(cx).remote_id();
4571 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4572 self.buffer_reload_tasks.insert(buffer_id, task);
4573 }
4574
4575 pub(crate) fn register_buffer_with_language_servers(
4576 &mut self,
4577 buffer: &Entity<Buffer>,
4578 only_register_servers: HashSet<LanguageServerSelector>,
4579 ignore_refcounts: bool,
4580 cx: &mut Context<Self>,
4581 ) -> OpenLspBufferHandle {
4582 let buffer_id = buffer.read(cx).remote_id();
4583 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4584 if let Some(local) = self.as_local_mut() {
4585 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4586 if !ignore_refcounts {
4587 *refcount += 1;
4588 }
4589
4590 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4591 // 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
4592 // 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
4593 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4594 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4595 return handle;
4596 };
4597 if !file.is_local() {
4598 return handle;
4599 }
4600
4601 if ignore_refcounts || *refcount == 1 {
4602 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4603 }
4604 if !ignore_refcounts {
4605 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4606 let refcount = {
4607 let local = lsp_store.as_local_mut().unwrap();
4608 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4609 debug_panic!("bad refcounting");
4610 return;
4611 };
4612
4613 *refcount -= 1;
4614 *refcount
4615 };
4616 if refcount == 0 {
4617 lsp_store.lsp_data.remove(&buffer_id);
4618 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4619 let local = lsp_store.as_local_mut().unwrap();
4620 local.registered_buffers.remove(&buffer_id);
4621
4622 local.buffers_opened_in_servers.remove(&buffer_id);
4623 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4624 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4625
4626 let buffer_abs_path = file.abs_path(cx);
4627 for (_, buffer_pull_diagnostics_result_ids) in
4628 &mut local.buffer_pull_diagnostics_result_ids
4629 {
4630 buffer_pull_diagnostics_result_ids.retain(
4631 |_, buffer_result_ids| {
4632 buffer_result_ids.remove(&buffer_abs_path);
4633 !buffer_result_ids.is_empty()
4634 },
4635 );
4636 }
4637
4638 let diagnostic_updates = local
4639 .language_servers
4640 .keys()
4641 .cloned()
4642 .map(|server_id| DocumentDiagnosticsUpdate {
4643 diagnostics: DocumentDiagnostics {
4644 document_abs_path: buffer_abs_path.clone(),
4645 version: None,
4646 diagnostics: Vec::new(),
4647 },
4648 result_id: None,
4649 registration_id: None,
4650 server_id,
4651 disk_based_sources: Cow::Borrowed(&[]),
4652 })
4653 .collect::<Vec<_>>();
4654
4655 lsp_store
4656 .merge_diagnostic_entries(
4657 diagnostic_updates,
4658 |_, diagnostic, _| {
4659 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4660 },
4661 cx,
4662 )
4663 .context("Clearing diagnostics for the closed buffer")
4664 .log_err();
4665 }
4666 }
4667 })
4668 .detach();
4669 }
4670 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4671 let buffer_id = buffer.read(cx).remote_id().to_proto();
4672 cx.background_spawn(async move {
4673 upstream_client
4674 .request(proto::RegisterBufferWithLanguageServers {
4675 project_id: upstream_project_id,
4676 buffer_id,
4677 only_servers: only_register_servers
4678 .into_iter()
4679 .map(|selector| {
4680 let selector = match selector {
4681 LanguageServerSelector::Id(language_server_id) => {
4682 proto::language_server_selector::Selector::ServerId(
4683 language_server_id.to_proto(),
4684 )
4685 }
4686 LanguageServerSelector::Name(language_server_name) => {
4687 proto::language_server_selector::Selector::Name(
4688 language_server_name.to_string(),
4689 )
4690 }
4691 };
4692 proto::LanguageServerSelector {
4693 selector: Some(selector),
4694 }
4695 })
4696 .collect(),
4697 })
4698 .await
4699 })
4700 .detach();
4701 } else {
4702 // Our remote connection got closed
4703 }
4704 handle
4705 }
4706
4707 fn maintain_buffer_languages(
4708 languages: Arc<LanguageRegistry>,
4709 cx: &mut Context<Self>,
4710 ) -> Task<()> {
4711 let mut subscription = languages.subscribe();
4712 let mut prev_reload_count = languages.reload_count();
4713 cx.spawn(async move |this, cx| {
4714 while let Some(()) = subscription.next().await {
4715 if let Some(this) = this.upgrade() {
4716 // If the language registry has been reloaded, then remove and
4717 // re-assign the languages on all open buffers.
4718 let reload_count = languages.reload_count();
4719 if reload_count > prev_reload_count {
4720 prev_reload_count = reload_count;
4721 this.update(cx, |this, cx| {
4722 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4723 for buffer in buffer_store.buffers() {
4724 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4725 {
4726 buffer.update(cx, |buffer, cx| {
4727 buffer.set_language_async(None, cx)
4728 });
4729 if let Some(local) = this.as_local_mut() {
4730 local.reset_buffer(&buffer, &f, cx);
4731
4732 if local
4733 .registered_buffers
4734 .contains_key(&buffer.read(cx).remote_id())
4735 && let Some(file_url) =
4736 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4737 {
4738 local.unregister_buffer_from_language_servers(
4739 &buffer, &file_url, cx,
4740 );
4741 }
4742 }
4743 }
4744 }
4745 });
4746 });
4747 }
4748
4749 this.update(cx, |this, cx| {
4750 let mut plain_text_buffers = Vec::new();
4751 let mut buffers_with_unknown_injections = Vec::new();
4752 for handle in this.buffer_store.read(cx).buffers() {
4753 let buffer = handle.read(cx);
4754 if buffer.language().is_none()
4755 || buffer.language() == Some(&*language::PLAIN_TEXT)
4756 {
4757 plain_text_buffers.push(handle);
4758 } else if buffer.contains_unknown_injections() {
4759 buffers_with_unknown_injections.push(handle);
4760 }
4761 }
4762
4763 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4764 // and reused later in the invisible worktrees.
4765 plain_text_buffers.sort_by_key(|buffer| {
4766 Reverse(
4767 File::from_dyn(buffer.read(cx).file())
4768 .map(|file| file.worktree.read(cx).is_visible()),
4769 )
4770 });
4771
4772 for buffer in plain_text_buffers {
4773 this.detect_language_for_buffer(&buffer, cx);
4774 if let Some(local) = this.as_local_mut() {
4775 local.initialize_buffer(&buffer, cx);
4776 if local
4777 .registered_buffers
4778 .contains_key(&buffer.read(cx).remote_id())
4779 {
4780 local.register_buffer_with_language_servers(
4781 &buffer,
4782 HashSet::default(),
4783 cx,
4784 );
4785 }
4786 }
4787 }
4788
4789 for buffer in buffers_with_unknown_injections {
4790 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4791 }
4792 });
4793 }
4794 }
4795 })
4796 }
4797
4798 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4799 let buffer = buffer_handle.read(cx);
4800 let content = buffer.as_rope();
4801
4802 let modeline_settings = {
4803 let settings_store = cx.global::<SettingsStore>();
4804 let modeline_lines = settings_store
4805 .raw_user_settings()
4806 .and_then(|s| s.content.modeline_lines)
4807 .or(settings_store.raw_default_settings().modeline_lines)
4808 .unwrap_or(5);
4809
4810 const MAX_MODELINE_BYTES: usize = 1024;
4811
4812 let first_bytes =
4813 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4814 let mut first_lines = Vec::new();
4815 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4816 for _ in 0..modeline_lines {
4817 if let Some(line) = lines.next() {
4818 first_lines.push(line.to_string());
4819 } else {
4820 break;
4821 }
4822 }
4823 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4824
4825 let last_start =
4826 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4827 let mut last_lines = Vec::new();
4828 let mut lines = content
4829 .reversed_chunks_in_range(last_start..content.len())
4830 .lines();
4831 for _ in 0..modeline_lines {
4832 if let Some(line) = lines.next() {
4833 last_lines.push(line.to_string());
4834 } else {
4835 break;
4836 }
4837 }
4838 let last_lines_ref: Vec<_> =
4839 last_lines.iter().rev().map(|line| line.as_str()).collect();
4840 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4841 };
4842
4843 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4844
4845 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4846 }
4847
4848 fn detect_language_for_buffer(
4849 &mut self,
4850 buffer_handle: &Entity<Buffer>,
4851 cx: &mut Context<Self>,
4852 ) -> Option<language::AvailableLanguage> {
4853 // If the buffer has a language, set it and start the language server if we haven't already.
4854 let buffer = buffer_handle.read(cx);
4855 let file = buffer.file()?;
4856 let content = buffer.as_rope();
4857 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4858
4859 let available_language = if let Some(ModelineSettings {
4860 mode: Some(mode_name),
4861 ..
4862 }) = modeline_settings
4863 {
4864 self.languages
4865 .available_language_for_modeline_name(mode_name)
4866 } else {
4867 self.languages.language_for_file(file, Some(content), cx)
4868 };
4869 if let Some(available_language) = &available_language {
4870 if let Some(Ok(Ok(new_language))) = self
4871 .languages
4872 .load_language(available_language)
4873 .now_or_never()
4874 {
4875 self.set_language_for_buffer(buffer_handle, new_language, cx);
4876 }
4877 } else {
4878 cx.emit(LspStoreEvent::LanguageDetected {
4879 buffer: buffer_handle.clone(),
4880 new_language: None,
4881 });
4882 }
4883
4884 available_language
4885 }
4886
4887 pub(crate) fn set_language_for_buffer(
4888 &mut self,
4889 buffer_entity: &Entity<Buffer>,
4890 new_language: Arc<Language>,
4891 cx: &mut Context<Self>,
4892 ) {
4893 let buffer = buffer_entity.read(cx);
4894 let buffer_file = buffer.file().cloned();
4895 let buffer_id = buffer.remote_id();
4896 if let Some(local_store) = self.as_local_mut()
4897 && local_store.registered_buffers.contains_key(&buffer_id)
4898 && let Some(abs_path) =
4899 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4900 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4901 {
4902 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4903 }
4904 buffer_entity.update(cx, |buffer, cx| {
4905 if buffer
4906 .language()
4907 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4908 {
4909 buffer.set_language_async(Some(new_language.clone()), cx);
4910 }
4911 });
4912
4913 let settings = LanguageSettings::resolve(
4914 Some(&buffer_entity.read(cx)),
4915 Some(&new_language.name()),
4916 cx,
4917 )
4918 .into_owned();
4919 let buffer_file = File::from_dyn(buffer_file.as_ref());
4920
4921 let worktree_id = if let Some(file) = buffer_file {
4922 let worktree = file.worktree.clone();
4923
4924 if let Some(local) = self.as_local_mut()
4925 && local.registered_buffers.contains_key(&buffer_id)
4926 {
4927 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4928 }
4929 Some(worktree.read(cx).id())
4930 } else {
4931 None
4932 };
4933
4934 if settings.prettier.allowed
4935 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4936 {
4937 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4938 if let Some(prettier_store) = prettier_store {
4939 prettier_store.update(cx, |prettier_store, cx| {
4940 prettier_store.install_default_prettier(
4941 worktree_id,
4942 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4943 cx,
4944 )
4945 })
4946 }
4947 }
4948
4949 cx.emit(LspStoreEvent::LanguageDetected {
4950 buffer: buffer_entity.clone(),
4951 new_language: Some(new_language),
4952 })
4953 }
4954
4955 pub fn buffer_store(&self) -> Entity<BufferStore> {
4956 self.buffer_store.clone()
4957 }
4958
4959 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4960 self.active_entry = active_entry;
4961 }
4962
4963 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4964 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4965 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4966 {
4967 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4968 summaries
4969 .iter()
4970 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4971 });
4972 if let Some(summary) = summaries.next() {
4973 client
4974 .send(proto::UpdateDiagnosticSummary {
4975 project_id: downstream_project_id,
4976 worktree_id: worktree.id().to_proto(),
4977 summary: Some(summary),
4978 more_summaries: summaries.collect(),
4979 })
4980 .log_err();
4981 }
4982 }
4983 }
4984
4985 fn is_capable_for_proto_request<R>(
4986 &self,
4987 buffer: &Entity<Buffer>,
4988 request: &R,
4989 cx: &App,
4990 ) -> bool
4991 where
4992 R: LspCommand,
4993 {
4994 self.check_if_capable_for_proto_request(
4995 buffer,
4996 |capabilities| {
4997 request.check_capabilities(AdapterServerCapabilities {
4998 server_capabilities: capabilities.clone(),
4999 code_action_kinds: None,
5000 })
5001 },
5002 cx,
5003 )
5004 }
5005
5006 fn check_if_capable_for_proto_request<F>(
5007 &self,
5008 buffer: &Entity<Buffer>,
5009 check: F,
5010 cx: &App,
5011 ) -> bool
5012 where
5013 F: FnMut(&lsp::ServerCapabilities) -> bool,
5014 {
5015 let Some(language) = buffer.read(cx).language().cloned() else {
5016 return false;
5017 };
5018 let registered_language_servers = self
5019 .languages
5020 .lsp_adapters(&language.name())
5021 .into_iter()
5022 .map(|lsp_adapter| lsp_adapter.name())
5023 .collect::<HashSet<_>>();
5024 self.language_server_statuses
5025 .iter()
5026 .filter_map(|(server_id, server_status)| {
5027 // Include servers that are either registered for this language OR
5028 // available to be loaded (for SSH remote mode where adapters like
5029 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5030 // but only loaded on the server side)
5031 let is_relevant = registered_language_servers.contains(&server_status.name)
5032 || self.languages.is_lsp_adapter_available(&server_status.name);
5033 is_relevant.then_some(server_id)
5034 })
5035 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
5036 .any(check)
5037 }
5038
5039 fn all_capable_for_proto_request<F>(
5040 &self,
5041 buffer: &Entity<Buffer>,
5042 mut check: F,
5043 cx: &App,
5044 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5045 where
5046 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5047 {
5048 let Some(language) = buffer.read(cx).language().cloned() else {
5049 return Vec::default();
5050 };
5051 let registered_language_servers = self
5052 .languages
5053 .lsp_adapters(&language.name())
5054 .into_iter()
5055 .map(|lsp_adapter| lsp_adapter.name())
5056 .collect::<HashSet<_>>();
5057 self.language_server_statuses
5058 .iter()
5059 .filter_map(|(server_id, server_status)| {
5060 // Include servers that are either registered for this language OR
5061 // available to be loaded (for SSH remote mode where adapters like
5062 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5063 // but only loaded on the server side)
5064 let is_relevant = registered_language_servers.contains(&server_status.name)
5065 || self.languages.is_lsp_adapter_available(&server_status.name);
5066 is_relevant.then_some((server_id, &server_status.name))
5067 })
5068 .filter_map(|(server_id, server_name)| {
5069 self.lsp_server_capabilities
5070 .get(server_id)
5071 .map(|c| (server_id, server_name, c))
5072 })
5073 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5074 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5075 .collect()
5076 }
5077
5078 pub fn request_lsp<R>(
5079 &mut self,
5080 buffer: Entity<Buffer>,
5081 server: LanguageServerToQuery,
5082 request: R,
5083 cx: &mut Context<Self>,
5084 ) -> Task<Result<R::Response>>
5085 where
5086 R: LspCommand,
5087 <R::LspRequest as lsp::request::Request>::Result: Send,
5088 <R::LspRequest as lsp::request::Request>::Params: Send,
5089 {
5090 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5091 return self.send_lsp_proto_request(
5092 buffer,
5093 upstream_client,
5094 upstream_project_id,
5095 request,
5096 cx,
5097 );
5098 }
5099
5100 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5101 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5102 local
5103 .language_servers_for_buffer(buffer, cx)
5104 .find(|(_, server)| {
5105 request.check_capabilities(server.adapter_server_capabilities())
5106 })
5107 .map(|(_, server)| server.clone())
5108 }),
5109 LanguageServerToQuery::Other(id) => self
5110 .language_server_for_local_buffer(buffer, id, cx)
5111 .and_then(|(_, server)| {
5112 request
5113 .check_capabilities(server.adapter_server_capabilities())
5114 .then(|| Arc::clone(server))
5115 }),
5116 }) else {
5117 return Task::ready(Ok(Default::default()));
5118 };
5119
5120 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5121
5122 let Some(file) = file else {
5123 return Task::ready(Ok(Default::default()));
5124 };
5125
5126 let lsp_params = match request.to_lsp_params_or_response(
5127 &file.abs_path(cx),
5128 buffer.read(cx),
5129 &language_server,
5130 cx,
5131 ) {
5132 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5133 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5134 Err(err) => {
5135 let message = format!(
5136 "{} via {} failed: {}",
5137 request.display_name(),
5138 language_server.name(),
5139 err
5140 );
5141 // rust-analyzer likes to error with this when its still loading up
5142 if !message.ends_with("content modified") {
5143 log::warn!("{message}");
5144 }
5145 return Task::ready(Err(anyhow!(message)));
5146 }
5147 };
5148
5149 let status = request.status();
5150 let request_timeout = ProjectSettings::get_global(cx)
5151 .global_lsp_settings
5152 .get_request_timeout();
5153
5154 cx.spawn(async move |this, cx| {
5155 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5156
5157 let id = lsp_request.id();
5158 let _cleanup = if status.is_some() {
5159 cx.update(|cx| {
5160 this.update(cx, |this, cx| {
5161 this.on_lsp_work_start(
5162 language_server.server_id(),
5163 ProgressToken::Number(id),
5164 LanguageServerProgress {
5165 is_disk_based_diagnostics_progress: false,
5166 is_cancellable: false,
5167 title: None,
5168 message: status.clone(),
5169 percentage: None,
5170 last_update_at: cx.background_executor().now(),
5171 },
5172 cx,
5173 );
5174 })
5175 })
5176 .log_err();
5177
5178 Some(defer(|| {
5179 cx.update(|cx| {
5180 this.update(cx, |this, cx| {
5181 this.on_lsp_work_end(
5182 language_server.server_id(),
5183 ProgressToken::Number(id),
5184 cx,
5185 );
5186 })
5187 })
5188 .log_err();
5189 }))
5190 } else {
5191 None
5192 };
5193
5194 let result = lsp_request.await.into_response();
5195
5196 let response = result.map_err(|err| {
5197 let message = format!(
5198 "{} via {} failed: {}",
5199 request.display_name(),
5200 language_server.name(),
5201 err
5202 );
5203 // rust-analyzer likes to error with this when its still loading up
5204 if !message.ends_with("content modified") {
5205 log::warn!("{message}");
5206 }
5207 anyhow::anyhow!(message)
5208 })?;
5209
5210 request
5211 .response_from_lsp(
5212 response,
5213 this.upgrade().context("no app context")?,
5214 buffer,
5215 language_server.server_id(),
5216 cx.clone(),
5217 )
5218 .await
5219 })
5220 }
5221
5222 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5223 let mut language_formatters_to_check = Vec::new();
5224 for buffer in self.buffer_store.read(cx).buffers() {
5225 let buffer = buffer.read(cx);
5226 let settings = LanguageSettings::for_buffer(buffer, cx);
5227 if buffer.language().is_some() {
5228 let buffer_file = File::from_dyn(buffer.file());
5229 language_formatters_to_check.push((
5230 buffer_file.map(|f| f.worktree_id(cx)),
5231 settings.into_owned(),
5232 ));
5233 }
5234 }
5235
5236 self.request_workspace_config_refresh();
5237
5238 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5239 prettier_store.update(cx, |prettier_store, cx| {
5240 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5241 })
5242 }
5243
5244 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5245 .global_lsp_settings
5246 .semantic_token_rules
5247 .clone();
5248 self.semantic_token_config
5249 .update_rules(new_semantic_token_rules);
5250 // Always clear cached stylizers so that changes to language-specific
5251 // semantic token rules (e.g. from extension install/uninstall) are
5252 // picked up. Stylizers are recreated lazily, so this is cheap.
5253 self.semantic_token_config.clear_stylizers();
5254
5255 let new_global_semantic_tokens_mode =
5256 all_language_settings(None, cx).defaults.semantic_tokens;
5257 if self
5258 .semantic_token_config
5259 .update_global_mode(new_global_semantic_tokens_mode)
5260 {
5261 self.restart_all_language_servers(cx);
5262 }
5263
5264 cx.notify();
5265 }
5266
5267 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5268 let buffer_store = self.buffer_store.clone();
5269 let Some(local) = self.as_local_mut() else {
5270 return;
5271 };
5272 let mut adapters = BTreeMap::default();
5273 let get_adapter = {
5274 let languages = local.languages.clone();
5275 let environment = local.environment.clone();
5276 let weak = local.weak.clone();
5277 let worktree_store = local.worktree_store.clone();
5278 let http_client = local.http_client.clone();
5279 let fs = local.fs.clone();
5280 move |worktree_id, cx: &mut App| {
5281 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5282 Some(LocalLspAdapterDelegate::new(
5283 languages.clone(),
5284 &environment,
5285 weak.clone(),
5286 &worktree,
5287 http_client.clone(),
5288 fs.clone(),
5289 cx,
5290 ))
5291 }
5292 };
5293
5294 let mut messages_to_report = Vec::new();
5295 let (new_tree, to_stop) = {
5296 let mut rebase = local.lsp_tree.rebase();
5297 let buffers = buffer_store
5298 .read(cx)
5299 .buffers()
5300 .filter_map(|buffer| {
5301 let raw_buffer = buffer.read(cx);
5302 if !local
5303 .registered_buffers
5304 .contains_key(&raw_buffer.remote_id())
5305 {
5306 return None;
5307 }
5308 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5309 let language = raw_buffer.language().cloned()?;
5310 Some((file, language, raw_buffer.remote_id()))
5311 })
5312 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5313 for (file, language, buffer_id) in buffers {
5314 let worktree_id = file.worktree_id(cx);
5315 let Some(worktree) = local
5316 .worktree_store
5317 .read(cx)
5318 .worktree_for_id(worktree_id, cx)
5319 else {
5320 continue;
5321 };
5322
5323 if let Some((_, apply)) = local.reuse_existing_language_server(
5324 rebase.server_tree(),
5325 &worktree,
5326 &language.name(),
5327 cx,
5328 ) {
5329 (apply)(rebase.server_tree());
5330 } else if let Some(lsp_delegate) = adapters
5331 .entry(worktree_id)
5332 .or_insert_with(|| get_adapter(worktree_id, cx))
5333 .clone()
5334 {
5335 let delegate =
5336 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5337 let path = file
5338 .path()
5339 .parent()
5340 .map(Arc::from)
5341 .unwrap_or_else(|| file.path().clone());
5342 let worktree_path = ProjectPath { worktree_id, path };
5343 let abs_path = file.abs_path(cx);
5344 let nodes = rebase
5345 .walk(
5346 worktree_path,
5347 language.name(),
5348 language.manifest(),
5349 delegate.clone(),
5350 cx,
5351 )
5352 .collect::<Vec<_>>();
5353 for node in nodes {
5354 let server_id = node.server_id_or_init(|disposition| {
5355 let path = &disposition.path;
5356 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5357 let key = LanguageServerSeed {
5358 worktree_id,
5359 name: disposition.server_name.clone(),
5360 settings: LanguageServerSeedSettings {
5361 binary: disposition.settings.binary.clone(),
5362 initialization_options: disposition
5363 .settings
5364 .initialization_options
5365 .clone(),
5366 },
5367 toolchain: local.toolchain_store.read(cx).active_toolchain(
5368 path.worktree_id,
5369 &path.path,
5370 language.name(),
5371 ),
5372 };
5373 local.language_server_ids.remove(&key);
5374
5375 let server_id = local.get_or_insert_language_server(
5376 &worktree,
5377 lsp_delegate.clone(),
5378 disposition,
5379 &language.name(),
5380 cx,
5381 );
5382 if let Some(state) = local.language_servers.get(&server_id)
5383 && let Ok(uri) = uri
5384 {
5385 state.add_workspace_folder(uri);
5386 };
5387 server_id
5388 });
5389
5390 if let Some(language_server_id) = server_id {
5391 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5392 language_server_id,
5393 name: node.name(),
5394 message:
5395 proto::update_language_server::Variant::RegisteredForBuffer(
5396 proto::RegisteredForBuffer {
5397 buffer_abs_path: abs_path
5398 .to_string_lossy()
5399 .into_owned(),
5400 buffer_id: buffer_id.to_proto(),
5401 },
5402 ),
5403 });
5404 }
5405 }
5406 } else {
5407 continue;
5408 }
5409 }
5410 rebase.finish()
5411 };
5412 for message in messages_to_report {
5413 cx.emit(message);
5414 }
5415 local.lsp_tree = new_tree;
5416 for (id, _) in to_stop {
5417 self.stop_local_language_server(id, cx).detach();
5418 }
5419 }
5420
5421 pub fn apply_code_action(
5422 &self,
5423 buffer_handle: Entity<Buffer>,
5424 mut action: CodeAction,
5425 push_to_history: bool,
5426 cx: &mut Context<Self>,
5427 ) -> Task<Result<ProjectTransaction>> {
5428 if let Some((upstream_client, project_id)) = self.upstream_client() {
5429 let request = proto::ApplyCodeAction {
5430 project_id,
5431 buffer_id: buffer_handle.read(cx).remote_id().into(),
5432 action: Some(Self::serialize_code_action(&action)),
5433 };
5434 let buffer_store = self.buffer_store();
5435 cx.spawn(async move |_, cx| {
5436 let response = upstream_client
5437 .request(request)
5438 .await?
5439 .transaction
5440 .context("missing transaction")?;
5441
5442 buffer_store
5443 .update(cx, |buffer_store, cx| {
5444 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5445 })
5446 .await
5447 })
5448 } else if self.mode.is_local() {
5449 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5450 let request_timeout = ProjectSettings::get_global(cx)
5451 .global_lsp_settings
5452 .get_request_timeout();
5453 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5454 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5455 }) else {
5456 return Task::ready(Ok(ProjectTransaction::default()));
5457 };
5458
5459 cx.spawn(async move |this, cx| {
5460 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5461 .await
5462 .context("resolving a code action")?;
5463 if let Some(edit) = action.lsp_action.edit()
5464 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5465 return LocalLspStore::deserialize_workspace_edit(
5466 this.upgrade().context("no app present")?,
5467 edit.clone(),
5468 push_to_history,
5469
5470 lang_server.clone(),
5471 cx,
5472 )
5473 .await;
5474 }
5475
5476 let Some(command) = action.lsp_action.command() else {
5477 return Ok(ProjectTransaction::default())
5478 };
5479
5480 let server_capabilities = lang_server.capabilities();
5481 let available_commands = server_capabilities
5482 .execute_command_provider
5483 .as_ref()
5484 .map(|options| options.commands.as_slice())
5485 .unwrap_or_default();
5486
5487 if !available_commands.contains(&command.command) {
5488 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5489 return Ok(ProjectTransaction::default())
5490 }
5491
5492 let request_timeout = cx.update(|app|
5493 ProjectSettings::get_global(app)
5494 .global_lsp_settings
5495 .get_request_timeout()
5496 );
5497
5498 this.update(cx, |this, _| {
5499 this.as_local_mut()
5500 .unwrap()
5501 .last_workspace_edits_by_language_server
5502 .remove(&lang_server.server_id());
5503 })?;
5504
5505 let _result = lang_server
5506 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5507 command: command.command.clone(),
5508 arguments: command.arguments.clone().unwrap_or_default(),
5509 ..lsp::ExecuteCommandParams::default()
5510 }, request_timeout)
5511 .await.into_response()
5512 .context("execute command")?;
5513
5514 return this.update(cx, |this, _| {
5515 this.as_local_mut()
5516 .unwrap()
5517 .last_workspace_edits_by_language_server
5518 .remove(&lang_server.server_id())
5519 .unwrap_or_default()
5520 });
5521 })
5522 } else {
5523 Task::ready(Err(anyhow!("no upstream client and not local")))
5524 }
5525 }
5526
5527 pub fn apply_code_action_kind(
5528 &mut self,
5529 buffers: HashSet<Entity<Buffer>>,
5530 kind: CodeActionKind,
5531 push_to_history: bool,
5532 cx: &mut Context<Self>,
5533 ) -> Task<anyhow::Result<ProjectTransaction>> {
5534 if self.as_local().is_some() {
5535 cx.spawn(async move |lsp_store, cx| {
5536 let buffers = buffers.into_iter().collect::<Vec<_>>();
5537 let result = LocalLspStore::execute_code_action_kind_locally(
5538 lsp_store.clone(),
5539 buffers,
5540 kind,
5541 push_to_history,
5542 cx,
5543 )
5544 .await;
5545 lsp_store.update(cx, |lsp_store, _| {
5546 lsp_store.update_last_formatting_failure(&result);
5547 })?;
5548 result
5549 })
5550 } else if let Some((client, project_id)) = self.upstream_client() {
5551 let buffer_store = self.buffer_store();
5552 cx.spawn(async move |lsp_store, cx| {
5553 let result = client
5554 .request(proto::ApplyCodeActionKind {
5555 project_id,
5556 kind: kind.as_str().to_owned(),
5557 buffer_ids: buffers
5558 .iter()
5559 .map(|buffer| {
5560 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5561 })
5562 .collect(),
5563 })
5564 .await
5565 .and_then(|result| result.transaction.context("missing transaction"));
5566 lsp_store.update(cx, |lsp_store, _| {
5567 lsp_store.update_last_formatting_failure(&result);
5568 })?;
5569
5570 let transaction_response = result?;
5571 buffer_store
5572 .update(cx, |buffer_store, cx| {
5573 buffer_store.deserialize_project_transaction(
5574 transaction_response,
5575 push_to_history,
5576 cx,
5577 )
5578 })
5579 .await
5580 })
5581 } else {
5582 Task::ready(Ok(ProjectTransaction::default()))
5583 }
5584 }
5585
5586 pub fn resolved_hint(
5587 &mut self,
5588 buffer_id: BufferId,
5589 id: InlayId,
5590 cx: &mut Context<Self>,
5591 ) -> Option<ResolvedHint> {
5592 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5593
5594 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5595 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5596 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5597 let (server_id, resolve_data) = match &hint.resolve_state {
5598 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5599 ResolveState::Resolving => {
5600 return Some(ResolvedHint::Resolving(
5601 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5602 ));
5603 }
5604 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5605 };
5606
5607 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5608 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5609 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5610 id,
5611 cx.spawn(async move |lsp_store, cx| {
5612 let resolved_hint = resolve_task.await;
5613 lsp_store
5614 .update(cx, |lsp_store, _| {
5615 if let Some(old_inlay_hint) = lsp_store
5616 .lsp_data
5617 .get_mut(&buffer_id)
5618 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5619 {
5620 match resolved_hint {
5621 Ok(resolved_hint) => {
5622 *old_inlay_hint = resolved_hint;
5623 }
5624 Err(e) => {
5625 old_inlay_hint.resolve_state =
5626 ResolveState::CanResolve(server_id, resolve_data);
5627 log::error!("Inlay hint resolve failed: {e:#}");
5628 }
5629 }
5630 }
5631 })
5632 .ok();
5633 })
5634 .shared(),
5635 );
5636 debug_assert!(
5637 previous_task.is_none(),
5638 "Did not change hint's resolve state after spawning its resolve"
5639 );
5640 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5641 None
5642 }
5643
5644 pub(crate) fn linked_edits(
5645 &mut self,
5646 buffer: &Entity<Buffer>,
5647 position: Anchor,
5648 cx: &mut Context<Self>,
5649 ) -> Task<Result<Vec<Range<Anchor>>>> {
5650 let snapshot = buffer.read(cx).snapshot();
5651 let scope = snapshot.language_scope_at(position);
5652 let Some(server_id) = self
5653 .as_local()
5654 .and_then(|local| {
5655 buffer.update(cx, |buffer, cx| {
5656 local
5657 .language_servers_for_buffer(buffer, cx)
5658 .filter(|(_, server)| {
5659 LinkedEditingRange::check_server_capabilities(server.capabilities())
5660 })
5661 .filter(|(adapter, _)| {
5662 scope
5663 .as_ref()
5664 .map(|scope| scope.language_allowed(&adapter.name))
5665 .unwrap_or(true)
5666 })
5667 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5668 .next()
5669 })
5670 })
5671 .or_else(|| {
5672 self.upstream_client()
5673 .is_some()
5674 .then_some(LanguageServerToQuery::FirstCapable)
5675 })
5676 .filter(|_| {
5677 maybe!({
5678 buffer.read(cx).language_at(position)?;
5679 Some(
5680 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5681 .linked_edits,
5682 )
5683 }) == Some(true)
5684 })
5685 else {
5686 return Task::ready(Ok(Vec::new()));
5687 };
5688
5689 self.request_lsp(
5690 buffer.clone(),
5691 server_id,
5692 LinkedEditingRange { position },
5693 cx,
5694 )
5695 }
5696
5697 fn apply_on_type_formatting(
5698 &mut self,
5699 buffer: Entity<Buffer>,
5700 position: Anchor,
5701 trigger: String,
5702 cx: &mut Context<Self>,
5703 ) -> Task<Result<Option<Transaction>>> {
5704 if let Some((client, project_id)) = self.upstream_client() {
5705 if !self.check_if_capable_for_proto_request(
5706 &buffer,
5707 |capabilities| {
5708 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5709 },
5710 cx,
5711 ) {
5712 return Task::ready(Ok(None));
5713 }
5714 let request = proto::OnTypeFormatting {
5715 project_id,
5716 buffer_id: buffer.read(cx).remote_id().into(),
5717 position: Some(serialize_anchor(&position)),
5718 trigger,
5719 version: serialize_version(&buffer.read(cx).version()),
5720 };
5721 cx.background_spawn(async move {
5722 client
5723 .request(request)
5724 .await?
5725 .transaction
5726 .map(language::proto::deserialize_transaction)
5727 .transpose()
5728 })
5729 } else if let Some(local) = self.as_local_mut() {
5730 let buffer_id = buffer.read(cx).remote_id();
5731 local.buffers_being_formatted.insert(buffer_id);
5732 cx.spawn(async move |this, cx| {
5733 let _cleanup = defer({
5734 let this = this.clone();
5735 let mut cx = cx.clone();
5736 move || {
5737 this.update(&mut cx, |this, _| {
5738 if let Some(local) = this.as_local_mut() {
5739 local.buffers_being_formatted.remove(&buffer_id);
5740 }
5741 })
5742 .ok();
5743 }
5744 });
5745
5746 buffer
5747 .update(cx, |buffer, _| {
5748 buffer.wait_for_edits(Some(position.timestamp()))
5749 })
5750 .await?;
5751 this.update(cx, |this, cx| {
5752 let position = position.to_point_utf16(buffer.read(cx));
5753 this.on_type_format(buffer, position, trigger, false, cx)
5754 })?
5755 .await
5756 })
5757 } else {
5758 Task::ready(Err(anyhow!("No upstream client or local language server")))
5759 }
5760 }
5761
5762 pub fn on_type_format<T: ToPointUtf16>(
5763 &mut self,
5764 buffer: Entity<Buffer>,
5765 position: T,
5766 trigger: String,
5767 push_to_history: bool,
5768 cx: &mut Context<Self>,
5769 ) -> Task<Result<Option<Transaction>>> {
5770 let position = position.to_point_utf16(buffer.read(cx));
5771 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5772 }
5773
5774 fn on_type_format_impl(
5775 &mut self,
5776 buffer: Entity<Buffer>,
5777 position: PointUtf16,
5778 trigger: String,
5779 push_to_history: bool,
5780 cx: &mut Context<Self>,
5781 ) -> Task<Result<Option<Transaction>>> {
5782 let options = buffer.update(cx, |buffer, cx| {
5783 lsp_command::lsp_formatting_options(
5784 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5785 )
5786 });
5787
5788 cx.spawn(async move |this, cx| {
5789 if let Some(waiter) =
5790 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5791 {
5792 waiter.await?;
5793 }
5794 cx.update(|cx| {
5795 this.update(cx, |this, cx| {
5796 this.request_lsp(
5797 buffer.clone(),
5798 LanguageServerToQuery::FirstCapable,
5799 OnTypeFormatting {
5800 position,
5801 trigger,
5802 options,
5803 push_to_history,
5804 },
5805 cx,
5806 )
5807 })
5808 })?
5809 .await
5810 })
5811 }
5812
5813 pub fn definitions(
5814 &mut self,
5815 buffer: &Entity<Buffer>,
5816 position: PointUtf16,
5817 cx: &mut Context<Self>,
5818 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5819 if let Some((upstream_client, project_id)) = self.upstream_client() {
5820 let request = GetDefinitions { position };
5821 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5822 return Task::ready(Ok(None));
5823 }
5824
5825 let request_timeout = ProjectSettings::get_global(cx)
5826 .global_lsp_settings
5827 .get_request_timeout();
5828
5829 let request_task = upstream_client.request_lsp(
5830 project_id,
5831 None,
5832 request_timeout,
5833 cx.background_executor().clone(),
5834 request.to_proto(project_id, buffer.read(cx)),
5835 );
5836 let buffer = buffer.clone();
5837 cx.spawn(async move |weak_lsp_store, cx| {
5838 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5839 return Ok(None);
5840 };
5841 let Some(responses) = request_task.await? else {
5842 return Ok(None);
5843 };
5844 let actions = join_all(responses.payload.into_iter().map(|response| {
5845 GetDefinitions { position }.response_from_proto(
5846 response.response,
5847 lsp_store.clone(),
5848 buffer.clone(),
5849 cx.clone(),
5850 )
5851 }))
5852 .await;
5853
5854 Ok(Some(
5855 actions
5856 .into_iter()
5857 .collect::<Result<Vec<Vec<_>>>>()?
5858 .into_iter()
5859 .flatten()
5860 .dedup()
5861 .collect(),
5862 ))
5863 })
5864 } else {
5865 let definitions_task = self.request_multiple_lsp_locally(
5866 buffer,
5867 Some(position),
5868 GetDefinitions { position },
5869 cx,
5870 );
5871 cx.background_spawn(async move {
5872 Ok(Some(
5873 definitions_task
5874 .await
5875 .into_iter()
5876 .flat_map(|(_, definitions)| definitions)
5877 .dedup()
5878 .collect(),
5879 ))
5880 })
5881 }
5882 }
5883
5884 pub fn declarations(
5885 &mut self,
5886 buffer: &Entity<Buffer>,
5887 position: PointUtf16,
5888 cx: &mut Context<Self>,
5889 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5890 if let Some((upstream_client, project_id)) = self.upstream_client() {
5891 let request = GetDeclarations { position };
5892 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5893 return Task::ready(Ok(None));
5894 }
5895 let request_timeout = ProjectSettings::get_global(cx)
5896 .global_lsp_settings
5897 .get_request_timeout();
5898 let request_task = upstream_client.request_lsp(
5899 project_id,
5900 None,
5901 request_timeout,
5902 cx.background_executor().clone(),
5903 request.to_proto(project_id, buffer.read(cx)),
5904 );
5905 let buffer = buffer.clone();
5906 cx.spawn(async move |weak_lsp_store, cx| {
5907 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5908 return Ok(None);
5909 };
5910 let Some(responses) = request_task.await? else {
5911 return Ok(None);
5912 };
5913 let actions = join_all(responses.payload.into_iter().map(|response| {
5914 GetDeclarations { position }.response_from_proto(
5915 response.response,
5916 lsp_store.clone(),
5917 buffer.clone(),
5918 cx.clone(),
5919 )
5920 }))
5921 .await;
5922
5923 Ok(Some(
5924 actions
5925 .into_iter()
5926 .collect::<Result<Vec<Vec<_>>>>()?
5927 .into_iter()
5928 .flatten()
5929 .dedup()
5930 .collect(),
5931 ))
5932 })
5933 } else {
5934 let declarations_task = self.request_multiple_lsp_locally(
5935 buffer,
5936 Some(position),
5937 GetDeclarations { position },
5938 cx,
5939 );
5940 cx.background_spawn(async move {
5941 Ok(Some(
5942 declarations_task
5943 .await
5944 .into_iter()
5945 .flat_map(|(_, declarations)| declarations)
5946 .dedup()
5947 .collect(),
5948 ))
5949 })
5950 }
5951 }
5952
5953 pub fn type_definitions(
5954 &mut self,
5955 buffer: &Entity<Buffer>,
5956 position: PointUtf16,
5957 cx: &mut Context<Self>,
5958 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5959 if let Some((upstream_client, project_id)) = self.upstream_client() {
5960 let request = GetTypeDefinitions { position };
5961 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5962 return Task::ready(Ok(None));
5963 }
5964 let request_timeout = ProjectSettings::get_global(cx)
5965 .global_lsp_settings
5966 .get_request_timeout();
5967 let request_task = upstream_client.request_lsp(
5968 project_id,
5969 None,
5970 request_timeout,
5971 cx.background_executor().clone(),
5972 request.to_proto(project_id, buffer.read(cx)),
5973 );
5974 let buffer = buffer.clone();
5975 cx.spawn(async move |weak_lsp_store, cx| {
5976 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5977 return Ok(None);
5978 };
5979 let Some(responses) = request_task.await? else {
5980 return Ok(None);
5981 };
5982 let actions = join_all(responses.payload.into_iter().map(|response| {
5983 GetTypeDefinitions { position }.response_from_proto(
5984 response.response,
5985 lsp_store.clone(),
5986 buffer.clone(),
5987 cx.clone(),
5988 )
5989 }))
5990 .await;
5991
5992 Ok(Some(
5993 actions
5994 .into_iter()
5995 .collect::<Result<Vec<Vec<_>>>>()?
5996 .into_iter()
5997 .flatten()
5998 .dedup()
5999 .collect(),
6000 ))
6001 })
6002 } else {
6003 let type_definitions_task = self.request_multiple_lsp_locally(
6004 buffer,
6005 Some(position),
6006 GetTypeDefinitions { position },
6007 cx,
6008 );
6009 cx.background_spawn(async move {
6010 Ok(Some(
6011 type_definitions_task
6012 .await
6013 .into_iter()
6014 .flat_map(|(_, type_definitions)| type_definitions)
6015 .dedup()
6016 .collect(),
6017 ))
6018 })
6019 }
6020 }
6021
6022 pub fn implementations(
6023 &mut self,
6024 buffer: &Entity<Buffer>,
6025 position: PointUtf16,
6026 cx: &mut Context<Self>,
6027 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6028 if let Some((upstream_client, project_id)) = self.upstream_client() {
6029 let request = GetImplementations { position };
6030 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6031 return Task::ready(Ok(None));
6032 }
6033
6034 let request_timeout = ProjectSettings::get_global(cx)
6035 .global_lsp_settings
6036 .get_request_timeout();
6037 let request_task = upstream_client.request_lsp(
6038 project_id,
6039 None,
6040 request_timeout,
6041 cx.background_executor().clone(),
6042 request.to_proto(project_id, buffer.read(cx)),
6043 );
6044 let buffer = buffer.clone();
6045 cx.spawn(async move |weak_lsp_store, cx| {
6046 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6047 return Ok(None);
6048 };
6049 let Some(responses) = request_task.await? else {
6050 return Ok(None);
6051 };
6052 let actions = join_all(responses.payload.into_iter().map(|response| {
6053 GetImplementations { position }.response_from_proto(
6054 response.response,
6055 lsp_store.clone(),
6056 buffer.clone(),
6057 cx.clone(),
6058 )
6059 }))
6060 .await;
6061
6062 Ok(Some(
6063 actions
6064 .into_iter()
6065 .collect::<Result<Vec<Vec<_>>>>()?
6066 .into_iter()
6067 .flatten()
6068 .dedup()
6069 .collect(),
6070 ))
6071 })
6072 } else {
6073 let implementations_task = self.request_multiple_lsp_locally(
6074 buffer,
6075 Some(position),
6076 GetImplementations { position },
6077 cx,
6078 );
6079 cx.background_spawn(async move {
6080 Ok(Some(
6081 implementations_task
6082 .await
6083 .into_iter()
6084 .flat_map(|(_, implementations)| implementations)
6085 .dedup()
6086 .collect(),
6087 ))
6088 })
6089 }
6090 }
6091
6092 pub fn references(
6093 &mut self,
6094 buffer: &Entity<Buffer>,
6095 position: PointUtf16,
6096 cx: &mut Context<Self>,
6097 ) -> Task<Result<Option<Vec<Location>>>> {
6098 if let Some((upstream_client, project_id)) = self.upstream_client() {
6099 let request = GetReferences { position };
6100 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6101 return Task::ready(Ok(None));
6102 }
6103
6104 let request_timeout = ProjectSettings::get_global(cx)
6105 .global_lsp_settings
6106 .get_request_timeout();
6107 let request_task = upstream_client.request_lsp(
6108 project_id,
6109 None,
6110 request_timeout,
6111 cx.background_executor().clone(),
6112 request.to_proto(project_id, buffer.read(cx)),
6113 );
6114 let buffer = buffer.clone();
6115 cx.spawn(async move |weak_lsp_store, cx| {
6116 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6117 return Ok(None);
6118 };
6119 let Some(responses) = request_task.await? else {
6120 return Ok(None);
6121 };
6122
6123 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6124 GetReferences { position }.response_from_proto(
6125 lsp_response.response,
6126 lsp_store.clone(),
6127 buffer.clone(),
6128 cx.clone(),
6129 )
6130 }))
6131 .await
6132 .into_iter()
6133 .collect::<Result<Vec<Vec<_>>>>()?
6134 .into_iter()
6135 .flatten()
6136 .dedup()
6137 .collect();
6138 Ok(Some(locations))
6139 })
6140 } else {
6141 let references_task = self.request_multiple_lsp_locally(
6142 buffer,
6143 Some(position),
6144 GetReferences { position },
6145 cx,
6146 );
6147 cx.background_spawn(async move {
6148 Ok(Some(
6149 references_task
6150 .await
6151 .into_iter()
6152 .flat_map(|(_, references)| references)
6153 .dedup()
6154 .collect(),
6155 ))
6156 })
6157 }
6158 }
6159
6160 pub fn code_actions(
6161 &mut self,
6162 buffer: &Entity<Buffer>,
6163 range: Range<Anchor>,
6164 kinds: Option<Vec<CodeActionKind>>,
6165 cx: &mut Context<Self>,
6166 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6167 if let Some((upstream_client, project_id)) = self.upstream_client() {
6168 let request = GetCodeActions {
6169 range: range.clone(),
6170 kinds: kinds.clone(),
6171 };
6172 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6173 return Task::ready(Ok(None));
6174 }
6175 let request_timeout = ProjectSettings::get_global(cx)
6176 .global_lsp_settings
6177 .get_request_timeout();
6178 let request_task = upstream_client.request_lsp(
6179 project_id,
6180 None,
6181 request_timeout,
6182 cx.background_executor().clone(),
6183 request.to_proto(project_id, buffer.read(cx)),
6184 );
6185 let buffer = buffer.clone();
6186 cx.spawn(async move |weak_lsp_store, cx| {
6187 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6188 return Ok(None);
6189 };
6190 let Some(responses) = request_task.await? else {
6191 return Ok(None);
6192 };
6193 let actions = join_all(responses.payload.into_iter().map(|response| {
6194 GetCodeActions {
6195 range: range.clone(),
6196 kinds: kinds.clone(),
6197 }
6198 .response_from_proto(
6199 response.response,
6200 lsp_store.clone(),
6201 buffer.clone(),
6202 cx.clone(),
6203 )
6204 }))
6205 .await;
6206
6207 Ok(Some(
6208 actions
6209 .into_iter()
6210 .collect::<Result<Vec<Vec<_>>>>()?
6211 .into_iter()
6212 .flatten()
6213 .collect(),
6214 ))
6215 })
6216 } else {
6217 let all_actions_task = self.request_multiple_lsp_locally(
6218 buffer,
6219 Some(range.start),
6220 GetCodeActions { range, kinds },
6221 cx,
6222 );
6223 cx.background_spawn(async move {
6224 Ok(Some(
6225 all_actions_task
6226 .await
6227 .into_iter()
6228 .flat_map(|(_, actions)| actions)
6229 .collect(),
6230 ))
6231 })
6232 }
6233 }
6234
6235 #[inline(never)]
6236 pub fn completions(
6237 &self,
6238 buffer: &Entity<Buffer>,
6239 position: PointUtf16,
6240 context: CompletionContext,
6241 cx: &mut Context<Self>,
6242 ) -> Task<Result<Vec<CompletionResponse>>> {
6243 let language_registry = self.languages.clone();
6244
6245 if let Some((upstream_client, project_id)) = self.upstream_client() {
6246 let snapshot = buffer.read(cx).snapshot();
6247 let offset = position.to_offset(&snapshot);
6248 let scope = snapshot.language_scope_at(offset);
6249 let capable_lsps = self.all_capable_for_proto_request(
6250 buffer,
6251 |server_name, capabilities| {
6252 capabilities.completion_provider.is_some()
6253 && scope
6254 .as_ref()
6255 .map(|scope| scope.language_allowed(server_name))
6256 .unwrap_or(true)
6257 },
6258 cx,
6259 );
6260 if capable_lsps.is_empty() {
6261 return Task::ready(Ok(Vec::new()));
6262 }
6263
6264 let language = buffer.read(cx).language().cloned();
6265
6266 let buffer = buffer.clone();
6267
6268 cx.spawn(async move |this, cx| {
6269 let requests = join_all(
6270 capable_lsps
6271 .into_iter()
6272 .map(|(id, server_name)| {
6273 let request = GetCompletions {
6274 position,
6275 context: context.clone(),
6276 server_id: Some(id),
6277 };
6278 let buffer = buffer.clone();
6279 let language = language.clone();
6280 let lsp_adapter = language.as_ref().and_then(|language| {
6281 let adapters = language_registry.lsp_adapters(&language.name());
6282 adapters
6283 .iter()
6284 .find(|adapter| adapter.name() == server_name)
6285 .or_else(|| adapters.first())
6286 .cloned()
6287 });
6288 let upstream_client = upstream_client.clone();
6289 let response = this
6290 .update(cx, |this, cx| {
6291 this.send_lsp_proto_request(
6292 buffer,
6293 upstream_client,
6294 project_id,
6295 request,
6296 cx,
6297 )
6298 })
6299 .log_err();
6300 async move {
6301 let response = response?.await.log_err()?;
6302
6303 let completions = populate_labels_for_completions(
6304 response.completions,
6305 language,
6306 lsp_adapter,
6307 )
6308 .await;
6309
6310 Some(CompletionResponse {
6311 completions,
6312 display_options: CompletionDisplayOptions::default(),
6313 is_incomplete: response.is_incomplete,
6314 })
6315 }
6316 })
6317 .collect::<Vec<_>>(),
6318 );
6319 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6320 })
6321 } else if let Some(local) = self.as_local() {
6322 let snapshot = buffer.read(cx).snapshot();
6323 let offset = position.to_offset(&snapshot);
6324 let scope = snapshot.language_scope_at(offset);
6325 let language = snapshot.language().cloned();
6326 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6327 .completions
6328 .clone();
6329 if !completion_settings.lsp {
6330 return Task::ready(Ok(Vec::new()));
6331 }
6332
6333 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6334 local
6335 .language_servers_for_buffer(buffer, cx)
6336 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6337 .filter(|(adapter, _)| {
6338 scope
6339 .as_ref()
6340 .map(|scope| scope.language_allowed(&adapter.name))
6341 .unwrap_or(true)
6342 })
6343 .map(|(_, server)| server.server_id())
6344 .collect()
6345 });
6346
6347 let buffer = buffer.clone();
6348 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6349 let lsp_timeout = if lsp_timeout > 0 {
6350 Some(Duration::from_millis(lsp_timeout))
6351 } else {
6352 None
6353 };
6354 cx.spawn(async move |this, cx| {
6355 let mut tasks = Vec::with_capacity(server_ids.len());
6356 this.update(cx, |lsp_store, cx| {
6357 for server_id in server_ids {
6358 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6359 let lsp_timeout = lsp_timeout
6360 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6361 let mut timeout = cx.background_spawn(async move {
6362 match lsp_timeout {
6363 Some(lsp_timeout) => {
6364 lsp_timeout.await;
6365 true
6366 },
6367 None => false,
6368 }
6369 }).fuse();
6370 let mut lsp_request = lsp_store.request_lsp(
6371 buffer.clone(),
6372 LanguageServerToQuery::Other(server_id),
6373 GetCompletions {
6374 position,
6375 context: context.clone(),
6376 server_id: Some(server_id),
6377 },
6378 cx,
6379 ).fuse();
6380 let new_task = cx.background_spawn(async move {
6381 select_biased! {
6382 response = lsp_request => anyhow::Ok(Some(response?)),
6383 timeout_happened = timeout => {
6384 if timeout_happened {
6385 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6386 Ok(None)
6387 } else {
6388 let completions = lsp_request.await?;
6389 Ok(Some(completions))
6390 }
6391 },
6392 }
6393 });
6394 tasks.push((lsp_adapter, new_task));
6395 }
6396 })?;
6397
6398 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6399 let completion_response = task.await.ok()??;
6400 let completions = populate_labels_for_completions(
6401 completion_response.completions,
6402 language.clone(),
6403 lsp_adapter,
6404 )
6405 .await;
6406 Some(CompletionResponse {
6407 completions,
6408 display_options: CompletionDisplayOptions::default(),
6409 is_incomplete: completion_response.is_incomplete,
6410 })
6411 });
6412
6413 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6414
6415 Ok(responses.into_iter().flatten().collect())
6416 })
6417 } else {
6418 Task::ready(Err(anyhow!("No upstream client or local language server")))
6419 }
6420 }
6421
6422 pub fn resolve_completions(
6423 &self,
6424 buffer: Entity<Buffer>,
6425 completion_indices: Vec<usize>,
6426 completions: Rc<RefCell<Box<[Completion]>>>,
6427 cx: &mut Context<Self>,
6428 ) -> Task<Result<bool>> {
6429 let client = self.upstream_client();
6430 let buffer_id = buffer.read(cx).remote_id();
6431 let buffer_snapshot = buffer.read(cx).snapshot();
6432
6433 if !self.check_if_capable_for_proto_request(
6434 &buffer,
6435 GetCompletions::can_resolve_completions,
6436 cx,
6437 ) {
6438 return Task::ready(Ok(false));
6439 }
6440 cx.spawn(async move |lsp_store, cx| {
6441 let request_timeout = cx.update(|app| {
6442 ProjectSettings::get_global(app)
6443 .global_lsp_settings
6444 .get_request_timeout()
6445 });
6446
6447 let mut did_resolve = false;
6448 if let Some((client, project_id)) = client {
6449 for completion_index in completion_indices {
6450 let server_id = {
6451 let completion = &completions.borrow()[completion_index];
6452 completion.source.server_id()
6453 };
6454 if let Some(server_id) = server_id {
6455 if Self::resolve_completion_remote(
6456 project_id,
6457 server_id,
6458 buffer_id,
6459 completions.clone(),
6460 completion_index,
6461 client.clone(),
6462 )
6463 .await
6464 .log_err()
6465 .is_some()
6466 {
6467 did_resolve = true;
6468 }
6469 } else {
6470 resolve_word_completion(
6471 &buffer_snapshot,
6472 &mut completions.borrow_mut()[completion_index],
6473 );
6474 }
6475 }
6476 } else {
6477 for completion_index in completion_indices {
6478 let server_id = {
6479 let completion = &completions.borrow()[completion_index];
6480 completion.source.server_id()
6481 };
6482 if let Some(server_id) = server_id {
6483 let server_and_adapter = lsp_store
6484 .read_with(cx, |lsp_store, _| {
6485 let server = lsp_store.language_server_for_id(server_id)?;
6486 let adapter =
6487 lsp_store.language_server_adapter_for_id(server.server_id())?;
6488 Some((server, adapter))
6489 })
6490 .ok()
6491 .flatten();
6492 let Some((server, adapter)) = server_and_adapter else {
6493 continue;
6494 };
6495
6496 let resolved = Self::resolve_completion_local(
6497 server,
6498 completions.clone(),
6499 completion_index,
6500 request_timeout,
6501 )
6502 .await
6503 .log_err()
6504 .is_some();
6505 if resolved {
6506 Self::regenerate_completion_labels(
6507 adapter,
6508 &buffer_snapshot,
6509 completions.clone(),
6510 completion_index,
6511 )
6512 .await
6513 .log_err();
6514 did_resolve = true;
6515 }
6516 } else {
6517 resolve_word_completion(
6518 &buffer_snapshot,
6519 &mut completions.borrow_mut()[completion_index],
6520 );
6521 }
6522 }
6523 }
6524
6525 Ok(did_resolve)
6526 })
6527 }
6528
6529 async fn resolve_completion_local(
6530 server: Arc<lsp::LanguageServer>,
6531 completions: Rc<RefCell<Box<[Completion]>>>,
6532 completion_index: usize,
6533 request_timeout: Duration,
6534 ) -> Result<()> {
6535 let server_id = server.server_id();
6536 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6537 return Ok(());
6538 }
6539
6540 let request = {
6541 let completion = &completions.borrow()[completion_index];
6542 match &completion.source {
6543 CompletionSource::Lsp {
6544 lsp_completion,
6545 resolved,
6546 server_id: completion_server_id,
6547 ..
6548 } => {
6549 if *resolved {
6550 return Ok(());
6551 }
6552 anyhow::ensure!(
6553 server_id == *completion_server_id,
6554 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6555 );
6556 server.request::<lsp::request::ResolveCompletionItem>(
6557 *lsp_completion.clone(),
6558 request_timeout,
6559 )
6560 }
6561 CompletionSource::BufferWord { .. }
6562 | CompletionSource::Dap { .. }
6563 | CompletionSource::Custom => {
6564 return Ok(());
6565 }
6566 }
6567 };
6568 let resolved_completion = request
6569 .await
6570 .into_response()
6571 .context("resolve completion")?;
6572
6573 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6574 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6575
6576 let mut completions = completions.borrow_mut();
6577 let completion = &mut completions[completion_index];
6578 if let CompletionSource::Lsp {
6579 lsp_completion,
6580 resolved,
6581 server_id: completion_server_id,
6582 ..
6583 } = &mut completion.source
6584 {
6585 if *resolved {
6586 return Ok(());
6587 }
6588 anyhow::ensure!(
6589 server_id == *completion_server_id,
6590 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6591 );
6592 **lsp_completion = resolved_completion;
6593 *resolved = true;
6594 }
6595 Ok(())
6596 }
6597
6598 async fn regenerate_completion_labels(
6599 adapter: Arc<CachedLspAdapter>,
6600 snapshot: &BufferSnapshot,
6601 completions: Rc<RefCell<Box<[Completion]>>>,
6602 completion_index: usize,
6603 ) -> Result<()> {
6604 let completion_item = completions.borrow()[completion_index]
6605 .source
6606 .lsp_completion(true)
6607 .map(Cow::into_owned);
6608 if let Some(lsp_documentation) = completion_item
6609 .as_ref()
6610 .and_then(|completion_item| completion_item.documentation.clone())
6611 {
6612 let mut completions = completions.borrow_mut();
6613 let completion = &mut completions[completion_index];
6614 completion.documentation = Some(lsp_documentation.into());
6615 } else {
6616 let mut completions = completions.borrow_mut();
6617 let completion = &mut completions[completion_index];
6618 completion.documentation = Some(CompletionDocumentation::Undocumented);
6619 }
6620
6621 let mut new_label = match completion_item {
6622 Some(completion_item) => {
6623 // Some language servers always return `detail` lazily via resolve, regardless of
6624 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6625 // See: https://github.com/yioneko/vtsls/issues/213
6626 let language = snapshot.language();
6627 match language {
6628 Some(language) => {
6629 adapter
6630 .labels_for_completions(
6631 std::slice::from_ref(&completion_item),
6632 language,
6633 )
6634 .await?
6635 }
6636 None => Vec::new(),
6637 }
6638 .pop()
6639 .flatten()
6640 .unwrap_or_else(|| {
6641 CodeLabel::fallback_for_completion(
6642 &completion_item,
6643 language.map(|language| language.as_ref()),
6644 )
6645 })
6646 }
6647 None => CodeLabel::plain(
6648 completions.borrow()[completion_index].new_text.clone(),
6649 None,
6650 ),
6651 };
6652 ensure_uniform_list_compatible_label(&mut new_label);
6653
6654 let mut completions = completions.borrow_mut();
6655 let completion = &mut completions[completion_index];
6656 if completion.label.filter_text() == new_label.filter_text() {
6657 completion.label = new_label;
6658 } else {
6659 log::error!(
6660 "Resolved completion changed display label from {} to {}. \
6661 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6662 completion.label.text(),
6663 new_label.text(),
6664 completion.label.filter_text(),
6665 new_label.filter_text()
6666 );
6667 }
6668
6669 Ok(())
6670 }
6671
6672 async fn resolve_completion_remote(
6673 project_id: u64,
6674 server_id: LanguageServerId,
6675 buffer_id: BufferId,
6676 completions: Rc<RefCell<Box<[Completion]>>>,
6677 completion_index: usize,
6678 client: AnyProtoClient,
6679 ) -> Result<()> {
6680 let lsp_completion = {
6681 let completion = &completions.borrow()[completion_index];
6682 match &completion.source {
6683 CompletionSource::Lsp {
6684 lsp_completion,
6685 resolved,
6686 server_id: completion_server_id,
6687 ..
6688 } => {
6689 anyhow::ensure!(
6690 server_id == *completion_server_id,
6691 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6692 );
6693 if *resolved {
6694 return Ok(());
6695 }
6696 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6697 }
6698 CompletionSource::Custom
6699 | CompletionSource::Dap { .. }
6700 | CompletionSource::BufferWord { .. } => {
6701 return Ok(());
6702 }
6703 }
6704 };
6705 let request = proto::ResolveCompletionDocumentation {
6706 project_id,
6707 language_server_id: server_id.0 as u64,
6708 lsp_completion,
6709 buffer_id: buffer_id.into(),
6710 };
6711
6712 let response = client
6713 .request(request)
6714 .await
6715 .context("completion documentation resolve proto request")?;
6716 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6717
6718 let documentation = if response.documentation.is_empty() {
6719 CompletionDocumentation::Undocumented
6720 } else if response.documentation_is_markdown {
6721 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6722 } else if response.documentation.lines().count() <= 1 {
6723 CompletionDocumentation::SingleLine(response.documentation.into())
6724 } else {
6725 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6726 };
6727
6728 let mut completions = completions.borrow_mut();
6729 let completion = &mut completions[completion_index];
6730 completion.documentation = Some(documentation);
6731 if let CompletionSource::Lsp {
6732 insert_range,
6733 lsp_completion,
6734 resolved,
6735 server_id: completion_server_id,
6736 lsp_defaults: _,
6737 } = &mut completion.source
6738 {
6739 let completion_insert_range = response
6740 .old_insert_start
6741 .and_then(deserialize_anchor)
6742 .zip(response.old_insert_end.and_then(deserialize_anchor));
6743 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6744
6745 if *resolved {
6746 return Ok(());
6747 }
6748 anyhow::ensure!(
6749 server_id == *completion_server_id,
6750 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6751 );
6752 **lsp_completion = resolved_lsp_completion;
6753 *resolved = true;
6754 }
6755
6756 let replace_range = response
6757 .old_replace_start
6758 .and_then(deserialize_anchor)
6759 .zip(response.old_replace_end.and_then(deserialize_anchor));
6760 if let Some((old_replace_start, old_replace_end)) = replace_range
6761 && !response.new_text.is_empty()
6762 {
6763 completion.new_text = response.new_text;
6764 completion.replace_range = old_replace_start..old_replace_end;
6765 }
6766
6767 Ok(())
6768 }
6769
6770 pub fn apply_additional_edits_for_completion(
6771 &self,
6772 buffer_handle: Entity<Buffer>,
6773 completions: Rc<RefCell<Box<[Completion]>>>,
6774 completion_index: usize,
6775 push_to_history: bool,
6776 all_commit_ranges: Vec<Range<language::Anchor>>,
6777 cx: &mut Context<Self>,
6778 ) -> Task<Result<Option<Transaction>>> {
6779 if let Some((client, project_id)) = self.upstream_client() {
6780 let buffer = buffer_handle.read(cx);
6781 let buffer_id = buffer.remote_id();
6782 cx.spawn(async move |_, cx| {
6783 let request = {
6784 let completion = completions.borrow()[completion_index].clone();
6785 proto::ApplyCompletionAdditionalEdits {
6786 project_id,
6787 buffer_id: buffer_id.into(),
6788 completion: Some(Self::serialize_completion(&CoreCompletion {
6789 replace_range: completion.replace_range,
6790 new_text: completion.new_text,
6791 source: completion.source,
6792 })),
6793 all_commit_ranges: all_commit_ranges
6794 .iter()
6795 .cloned()
6796 .map(language::proto::serialize_anchor_range)
6797 .collect(),
6798 }
6799 };
6800
6801 let Some(transaction) = client.request(request).await?.transaction else {
6802 return Ok(None);
6803 };
6804
6805 let transaction = language::proto::deserialize_transaction(transaction)?;
6806 buffer_handle
6807 .update(cx, |buffer, _| {
6808 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6809 })
6810 .await?;
6811 if push_to_history {
6812 buffer_handle.update(cx, |buffer, _| {
6813 buffer.push_transaction(transaction.clone(), Instant::now());
6814 buffer.finalize_last_transaction();
6815 });
6816 }
6817 Ok(Some(transaction))
6818 })
6819 } else {
6820 let request_timeout = ProjectSettings::get_global(cx)
6821 .global_lsp_settings
6822 .get_request_timeout();
6823
6824 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6825 let completion = &completions.borrow()[completion_index];
6826 let server_id = completion.source.server_id()?;
6827 Some(
6828 self.language_server_for_local_buffer(buffer, server_id, cx)?
6829 .1
6830 .clone(),
6831 )
6832 }) else {
6833 return Task::ready(Ok(None));
6834 };
6835
6836 cx.spawn(async move |this, cx| {
6837 Self::resolve_completion_local(
6838 server.clone(),
6839 completions.clone(),
6840 completion_index,
6841 request_timeout,
6842 )
6843 .await
6844 .context("resolving completion")?;
6845 let completion = completions.borrow()[completion_index].clone();
6846 let additional_text_edits = completion
6847 .source
6848 .lsp_completion(true)
6849 .as_ref()
6850 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6851 if let Some(edits) = additional_text_edits {
6852 let edits = this
6853 .update(cx, |this, cx| {
6854 this.as_local_mut().unwrap().edits_from_lsp(
6855 &buffer_handle,
6856 edits,
6857 server.server_id(),
6858 None,
6859 cx,
6860 )
6861 })?
6862 .await?;
6863
6864 buffer_handle.update(cx, |buffer, cx| {
6865 buffer.finalize_last_transaction();
6866 buffer.start_transaction();
6867
6868 for (range, text) in edits {
6869 let primary = &completion.replace_range;
6870
6871 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6872 // and the primary completion is just an insertion (empty range), then this is likely
6873 // an auto-import scenario and should not be considered overlapping
6874 // https://github.com/zed-industries/zed/issues/26136
6875 let is_file_start_auto_import = {
6876 let snapshot = buffer.snapshot();
6877 let primary_start_point = primary.start.to_point(&snapshot);
6878 let range_start_point = range.start.to_point(&snapshot);
6879
6880 let result = primary_start_point.row == 0
6881 && primary_start_point.column == 0
6882 && range_start_point.row == 0
6883 && range_start_point.column == 0;
6884
6885 result
6886 };
6887
6888 let has_overlap = if is_file_start_auto_import {
6889 false
6890 } else {
6891 all_commit_ranges.iter().any(|commit_range| {
6892 let start_within =
6893 commit_range.start.cmp(&range.start, buffer).is_le()
6894 && commit_range.end.cmp(&range.start, buffer).is_ge();
6895 let end_within =
6896 range.start.cmp(&commit_range.end, buffer).is_le()
6897 && range.end.cmp(&commit_range.end, buffer).is_ge();
6898 start_within || end_within
6899 })
6900 };
6901
6902 //Skip additional edits which overlap with the primary completion edit
6903 //https://github.com/zed-industries/zed/pull/1871
6904 if !has_overlap {
6905 buffer.edit([(range, text)], None, cx);
6906 }
6907 }
6908
6909 let transaction = if buffer.end_transaction(cx).is_some() {
6910 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6911 if !push_to_history {
6912 buffer.forget_transaction(transaction.id);
6913 }
6914 Some(transaction)
6915 } else {
6916 None
6917 };
6918 Ok(transaction)
6919 })
6920 } else {
6921 Ok(None)
6922 }
6923 })
6924 }
6925 }
6926
6927 pub fn pull_diagnostics(
6928 &mut self,
6929 buffer: Entity<Buffer>,
6930 cx: &mut Context<Self>,
6931 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6932 let buffer_id = buffer.read(cx).remote_id();
6933
6934 if let Some((client, upstream_project_id)) = self.upstream_client() {
6935 let mut suitable_capabilities = None;
6936 // Are we capable for proto request?
6937 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6938 &buffer,
6939 |capabilities| {
6940 if let Some(caps) = &capabilities.diagnostic_provider {
6941 suitable_capabilities = Some(caps.clone());
6942 true
6943 } else {
6944 false
6945 }
6946 },
6947 cx,
6948 );
6949 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6950 let Some(dynamic_caps) = suitable_capabilities else {
6951 return Task::ready(Ok(None));
6952 };
6953 assert!(any_server_has_diagnostics_provider);
6954
6955 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6956 let request = GetDocumentDiagnostics {
6957 previous_result_id: None,
6958 identifier,
6959 registration_id: None,
6960 };
6961 let request_timeout = ProjectSettings::get_global(cx)
6962 .global_lsp_settings
6963 .get_request_timeout();
6964 let request_task = client.request_lsp(
6965 upstream_project_id,
6966 None,
6967 request_timeout,
6968 cx.background_executor().clone(),
6969 request.to_proto(upstream_project_id, buffer.read(cx)),
6970 );
6971 cx.background_spawn(async move {
6972 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6973 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6974 // Do not attempt to further process the dummy responses here.
6975 let _response = request_task.await?;
6976 Ok(None)
6977 })
6978 } else {
6979 let servers = buffer.update(cx, |buffer, cx| {
6980 self.running_language_servers_for_local_buffer(buffer, cx)
6981 .map(|(_, server)| server.clone())
6982 .collect::<Vec<_>>()
6983 });
6984
6985 let pull_diagnostics = servers
6986 .into_iter()
6987 .flat_map(|server| {
6988 let result = maybe!({
6989 let local = self.as_local()?;
6990 let server_id = server.server_id();
6991 let providers_with_identifiers = local
6992 .language_server_dynamic_registrations
6993 .get(&server_id)
6994 .into_iter()
6995 .flat_map(|registrations| registrations.diagnostics.clone())
6996 .collect::<Vec<_>>();
6997 Some(
6998 providers_with_identifiers
6999 .into_iter()
7000 .map(|(registration_id, dynamic_caps)| {
7001 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7002 let registration_id = registration_id.map(SharedString::from);
7003 let result_id = self.result_id_for_buffer_pull(
7004 server_id,
7005 buffer_id,
7006 ®istration_id,
7007 cx,
7008 );
7009 self.request_lsp(
7010 buffer.clone(),
7011 LanguageServerToQuery::Other(server_id),
7012 GetDocumentDiagnostics {
7013 previous_result_id: result_id,
7014 registration_id,
7015 identifier,
7016 },
7017 cx,
7018 )
7019 })
7020 .collect::<Vec<_>>(),
7021 )
7022 });
7023
7024 result.unwrap_or_default()
7025 })
7026 .collect::<Vec<_>>();
7027
7028 cx.background_spawn(async move {
7029 let mut responses = Vec::new();
7030 for diagnostics in join_all(pull_diagnostics).await {
7031 responses.extend(diagnostics?);
7032 }
7033 Ok(Some(responses))
7034 })
7035 }
7036 }
7037
7038 pub fn applicable_inlay_chunks(
7039 &mut self,
7040 buffer: &Entity<Buffer>,
7041 ranges: &[Range<text::Anchor>],
7042 cx: &mut Context<Self>,
7043 ) -> Vec<Range<BufferRow>> {
7044 let buffer_snapshot = buffer.read(cx).snapshot();
7045 let ranges = ranges
7046 .iter()
7047 .map(|range| range.to_point(&buffer_snapshot))
7048 .collect::<Vec<_>>();
7049
7050 self.latest_lsp_data(buffer, cx)
7051 .inlay_hints
7052 .applicable_chunks(ranges.as_slice())
7053 .map(|chunk| chunk.row_range())
7054 .collect()
7055 }
7056
7057 pub fn invalidate_inlay_hints<'a>(
7058 &'a mut self,
7059 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7060 ) {
7061 for buffer_id in for_buffers {
7062 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7063 lsp_data.inlay_hints.clear();
7064 }
7065 }
7066 }
7067
7068 pub fn inlay_hints(
7069 &mut self,
7070 invalidate: InvalidationStrategy,
7071 buffer: Entity<Buffer>,
7072 ranges: Vec<Range<text::Anchor>>,
7073 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7074 cx: &mut Context<Self>,
7075 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7076 let next_hint_id = self.next_hint_id.clone();
7077 let lsp_data = self.latest_lsp_data(&buffer, cx);
7078 let query_version = lsp_data.buffer_version.clone();
7079 let mut lsp_refresh_requested = false;
7080 let for_server = if let InvalidationStrategy::RefreshRequested {
7081 server_id,
7082 request_id,
7083 } = invalidate
7084 {
7085 let invalidated = lsp_data
7086 .inlay_hints
7087 .invalidate_for_server_refresh(server_id, request_id);
7088 lsp_refresh_requested = invalidated;
7089 Some(server_id)
7090 } else {
7091 None
7092 };
7093 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7094 let known_chunks = known_chunks
7095 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7096 .map(|(_, known_chunks)| known_chunks)
7097 .unwrap_or_default();
7098
7099 let buffer_snapshot = buffer.read(cx).snapshot();
7100 let ranges = ranges
7101 .iter()
7102 .map(|range| range.to_point(&buffer_snapshot))
7103 .collect::<Vec<_>>();
7104
7105 let mut hint_fetch_tasks = Vec::new();
7106 let mut cached_inlay_hints = None;
7107 let mut ranges_to_query = None;
7108 let applicable_chunks = existing_inlay_hints
7109 .applicable_chunks(ranges.as_slice())
7110 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7111 .collect::<Vec<_>>();
7112 if applicable_chunks.is_empty() {
7113 return HashMap::default();
7114 }
7115
7116 for row_chunk in applicable_chunks {
7117 match (
7118 existing_inlay_hints
7119 .cached_hints(&row_chunk)
7120 .filter(|_| !lsp_refresh_requested)
7121 .cloned(),
7122 existing_inlay_hints
7123 .fetched_hints(&row_chunk)
7124 .as_ref()
7125 .filter(|_| !lsp_refresh_requested)
7126 .cloned(),
7127 ) {
7128 (None, None) => {
7129 let chunk_range = row_chunk.anchor_range();
7130 ranges_to_query
7131 .get_or_insert_with(Vec::new)
7132 .push((row_chunk, chunk_range));
7133 }
7134 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7135 (Some(cached_hints), None) => {
7136 for (server_id, cached_hints) in cached_hints {
7137 if for_server.is_none_or(|for_server| for_server == server_id) {
7138 cached_inlay_hints
7139 .get_or_insert_with(HashMap::default)
7140 .entry(row_chunk.row_range())
7141 .or_insert_with(HashMap::default)
7142 .entry(server_id)
7143 .or_insert_with(Vec::new)
7144 .extend(cached_hints);
7145 }
7146 }
7147 }
7148 (Some(cached_hints), Some(fetched_hints)) => {
7149 hint_fetch_tasks.push((row_chunk, fetched_hints));
7150 for (server_id, cached_hints) in cached_hints {
7151 if for_server.is_none_or(|for_server| for_server == server_id) {
7152 cached_inlay_hints
7153 .get_or_insert_with(HashMap::default)
7154 .entry(row_chunk.row_range())
7155 .or_insert_with(HashMap::default)
7156 .entry(server_id)
7157 .or_insert_with(Vec::new)
7158 .extend(cached_hints);
7159 }
7160 }
7161 }
7162 }
7163 }
7164
7165 if hint_fetch_tasks.is_empty()
7166 && ranges_to_query
7167 .as_ref()
7168 .is_none_or(|ranges| ranges.is_empty())
7169 && let Some(cached_inlay_hints) = cached_inlay_hints
7170 {
7171 cached_inlay_hints
7172 .into_iter()
7173 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7174 .collect()
7175 } else {
7176 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7177 // When a server refresh was requested, other servers' cached hints
7178 // are unaffected by the refresh and must be included in the result.
7179 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7180 // removes all visible hints but only adds back the requesting
7181 // server's new hints, permanently losing other servers' hints.
7182 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7183 lsp_data
7184 .inlay_hints
7185 .cached_hints(&chunk)
7186 .cloned()
7187 .unwrap_or_default()
7188 } else {
7189 HashMap::default()
7190 };
7191
7192 let next_hint_id = next_hint_id.clone();
7193 let buffer = buffer.clone();
7194 let query_version = query_version.clone();
7195 let new_inlay_hints = cx
7196 .spawn(async move |lsp_store, cx| {
7197 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7198 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7199 })?;
7200 new_fetch_task
7201 .await
7202 .and_then(|new_hints_by_server| {
7203 lsp_store.update(cx, |lsp_store, cx| {
7204 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7205 let update_cache = lsp_data.buffer_version == query_version;
7206 if new_hints_by_server.is_empty() {
7207 if update_cache {
7208 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7209 }
7210 other_servers_cached
7211 } else {
7212 let mut result = other_servers_cached;
7213 for (server_id, new_hints) in new_hints_by_server {
7214 let new_hints = new_hints
7215 .into_iter()
7216 .map(|new_hint| {
7217 (
7218 InlayId::Hint(next_hint_id.fetch_add(
7219 1,
7220 atomic::Ordering::AcqRel,
7221 )),
7222 new_hint,
7223 )
7224 })
7225 .collect::<Vec<_>>();
7226 if update_cache {
7227 lsp_data.inlay_hints.insert_new_hints(
7228 chunk,
7229 server_id,
7230 new_hints.clone(),
7231 );
7232 }
7233 result.insert(server_id, new_hints);
7234 }
7235 result
7236 }
7237 })
7238 })
7239 .map_err(Arc::new)
7240 })
7241 .shared();
7242
7243 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7244 *fetch_task = Some(new_inlay_hints.clone());
7245 hint_fetch_tasks.push((chunk, new_inlay_hints));
7246 }
7247
7248 cached_inlay_hints
7249 .unwrap_or_default()
7250 .into_iter()
7251 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7252 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7253 (
7254 chunk.row_range(),
7255 cx.spawn(async move |_, _| {
7256 hints_fetch.await.map_err(|e| {
7257 if e.error_code() != ErrorCode::Internal {
7258 anyhow!(e.error_code())
7259 } else {
7260 anyhow!("{e:#}")
7261 }
7262 })
7263 }),
7264 )
7265 }))
7266 .collect()
7267 }
7268 }
7269
7270 fn fetch_inlay_hints(
7271 &mut self,
7272 for_server: Option<LanguageServerId>,
7273 buffer: &Entity<Buffer>,
7274 range: Range<Anchor>,
7275 cx: &mut Context<Self>,
7276 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7277 let request = InlayHints {
7278 range: range.clone(),
7279 };
7280 if let Some((upstream_client, project_id)) = self.upstream_client() {
7281 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7282 return Task::ready(Ok(HashMap::default()));
7283 }
7284 let request_timeout = ProjectSettings::get_global(cx)
7285 .global_lsp_settings
7286 .get_request_timeout();
7287 let request_task = upstream_client.request_lsp(
7288 project_id,
7289 for_server.map(|id| id.to_proto()),
7290 request_timeout,
7291 cx.background_executor().clone(),
7292 request.to_proto(project_id, buffer.read(cx)),
7293 );
7294 let buffer = buffer.clone();
7295 cx.spawn(async move |weak_lsp_store, cx| {
7296 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7297 return Ok(HashMap::default());
7298 };
7299 let Some(responses) = request_task.await? else {
7300 return Ok(HashMap::default());
7301 };
7302
7303 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7304 let lsp_store = lsp_store.clone();
7305 let buffer = buffer.clone();
7306 let cx = cx.clone();
7307 let request = request.clone();
7308 async move {
7309 (
7310 LanguageServerId::from_proto(response.server_id),
7311 request
7312 .response_from_proto(response.response, lsp_store, buffer, cx)
7313 .await,
7314 )
7315 }
7316 }))
7317 .await;
7318
7319 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7320 let mut has_errors = false;
7321 let inlay_hints = inlay_hints
7322 .into_iter()
7323 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7324 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7325 Err(e) => {
7326 has_errors = true;
7327 log::error!("{e:#}");
7328 None
7329 }
7330 })
7331 .map(|(server_id, mut new_hints)| {
7332 new_hints.retain(|hint| {
7333 hint.position.is_valid(&buffer_snapshot)
7334 && range.start.is_valid(&buffer_snapshot)
7335 && range.end.is_valid(&buffer_snapshot)
7336 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7337 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7338 });
7339 (server_id, new_hints)
7340 })
7341 .collect::<HashMap<_, _>>();
7342 anyhow::ensure!(
7343 !has_errors || !inlay_hints.is_empty(),
7344 "Failed to fetch inlay hints"
7345 );
7346 Ok(inlay_hints)
7347 })
7348 } else {
7349 let inlay_hints_task = match for_server {
7350 Some(server_id) => {
7351 let server_task = self.request_lsp(
7352 buffer.clone(),
7353 LanguageServerToQuery::Other(server_id),
7354 request,
7355 cx,
7356 );
7357 cx.background_spawn(async move {
7358 let mut responses = Vec::new();
7359 match server_task.await {
7360 Ok(response) => responses.push((server_id, response)),
7361 // rust-analyzer likes to error with this when its still loading up
7362 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7363 Err(e) => log::error!(
7364 "Error handling response for inlay hints request: {e:#}"
7365 ),
7366 }
7367 responses
7368 })
7369 }
7370 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7371 };
7372 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7373 cx.background_spawn(async move {
7374 Ok(inlay_hints_task
7375 .await
7376 .into_iter()
7377 .map(|(server_id, mut new_hints)| {
7378 new_hints.retain(|hint| {
7379 hint.position.is_valid(&buffer_snapshot)
7380 && range.start.is_valid(&buffer_snapshot)
7381 && range.end.is_valid(&buffer_snapshot)
7382 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7383 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7384 });
7385 (server_id, new_hints)
7386 })
7387 .collect())
7388 })
7389 }
7390 }
7391
7392 fn diagnostic_registration_exists(
7393 &self,
7394 server_id: LanguageServerId,
7395 registration_id: &Option<SharedString>,
7396 ) -> bool {
7397 let Some(local) = self.as_local() else {
7398 return false;
7399 };
7400 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7401 else {
7402 return false;
7403 };
7404 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7405 registrations.diagnostics.contains_key(®istration_key)
7406 }
7407
7408 pub fn pull_diagnostics_for_buffer(
7409 &mut self,
7410 buffer: Entity<Buffer>,
7411 cx: &mut Context<Self>,
7412 ) -> Task<anyhow::Result<()>> {
7413 let diagnostics = self.pull_diagnostics(buffer, cx);
7414 cx.spawn(async move |lsp_store, cx| {
7415 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7416 return Ok(());
7417 };
7418 lsp_store.update(cx, |lsp_store, cx| {
7419 if lsp_store.as_local().is_none() {
7420 return;
7421 }
7422
7423 let mut unchanged_buffers = HashMap::default();
7424 let server_diagnostics_updates = diagnostics
7425 .into_iter()
7426 .filter_map(|diagnostics_set| match diagnostics_set {
7427 LspPullDiagnostics::Response {
7428 server_id,
7429 uri,
7430 diagnostics,
7431 registration_id,
7432 } => Some((server_id, uri, diagnostics, registration_id)),
7433 LspPullDiagnostics::Default => None,
7434 })
7435 .filter(|(server_id, _, _, registration_id)| {
7436 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7437 })
7438 .fold(
7439 HashMap::default(),
7440 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7441 let (result_id, diagnostics) = match diagnostics {
7442 PulledDiagnostics::Unchanged { result_id } => {
7443 unchanged_buffers
7444 .entry(new_registration_id.clone())
7445 .or_insert_with(HashSet::default)
7446 .insert(uri.clone());
7447 (Some(result_id), Vec::new())
7448 }
7449 PulledDiagnostics::Changed {
7450 result_id,
7451 diagnostics,
7452 } => (result_id, diagnostics),
7453 };
7454 let disk_based_sources = Cow::Owned(
7455 lsp_store
7456 .language_server_adapter_for_id(server_id)
7457 .as_ref()
7458 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7459 .unwrap_or(&[])
7460 .to_vec(),
7461 );
7462 acc.entry(server_id)
7463 .or_insert_with(HashMap::default)
7464 .entry(new_registration_id.clone())
7465 .or_insert_with(Vec::new)
7466 .push(DocumentDiagnosticsUpdate {
7467 server_id,
7468 diagnostics: lsp::PublishDiagnosticsParams {
7469 uri,
7470 diagnostics,
7471 version: None,
7472 },
7473 result_id: result_id.map(SharedString::new),
7474 disk_based_sources,
7475 registration_id: new_registration_id,
7476 });
7477 acc
7478 },
7479 );
7480
7481 for diagnostic_updates in server_diagnostics_updates.into_values() {
7482 for (registration_id, diagnostic_updates) in diagnostic_updates {
7483 lsp_store
7484 .merge_lsp_diagnostics(
7485 DiagnosticSourceKind::Pulled,
7486 diagnostic_updates,
7487 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7488 DiagnosticSourceKind::Pulled => {
7489 old_diagnostic.registration_id != registration_id
7490 || unchanged_buffers
7491 .get(&old_diagnostic.registration_id)
7492 .is_some_and(|unchanged_buffers| {
7493 unchanged_buffers.contains(&document_uri)
7494 })
7495 }
7496 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7497 true
7498 }
7499 },
7500 cx,
7501 )
7502 .log_err();
7503 }
7504 }
7505 })
7506 })
7507 }
7508
7509 pub fn signature_help<T: ToPointUtf16>(
7510 &mut self,
7511 buffer: &Entity<Buffer>,
7512 position: T,
7513 cx: &mut Context<Self>,
7514 ) -> Task<Option<Vec<SignatureHelp>>> {
7515 let position = position.to_point_utf16(buffer.read(cx));
7516
7517 if let Some((client, upstream_project_id)) = self.upstream_client() {
7518 let request = GetSignatureHelp { position };
7519 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7520 return Task::ready(None);
7521 }
7522 let request_timeout = ProjectSettings::get_global(cx)
7523 .global_lsp_settings
7524 .get_request_timeout();
7525 let request_task = client.request_lsp(
7526 upstream_project_id,
7527 None,
7528 request_timeout,
7529 cx.background_executor().clone(),
7530 request.to_proto(upstream_project_id, buffer.read(cx)),
7531 );
7532 let buffer = buffer.clone();
7533 cx.spawn(async move |weak_lsp_store, cx| {
7534 let lsp_store = weak_lsp_store.upgrade()?;
7535 let signatures = join_all(
7536 request_task
7537 .await
7538 .log_err()
7539 .flatten()
7540 .map(|response| response.payload)
7541 .unwrap_or_default()
7542 .into_iter()
7543 .map(|response| {
7544 let response = GetSignatureHelp { position }.response_from_proto(
7545 response.response,
7546 lsp_store.clone(),
7547 buffer.clone(),
7548 cx.clone(),
7549 );
7550 async move { response.await.log_err().flatten() }
7551 }),
7552 )
7553 .await
7554 .into_iter()
7555 .flatten()
7556 .collect();
7557 Some(signatures)
7558 })
7559 } else {
7560 let all_actions_task = self.request_multiple_lsp_locally(
7561 buffer,
7562 Some(position),
7563 GetSignatureHelp { position },
7564 cx,
7565 );
7566 cx.background_spawn(async move {
7567 Some(
7568 all_actions_task
7569 .await
7570 .into_iter()
7571 .flat_map(|(_, actions)| actions)
7572 .collect::<Vec<_>>(),
7573 )
7574 })
7575 }
7576 }
7577
7578 pub fn hover(
7579 &mut self,
7580 buffer: &Entity<Buffer>,
7581 position: PointUtf16,
7582 cx: &mut Context<Self>,
7583 ) -> Task<Option<Vec<Hover>>> {
7584 if let Some((client, upstream_project_id)) = self.upstream_client() {
7585 let request = GetHover { position };
7586 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7587 return Task::ready(None);
7588 }
7589 let request_timeout = ProjectSettings::get_global(cx)
7590 .global_lsp_settings
7591 .get_request_timeout();
7592 let request_task = client.request_lsp(
7593 upstream_project_id,
7594 None,
7595 request_timeout,
7596 cx.background_executor().clone(),
7597 request.to_proto(upstream_project_id, buffer.read(cx)),
7598 );
7599 let buffer = buffer.clone();
7600 cx.spawn(async move |weak_lsp_store, cx| {
7601 let lsp_store = weak_lsp_store.upgrade()?;
7602 let hovers = join_all(
7603 request_task
7604 .await
7605 .log_err()
7606 .flatten()
7607 .map(|response| response.payload)
7608 .unwrap_or_default()
7609 .into_iter()
7610 .map(|response| {
7611 let response = GetHover { position }.response_from_proto(
7612 response.response,
7613 lsp_store.clone(),
7614 buffer.clone(),
7615 cx.clone(),
7616 );
7617 async move {
7618 response
7619 .await
7620 .log_err()
7621 .flatten()
7622 .and_then(remove_empty_hover_blocks)
7623 }
7624 }),
7625 )
7626 .await
7627 .into_iter()
7628 .flatten()
7629 .collect();
7630 Some(hovers)
7631 })
7632 } else {
7633 let all_actions_task = self.request_multiple_lsp_locally(
7634 buffer,
7635 Some(position),
7636 GetHover { position },
7637 cx,
7638 );
7639 cx.background_spawn(async move {
7640 Some(
7641 all_actions_task
7642 .await
7643 .into_iter()
7644 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7645 .collect::<Vec<Hover>>(),
7646 )
7647 })
7648 }
7649 }
7650
7651 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7652 let language_registry = self.languages.clone();
7653
7654 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7655 let request = upstream_client.request(proto::GetProjectSymbols {
7656 project_id: *project_id,
7657 query: query.to_string(),
7658 });
7659 cx.foreground_executor().spawn(async move {
7660 let response = request.await?;
7661 let mut symbols = Vec::new();
7662 let core_symbols = response
7663 .symbols
7664 .into_iter()
7665 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7666 .collect::<Vec<_>>();
7667 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7668 .await;
7669 Ok(symbols)
7670 })
7671 } else if let Some(local) = self.as_local() {
7672 struct WorkspaceSymbolsResult {
7673 server_id: LanguageServerId,
7674 lsp_adapter: Arc<CachedLspAdapter>,
7675 worktree: WeakEntity<Worktree>,
7676 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7677 }
7678
7679 let mut requests = Vec::new();
7680 let mut requested_servers = BTreeSet::new();
7681 let request_timeout = ProjectSettings::get_global(cx)
7682 .global_lsp_settings
7683 .get_request_timeout();
7684
7685 for (seed, state) in local.language_server_ids.iter() {
7686 let Some(worktree_handle) = self
7687 .worktree_store
7688 .read(cx)
7689 .worktree_for_id(seed.worktree_id, cx)
7690 else {
7691 continue;
7692 };
7693
7694 let worktree = worktree_handle.read(cx);
7695 if !worktree.is_visible() {
7696 continue;
7697 }
7698
7699 if !requested_servers.insert(state.id) {
7700 continue;
7701 }
7702
7703 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7704 Some(LanguageServerState::Running {
7705 adapter, server, ..
7706 }) => (adapter.clone(), server),
7707
7708 _ => continue,
7709 };
7710
7711 let supports_workspace_symbol_request =
7712 match server.capabilities().workspace_symbol_provider {
7713 Some(OneOf::Left(supported)) => supported,
7714 Some(OneOf::Right(_)) => true,
7715 None => false,
7716 };
7717
7718 if !supports_workspace_symbol_request {
7719 continue;
7720 }
7721
7722 let worktree_handle = worktree_handle.clone();
7723 let server_id = server.server_id();
7724 requests.push(
7725 server
7726 .request::<lsp::request::WorkspaceSymbolRequest>(
7727 lsp::WorkspaceSymbolParams {
7728 query: query.to_string(),
7729 ..Default::default()
7730 },
7731 request_timeout,
7732 )
7733 .map(move |response| {
7734 let lsp_symbols = response
7735 .into_response()
7736 .context("workspace symbols request")
7737 .log_err()
7738 .flatten()
7739 .map(|symbol_response| match symbol_response {
7740 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7741 flat_responses
7742 .into_iter()
7743 .map(|lsp_symbol| {
7744 (
7745 lsp_symbol.name,
7746 lsp_symbol.kind,
7747 lsp_symbol.location,
7748 lsp_symbol.container_name,
7749 )
7750 })
7751 .collect::<Vec<_>>()
7752 }
7753 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7754 nested_responses
7755 .into_iter()
7756 .filter_map(|lsp_symbol| {
7757 let location = match lsp_symbol.location {
7758 OneOf::Left(location) => location,
7759 OneOf::Right(_) => {
7760 log::error!(
7761 "Unexpected: client capabilities \
7762 forbid symbol resolutions in \
7763 workspace.symbol.resolveSupport"
7764 );
7765 return None;
7766 }
7767 };
7768 Some((
7769 lsp_symbol.name,
7770 lsp_symbol.kind,
7771 location,
7772 lsp_symbol.container_name,
7773 ))
7774 })
7775 .collect::<Vec<_>>()
7776 }
7777 })
7778 .unwrap_or_default();
7779
7780 WorkspaceSymbolsResult {
7781 server_id,
7782 lsp_adapter,
7783 worktree: worktree_handle.downgrade(),
7784 lsp_symbols,
7785 }
7786 }),
7787 );
7788 }
7789
7790 cx.spawn(async move |this, cx| {
7791 let responses = futures::future::join_all(requests).await;
7792 let this = match this.upgrade() {
7793 Some(this) => this,
7794 None => return Ok(Vec::new()),
7795 };
7796
7797 let mut symbols = Vec::new();
7798 for result in responses {
7799 let core_symbols = this.update(cx, |this, cx| {
7800 result
7801 .lsp_symbols
7802 .into_iter()
7803 .filter_map(
7804 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7805 let abs_path = symbol_location.uri.to_file_path().ok()?;
7806 let source_worktree = result.worktree.upgrade()?;
7807 let source_worktree_id = source_worktree.read(cx).id();
7808
7809 let path = if let Some((tree, rel_path)) =
7810 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7811 {
7812 let worktree_id = tree.read(cx).id();
7813 SymbolLocation::InProject(ProjectPath {
7814 worktree_id,
7815 path: rel_path,
7816 })
7817 } else {
7818 SymbolLocation::OutsideProject {
7819 signature: this.symbol_signature(&abs_path),
7820 abs_path: abs_path.into(),
7821 }
7822 };
7823
7824 Some(CoreSymbol {
7825 source_language_server_id: result.server_id,
7826 language_server_name: result.lsp_adapter.name.clone(),
7827 source_worktree_id,
7828 path,
7829 kind: symbol_kind,
7830 name: collapse_newlines(&symbol_name, "↵ "),
7831 range: range_from_lsp(symbol_location.range),
7832 container_name: container_name
7833 .map(|c| collapse_newlines(&c, "↵ ")),
7834 })
7835 },
7836 )
7837 .collect::<Vec<_>>()
7838 });
7839
7840 populate_labels_for_symbols(
7841 core_symbols,
7842 &language_registry,
7843 Some(result.lsp_adapter),
7844 &mut symbols,
7845 )
7846 .await;
7847 }
7848
7849 Ok(symbols)
7850 })
7851 } else {
7852 Task::ready(Err(anyhow!("No upstream client or local language server")))
7853 }
7854 }
7855
7856 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7857 let mut summary = DiagnosticSummary::default();
7858 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7859 summary.error_count += path_summary.error_count;
7860 summary.warning_count += path_summary.warning_count;
7861 }
7862 summary
7863 }
7864
7865 /// Returns the diagnostic summary for a specific project path.
7866 pub fn diagnostic_summary_for_path(
7867 &self,
7868 project_path: &ProjectPath,
7869 _: &App,
7870 ) -> DiagnosticSummary {
7871 if let Some(summaries) = self
7872 .diagnostic_summaries
7873 .get(&project_path.worktree_id)
7874 .and_then(|map| map.get(&project_path.path))
7875 {
7876 let (error_count, warning_count) = summaries.iter().fold(
7877 (0, 0),
7878 |(error_count, warning_count), (_language_server_id, summary)| {
7879 (
7880 error_count + summary.error_count,
7881 warning_count + summary.warning_count,
7882 )
7883 },
7884 );
7885
7886 DiagnosticSummary {
7887 error_count,
7888 warning_count,
7889 }
7890 } else {
7891 DiagnosticSummary::default()
7892 }
7893 }
7894
7895 pub fn diagnostic_summaries<'a>(
7896 &'a self,
7897 include_ignored: bool,
7898 cx: &'a App,
7899 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7900 self.worktree_store
7901 .read(cx)
7902 .visible_worktrees(cx)
7903 .filter_map(|worktree| {
7904 let worktree = worktree.read(cx);
7905 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7906 })
7907 .flat_map(move |(worktree, summaries)| {
7908 let worktree_id = worktree.id();
7909 summaries
7910 .iter()
7911 .filter(move |(path, _)| {
7912 include_ignored
7913 || worktree
7914 .entry_for_path(path.as_ref())
7915 .is_some_and(|entry| !entry.is_ignored)
7916 })
7917 .flat_map(move |(path, summaries)| {
7918 summaries.iter().map(move |(server_id, summary)| {
7919 (
7920 ProjectPath {
7921 worktree_id,
7922 path: path.clone(),
7923 },
7924 *server_id,
7925 *summary,
7926 )
7927 })
7928 })
7929 })
7930 }
7931
7932 pub fn on_buffer_edited(
7933 &mut self,
7934 buffer: Entity<Buffer>,
7935 cx: &mut Context<Self>,
7936 ) -> Option<()> {
7937 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7938 Some(
7939 self.as_local()?
7940 .language_servers_for_buffer(buffer, cx)
7941 .map(|i| i.1.clone())
7942 .collect(),
7943 )
7944 })?;
7945
7946 let buffer = buffer.read(cx);
7947 let file = File::from_dyn(buffer.file())?;
7948 let abs_path = file.as_local()?.abs_path(cx);
7949 let uri = lsp::Uri::from_file_path(&abs_path)
7950 .ok()
7951 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7952 .log_err()?;
7953 let next_snapshot = buffer.text_snapshot();
7954 for language_server in language_servers {
7955 let language_server = language_server.clone();
7956
7957 let buffer_snapshots = self
7958 .as_local_mut()?
7959 .buffer_snapshots
7960 .get_mut(&buffer.remote_id())
7961 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7962 let previous_snapshot = buffer_snapshots.last()?;
7963
7964 let build_incremental_change = || {
7965 buffer
7966 .edits_since::<Dimensions<PointUtf16, usize>>(
7967 previous_snapshot.snapshot.version(),
7968 )
7969 .map(|edit| {
7970 let edit_start = edit.new.start.0;
7971 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7972 let new_text = next_snapshot
7973 .text_for_range(edit.new.start.1..edit.new.end.1)
7974 .collect();
7975 lsp::TextDocumentContentChangeEvent {
7976 range: Some(lsp::Range::new(
7977 point_to_lsp(edit_start),
7978 point_to_lsp(edit_end),
7979 )),
7980 range_length: None,
7981 text: new_text,
7982 }
7983 })
7984 .collect()
7985 };
7986
7987 let document_sync_kind = language_server
7988 .capabilities()
7989 .text_document_sync
7990 .as_ref()
7991 .and_then(|sync| match sync {
7992 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7993 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7994 });
7995
7996 let content_changes: Vec<_> = match document_sync_kind {
7997 Some(lsp::TextDocumentSyncKind::FULL) => {
7998 vec![lsp::TextDocumentContentChangeEvent {
7999 range: None,
8000 range_length: None,
8001 text: next_snapshot.text(),
8002 }]
8003 }
8004 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8005 _ => {
8006 #[cfg(any(test, feature = "test-support"))]
8007 {
8008 build_incremental_change()
8009 }
8010
8011 #[cfg(not(any(test, feature = "test-support")))]
8012 {
8013 continue;
8014 }
8015 }
8016 };
8017
8018 let next_version = previous_snapshot.version + 1;
8019 buffer_snapshots.push(LspBufferSnapshot {
8020 version: next_version,
8021 snapshot: next_snapshot.clone(),
8022 });
8023
8024 language_server
8025 .notify::<lsp::notification::DidChangeTextDocument>(
8026 lsp::DidChangeTextDocumentParams {
8027 text_document: lsp::VersionedTextDocumentIdentifier::new(
8028 uri.clone(),
8029 next_version,
8030 ),
8031 content_changes,
8032 },
8033 )
8034 .ok();
8035 self.pull_workspace_diagnostics(language_server.server_id());
8036 }
8037
8038 None
8039 }
8040
8041 pub fn on_buffer_saved(
8042 &mut self,
8043 buffer: Entity<Buffer>,
8044 cx: &mut Context<Self>,
8045 ) -> Option<()> {
8046 let file = File::from_dyn(buffer.read(cx).file())?;
8047 let worktree_id = file.worktree_id(cx);
8048 let abs_path = file.as_local()?.abs_path(cx);
8049 let text_document = lsp::TextDocumentIdentifier {
8050 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8051 };
8052 let local = self.as_local()?;
8053
8054 for server in local.language_servers_for_worktree(worktree_id) {
8055 if let Some(include_text) = include_text(server.as_ref()) {
8056 let text = if include_text {
8057 Some(buffer.read(cx).text())
8058 } else {
8059 None
8060 };
8061 server
8062 .notify::<lsp::notification::DidSaveTextDocument>(
8063 lsp::DidSaveTextDocumentParams {
8064 text_document: text_document.clone(),
8065 text,
8066 },
8067 )
8068 .ok();
8069 }
8070 }
8071
8072 let language_servers = buffer.update(cx, |buffer, cx| {
8073 local.language_server_ids_for_buffer(buffer, cx)
8074 });
8075 for language_server_id in language_servers {
8076 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8077 }
8078
8079 None
8080 }
8081
8082 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8083 maybe!(async move {
8084 let mut refreshed_servers = HashSet::default();
8085 let servers = lsp_store
8086 .update(cx, |lsp_store, cx| {
8087 let local = lsp_store.as_local()?;
8088
8089 let servers = local
8090 .language_server_ids
8091 .iter()
8092 .filter_map(|(seed, state)| {
8093 let worktree = lsp_store
8094 .worktree_store
8095 .read(cx)
8096 .worktree_for_id(seed.worktree_id, cx);
8097 let delegate: Arc<dyn LspAdapterDelegate> =
8098 worktree.map(|worktree| {
8099 LocalLspAdapterDelegate::new(
8100 local.languages.clone(),
8101 &local.environment,
8102 cx.weak_entity(),
8103 &worktree,
8104 local.http_client.clone(),
8105 local.fs.clone(),
8106 cx,
8107 )
8108 })?;
8109 let server_id = state.id;
8110
8111 let states = local.language_servers.get(&server_id)?;
8112
8113 match states {
8114 LanguageServerState::Starting { .. } => None,
8115 LanguageServerState::Running {
8116 adapter, server, ..
8117 } => {
8118 let adapter = adapter.clone();
8119 let server = server.clone();
8120 refreshed_servers.insert(server.name());
8121 let toolchain = seed.toolchain.clone();
8122 Some(cx.spawn(async move |_, cx| {
8123 let settings =
8124 LocalLspStore::workspace_configuration_for_adapter(
8125 adapter.adapter.clone(),
8126 &delegate,
8127 toolchain,
8128 None,
8129 cx,
8130 )
8131 .await
8132 .ok()?;
8133 server
8134 .notify::<lsp::notification::DidChangeConfiguration>(
8135 lsp::DidChangeConfigurationParams { settings },
8136 )
8137 .ok()?;
8138 Some(())
8139 }))
8140 }
8141 }
8142 })
8143 .collect::<Vec<_>>();
8144
8145 Some(servers)
8146 })
8147 .ok()
8148 .flatten()?;
8149
8150 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8151 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8152 // to stop and unregister its language server wrapper.
8153 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8154 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8155 let _: Vec<Option<()>> = join_all(servers).await;
8156
8157 Some(())
8158 })
8159 .await;
8160 }
8161
8162 fn maintain_workspace_config(
8163 external_refresh_requests: watch::Receiver<()>,
8164 cx: &mut Context<Self>,
8165 ) -> Task<Result<()>> {
8166 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8167 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8168
8169 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8170 *settings_changed_tx.borrow_mut() = ();
8171 });
8172
8173 let mut joint_future =
8174 futures::stream::select(settings_changed_rx, external_refresh_requests);
8175 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8176 // - 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).
8177 // - 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.
8178 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8179 // - 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,
8180 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8181 cx.spawn(async move |this, cx| {
8182 while let Some(()) = joint_future.next().await {
8183 this.update(cx, |this, cx| {
8184 this.refresh_server_tree(cx);
8185 })
8186 .ok();
8187
8188 Self::refresh_workspace_configurations(&this, cx).await;
8189 }
8190
8191 drop(settings_observation);
8192 anyhow::Ok(())
8193 })
8194 }
8195
8196 pub fn running_language_servers_for_local_buffer<'a>(
8197 &'a self,
8198 buffer: &Buffer,
8199 cx: &mut App,
8200 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8201 let local = self.as_local();
8202 let language_server_ids = local
8203 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8204 .unwrap_or_default();
8205
8206 language_server_ids
8207 .into_iter()
8208 .filter_map(
8209 move |server_id| match local?.language_servers.get(&server_id)? {
8210 LanguageServerState::Running {
8211 adapter, server, ..
8212 } => Some((adapter, server)),
8213 _ => None,
8214 },
8215 )
8216 }
8217
8218 pub fn language_servers_for_local_buffer(
8219 &self,
8220 buffer: &Buffer,
8221 cx: &mut App,
8222 ) -> Vec<LanguageServerId> {
8223 let local = self.as_local();
8224 local
8225 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8226 .unwrap_or_default()
8227 }
8228
8229 pub fn language_server_for_local_buffer<'a>(
8230 &'a self,
8231 buffer: &'a Buffer,
8232 server_id: LanguageServerId,
8233 cx: &'a mut App,
8234 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8235 self.as_local()?
8236 .language_servers_for_buffer(buffer, cx)
8237 .find(|(_, s)| s.server_id() == server_id)
8238 }
8239
8240 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8241 self.diagnostic_summaries.remove(&id_to_remove);
8242 if let Some(local) = self.as_local_mut() {
8243 let to_remove = local.remove_worktree(id_to_remove, cx);
8244 for server in to_remove {
8245 self.language_server_statuses.remove(&server);
8246 }
8247 }
8248 }
8249
8250 fn invalidate_diagnostic_summaries_for_removed_entries(
8251 &mut self,
8252 worktree_id: WorktreeId,
8253 changes: &UpdatedEntriesSet,
8254 cx: &mut Context<Self>,
8255 ) {
8256 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8257 return;
8258 };
8259
8260 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8261 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8262 let downstream = self.downstream_client.clone();
8263
8264 for (path, _, _) in changes
8265 .iter()
8266 .filter(|(_, _, change)| *change == PathChange::Removed)
8267 {
8268 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8269 for (server_id, _) in &summaries_by_server_id {
8270 cleared_server_ids.insert(*server_id);
8271 if let Some((client, project_id)) = &downstream {
8272 client
8273 .send(proto::UpdateDiagnosticSummary {
8274 project_id: *project_id,
8275 worktree_id: worktree_id.to_proto(),
8276 summary: Some(proto::DiagnosticSummary {
8277 path: path.as_ref().to_proto(),
8278 language_server_id: server_id.0 as u64,
8279 error_count: 0,
8280 warning_count: 0,
8281 }),
8282 more_summaries: Vec::new(),
8283 })
8284 .ok();
8285 }
8286 }
8287 cleared_paths.push(ProjectPath {
8288 worktree_id,
8289 path: path.clone(),
8290 });
8291 }
8292 }
8293
8294 if !cleared_paths.is_empty() {
8295 for server_id in cleared_server_ids {
8296 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8297 server_id,
8298 paths: cleared_paths.clone(),
8299 });
8300 }
8301 }
8302 }
8303
8304 pub fn shared(
8305 &mut self,
8306 project_id: u64,
8307 downstream_client: AnyProtoClient,
8308 _: &mut Context<Self>,
8309 ) {
8310 self.downstream_client = Some((downstream_client.clone(), project_id));
8311
8312 for (server_id, status) in &self.language_server_statuses {
8313 if let Some(server) = self.language_server_for_id(*server_id) {
8314 downstream_client
8315 .send(proto::StartLanguageServer {
8316 project_id,
8317 server: Some(proto::LanguageServer {
8318 id: server_id.to_proto(),
8319 name: status.name.to_string(),
8320 worktree_id: status.worktree.map(|id| id.to_proto()),
8321 }),
8322 capabilities: serde_json::to_string(&server.capabilities())
8323 .expect("serializing server LSP capabilities"),
8324 })
8325 .log_err();
8326 }
8327 }
8328 }
8329
8330 pub fn disconnected_from_host(&mut self) {
8331 self.downstream_client.take();
8332 }
8333
8334 pub fn disconnected_from_ssh_remote(&mut self) {
8335 if let LspStoreMode::Remote(RemoteLspStore {
8336 upstream_client, ..
8337 }) = &mut self.mode
8338 {
8339 upstream_client.take();
8340 }
8341 }
8342
8343 pub(crate) fn set_language_server_statuses_from_proto(
8344 &mut self,
8345 project: WeakEntity<Project>,
8346 language_servers: Vec<proto::LanguageServer>,
8347 server_capabilities: Vec<String>,
8348 cx: &mut Context<Self>,
8349 ) {
8350 let lsp_logs = cx
8351 .try_global::<GlobalLogStore>()
8352 .map(|lsp_store| lsp_store.0.clone());
8353
8354 self.language_server_statuses = language_servers
8355 .into_iter()
8356 .zip(server_capabilities)
8357 .map(|(server, server_capabilities)| {
8358 let server_id = LanguageServerId(server.id as usize);
8359 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8360 self.lsp_server_capabilities
8361 .insert(server_id, server_capabilities);
8362 }
8363
8364 let name = LanguageServerName::from_proto(server.name);
8365 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8366
8367 if let Some(lsp_logs) = &lsp_logs {
8368 lsp_logs.update(cx, |lsp_logs, cx| {
8369 lsp_logs.add_language_server(
8370 // Only remote clients get their language servers set from proto
8371 LanguageServerKind::Remote {
8372 project: project.clone(),
8373 },
8374 server_id,
8375 Some(name.clone()),
8376 worktree,
8377 None,
8378 cx,
8379 );
8380 });
8381 }
8382
8383 (
8384 server_id,
8385 LanguageServerStatus {
8386 name,
8387 server_version: None,
8388 server_readable_version: None,
8389 pending_work: Default::default(),
8390 has_pending_diagnostic_updates: false,
8391 progress_tokens: Default::default(),
8392 worktree,
8393 binary: None,
8394 configuration: None,
8395 workspace_folders: BTreeSet::new(),
8396 process_id: None,
8397 },
8398 )
8399 })
8400 .collect();
8401 }
8402
8403 #[cfg(feature = "test-support")]
8404 pub fn update_diagnostic_entries(
8405 &mut self,
8406 server_id: LanguageServerId,
8407 abs_path: PathBuf,
8408 result_id: Option<SharedString>,
8409 version: Option<i32>,
8410 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8411 cx: &mut Context<Self>,
8412 ) -> anyhow::Result<()> {
8413 self.merge_diagnostic_entries(
8414 vec![DocumentDiagnosticsUpdate {
8415 diagnostics: DocumentDiagnostics {
8416 diagnostics,
8417 document_abs_path: abs_path,
8418 version,
8419 },
8420 result_id,
8421 server_id,
8422 disk_based_sources: Cow::Borrowed(&[]),
8423 registration_id: None,
8424 }],
8425 |_, _, _| false,
8426 cx,
8427 )?;
8428 Ok(())
8429 }
8430
8431 pub fn merge_diagnostic_entries<'a>(
8432 &mut self,
8433 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8434 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8435 cx: &mut Context<Self>,
8436 ) -> anyhow::Result<()> {
8437 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8438 let mut updated_diagnostics_paths = HashMap::default();
8439 for mut update in diagnostic_updates {
8440 let abs_path = &update.diagnostics.document_abs_path;
8441 let server_id = update.server_id;
8442 let Some((worktree, relative_path)) =
8443 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8444 else {
8445 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8446 return Ok(());
8447 };
8448
8449 let worktree_id = worktree.read(cx).id();
8450 let project_path = ProjectPath {
8451 worktree_id,
8452 path: relative_path,
8453 };
8454
8455 let document_uri = lsp::Uri::from_file_path(abs_path)
8456 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8457 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8458 let snapshot = buffer_handle.read(cx).snapshot();
8459 let buffer = buffer_handle.read(cx);
8460 let reused_diagnostics = buffer
8461 .buffer_diagnostics(Some(server_id))
8462 .iter()
8463 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8464 .map(|v| {
8465 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8466 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8467 DiagnosticEntry {
8468 range: start..end,
8469 diagnostic: v.diagnostic.clone(),
8470 }
8471 })
8472 .collect::<Vec<_>>();
8473
8474 self.as_local_mut()
8475 .context("cannot merge diagnostics on a remote LspStore")?
8476 .update_buffer_diagnostics(
8477 &buffer_handle,
8478 server_id,
8479 Some(update.registration_id),
8480 update.result_id,
8481 update.diagnostics.version,
8482 update.diagnostics.diagnostics.clone(),
8483 reused_diagnostics.clone(),
8484 cx,
8485 )?;
8486
8487 update.diagnostics.diagnostics.extend(reused_diagnostics);
8488 } else if let Some(local) = self.as_local() {
8489 let reused_diagnostics = local
8490 .diagnostics
8491 .get(&worktree_id)
8492 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8493 .and_then(|diagnostics_by_server_id| {
8494 diagnostics_by_server_id
8495 .binary_search_by_key(&server_id, |e| e.0)
8496 .ok()
8497 .map(|ix| &diagnostics_by_server_id[ix].1)
8498 })
8499 .into_iter()
8500 .flatten()
8501 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8502
8503 update
8504 .diagnostics
8505 .diagnostics
8506 .extend(reused_diagnostics.cloned());
8507 }
8508
8509 let updated = worktree.update(cx, |worktree, cx| {
8510 self.update_worktree_diagnostics(
8511 worktree.id(),
8512 server_id,
8513 project_path.path.clone(),
8514 update.diagnostics.diagnostics,
8515 cx,
8516 )
8517 })?;
8518 match updated {
8519 ControlFlow::Continue(new_summary) => {
8520 if let Some((project_id, new_summary)) = new_summary {
8521 match &mut diagnostics_summary {
8522 Some(diagnostics_summary) => {
8523 diagnostics_summary
8524 .more_summaries
8525 .push(proto::DiagnosticSummary {
8526 path: project_path.path.as_ref().to_proto(),
8527 language_server_id: server_id.0 as u64,
8528 error_count: new_summary.error_count,
8529 warning_count: new_summary.warning_count,
8530 })
8531 }
8532 None => {
8533 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8534 project_id,
8535 worktree_id: worktree_id.to_proto(),
8536 summary: Some(proto::DiagnosticSummary {
8537 path: project_path.path.as_ref().to_proto(),
8538 language_server_id: server_id.0 as u64,
8539 error_count: new_summary.error_count,
8540 warning_count: new_summary.warning_count,
8541 }),
8542 more_summaries: Vec::new(),
8543 })
8544 }
8545 }
8546 }
8547 updated_diagnostics_paths
8548 .entry(server_id)
8549 .or_insert_with(Vec::new)
8550 .push(project_path);
8551 }
8552 ControlFlow::Break(()) => {}
8553 }
8554 }
8555
8556 if let Some((diagnostics_summary, (downstream_client, _))) =
8557 diagnostics_summary.zip(self.downstream_client.as_ref())
8558 {
8559 downstream_client.send(diagnostics_summary).log_err();
8560 }
8561 for (server_id, paths) in updated_diagnostics_paths {
8562 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8563 }
8564 Ok(())
8565 }
8566
8567 fn update_worktree_diagnostics(
8568 &mut self,
8569 worktree_id: WorktreeId,
8570 server_id: LanguageServerId,
8571 path_in_worktree: Arc<RelPath>,
8572 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8573 _: &mut Context<Worktree>,
8574 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8575 let local = match &mut self.mode {
8576 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8577 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8578 };
8579
8580 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8581 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8582 let summaries_by_server_id = summaries_for_tree
8583 .entry(path_in_worktree.clone())
8584 .or_default();
8585
8586 let old_summary = summaries_by_server_id
8587 .remove(&server_id)
8588 .unwrap_or_default();
8589
8590 let new_summary = DiagnosticSummary::new(&diagnostics);
8591 if diagnostics.is_empty() {
8592 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8593 {
8594 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8595 diagnostics_by_server_id.remove(ix);
8596 }
8597 if diagnostics_by_server_id.is_empty() {
8598 diagnostics_for_tree.remove(&path_in_worktree);
8599 }
8600 }
8601 } else {
8602 summaries_by_server_id.insert(server_id, new_summary);
8603 let diagnostics_by_server_id = diagnostics_for_tree
8604 .entry(path_in_worktree.clone())
8605 .or_default();
8606 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8607 Ok(ix) => {
8608 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8609 }
8610 Err(ix) => {
8611 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8612 }
8613 }
8614 }
8615
8616 if !old_summary.is_empty() || !new_summary.is_empty() {
8617 if let Some((_, project_id)) = &self.downstream_client {
8618 Ok(ControlFlow::Continue(Some((
8619 *project_id,
8620 proto::DiagnosticSummary {
8621 path: path_in_worktree.to_proto(),
8622 language_server_id: server_id.0 as u64,
8623 error_count: new_summary.error_count as u32,
8624 warning_count: new_summary.warning_count as u32,
8625 },
8626 ))))
8627 } else {
8628 Ok(ControlFlow::Continue(None))
8629 }
8630 } else {
8631 Ok(ControlFlow::Break(()))
8632 }
8633 }
8634
8635 pub fn open_buffer_for_symbol(
8636 &mut self,
8637 symbol: &Symbol,
8638 cx: &mut Context<Self>,
8639 ) -> Task<Result<Entity<Buffer>>> {
8640 if let Some((client, project_id)) = self.upstream_client() {
8641 let request = client.request(proto::OpenBufferForSymbol {
8642 project_id,
8643 symbol: Some(Self::serialize_symbol(symbol)),
8644 });
8645 cx.spawn(async move |this, cx| {
8646 let response = request.await?;
8647 let buffer_id = BufferId::new(response.buffer_id)?;
8648 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8649 .await
8650 })
8651 } else if let Some(local) = self.as_local() {
8652 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8653 seed.worktree_id == symbol.source_worktree_id
8654 && state.id == symbol.source_language_server_id
8655 && symbol.language_server_name == seed.name
8656 });
8657 if !is_valid {
8658 return Task::ready(Err(anyhow!(
8659 "language server for worktree and language not found"
8660 )));
8661 };
8662
8663 let symbol_abs_path = match &symbol.path {
8664 SymbolLocation::InProject(project_path) => self
8665 .worktree_store
8666 .read(cx)
8667 .absolutize(&project_path, cx)
8668 .context("no such worktree"),
8669 SymbolLocation::OutsideProject {
8670 abs_path,
8671 signature: _,
8672 } => Ok(abs_path.to_path_buf()),
8673 };
8674 let symbol_abs_path = match symbol_abs_path {
8675 Ok(abs_path) => abs_path,
8676 Err(err) => return Task::ready(Err(err)),
8677 };
8678 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8679 uri
8680 } else {
8681 return Task::ready(Err(anyhow!("invalid symbol path")));
8682 };
8683
8684 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8685 } else {
8686 Task::ready(Err(anyhow!("no upstream client or local store")))
8687 }
8688 }
8689
8690 pub(crate) fn open_local_buffer_via_lsp(
8691 &mut self,
8692 abs_path: lsp::Uri,
8693 language_server_id: LanguageServerId,
8694 cx: &mut Context<Self>,
8695 ) -> Task<Result<Entity<Buffer>>> {
8696 let path_style = self.worktree_store.read(cx).path_style();
8697 cx.spawn(async move |lsp_store, cx| {
8698 // Escape percent-encoded string.
8699 let current_scheme = abs_path.scheme().to_owned();
8700 // Uri is immutable, so we can't modify the scheme
8701
8702 let abs_path = abs_path
8703 .to_file_path_ext(path_style)
8704 .map_err(|()| anyhow!("can't convert URI to path"))?;
8705 let p = abs_path.clone();
8706 let yarn_worktree = lsp_store
8707 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8708 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8709 cx.spawn(async move |this, cx| {
8710 let t = this
8711 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8712 .ok()?;
8713 t.await
8714 })
8715 }),
8716 None => Task::ready(None),
8717 })?
8718 .await;
8719 let (worktree_root_target, known_relative_path) =
8720 if let Some((zip_root, relative_path)) = yarn_worktree {
8721 (zip_root, Some(relative_path))
8722 } else {
8723 (Arc::<Path>::from(abs_path.as_path()), None)
8724 };
8725 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8726 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8727 worktree_store.find_worktree(&worktree_root_target, cx)
8728 })
8729 })?;
8730 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8731 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8732 (result.0, relative_path, None)
8733 } else {
8734 let worktree = lsp_store
8735 .update(cx, |lsp_store, cx| {
8736 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8737 worktree_store.create_worktree(&worktree_root_target, false, cx)
8738 })
8739 })?
8740 .await?;
8741 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8742 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8743 lsp_store
8744 .update(cx, |lsp_store, cx| {
8745 if let Some(local) = lsp_store.as_local_mut() {
8746 local.register_language_server_for_invisible_worktree(
8747 &worktree,
8748 language_server_id,
8749 cx,
8750 )
8751 }
8752 match lsp_store.language_server_statuses.get(&language_server_id) {
8753 Some(status) => status.worktree,
8754 None => None,
8755 }
8756 })
8757 .ok()
8758 .flatten()
8759 .zip(Some(worktree_root.clone()))
8760 } else {
8761 None
8762 };
8763 let relative_path = if let Some(known_path) = known_relative_path {
8764 known_path
8765 } else {
8766 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8767 .into_arc()
8768 };
8769 (worktree, relative_path, source_ws)
8770 };
8771 let project_path = ProjectPath {
8772 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8773 path: relative_path,
8774 };
8775 let buffer = lsp_store
8776 .update(cx, |lsp_store, cx| {
8777 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8778 buffer_store.open_buffer(project_path, cx)
8779 })
8780 })?
8781 .await?;
8782 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8783 if let Some((source_ws, worktree_root)) = source_ws {
8784 buffer.update(cx, |buffer, cx| {
8785 let settings = WorktreeSettings::get(
8786 Some(
8787 (&ProjectPath {
8788 worktree_id: source_ws,
8789 path: Arc::from(RelPath::empty()),
8790 })
8791 .into(),
8792 ),
8793 cx,
8794 );
8795 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8796 if is_read_only {
8797 buffer.set_capability(Capability::ReadOnly, cx);
8798 }
8799 });
8800 }
8801 Ok(buffer)
8802 })
8803 }
8804
8805 fn local_lsp_servers_for_buffer(
8806 &self,
8807 buffer: &Entity<Buffer>,
8808 cx: &mut Context<Self>,
8809 ) -> Vec<LanguageServerId> {
8810 let Some(local) = self.as_local() else {
8811 return Vec::new();
8812 };
8813
8814 let snapshot = buffer.read(cx).snapshot();
8815
8816 buffer.update(cx, |buffer, cx| {
8817 local
8818 .language_servers_for_buffer(buffer, cx)
8819 .map(|(_, server)| server.server_id())
8820 .filter(|server_id| {
8821 self.as_local().is_none_or(|local| {
8822 local
8823 .buffers_opened_in_servers
8824 .get(&snapshot.remote_id())
8825 .is_some_and(|servers| servers.contains(server_id))
8826 })
8827 })
8828 .collect()
8829 })
8830 }
8831
8832 fn request_multiple_lsp_locally<P, R>(
8833 &mut self,
8834 buffer: &Entity<Buffer>,
8835 position: Option<P>,
8836 request: R,
8837 cx: &mut Context<Self>,
8838 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8839 where
8840 P: ToOffset,
8841 R: LspCommand + Clone,
8842 <R::LspRequest as lsp::request::Request>::Result: Send,
8843 <R::LspRequest as lsp::request::Request>::Params: Send,
8844 {
8845 let Some(local) = self.as_local() else {
8846 return Task::ready(Vec::new());
8847 };
8848
8849 let snapshot = buffer.read(cx).snapshot();
8850 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8851
8852 let server_ids = buffer.update(cx, |buffer, cx| {
8853 local
8854 .language_servers_for_buffer(buffer, cx)
8855 .filter(|(adapter, _)| {
8856 scope
8857 .as_ref()
8858 .map(|scope| scope.language_allowed(&adapter.name))
8859 .unwrap_or(true)
8860 })
8861 .map(|(_, server)| server.server_id())
8862 .filter(|server_id| {
8863 self.as_local().is_none_or(|local| {
8864 local
8865 .buffers_opened_in_servers
8866 .get(&snapshot.remote_id())
8867 .is_some_and(|servers| servers.contains(server_id))
8868 })
8869 })
8870 .collect::<Vec<_>>()
8871 });
8872
8873 let mut response_results = server_ids
8874 .into_iter()
8875 .map(|server_id| {
8876 let task = self.request_lsp(
8877 buffer.clone(),
8878 LanguageServerToQuery::Other(server_id),
8879 request.clone(),
8880 cx,
8881 );
8882 async move { (server_id, task.await) }
8883 })
8884 .collect::<FuturesUnordered<_>>();
8885
8886 cx.background_spawn(async move {
8887 let mut responses = Vec::with_capacity(response_results.len());
8888 while let Some((server_id, response_result)) = response_results.next().await {
8889 match response_result {
8890 Ok(response) => responses.push((server_id, response)),
8891 // rust-analyzer likes to error with this when its still loading up
8892 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8893 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8894 }
8895 }
8896 responses
8897 })
8898 }
8899
8900 async fn handle_lsp_get_completions(
8901 this: Entity<Self>,
8902 envelope: TypedEnvelope<proto::GetCompletions>,
8903 mut cx: AsyncApp,
8904 ) -> Result<proto::GetCompletionsResponse> {
8905 let sender_id = envelope.original_sender_id().unwrap_or_default();
8906
8907 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8908 let buffer_handle = this.update(&mut cx, |this, cx| {
8909 this.buffer_store.read(cx).get_existing(buffer_id)
8910 })?;
8911 let request = GetCompletions::from_proto(
8912 envelope.payload,
8913 this.clone(),
8914 buffer_handle.clone(),
8915 cx.clone(),
8916 )
8917 .await?;
8918
8919 let server_to_query = match request.server_id {
8920 Some(server_id) => LanguageServerToQuery::Other(server_id),
8921 None => LanguageServerToQuery::FirstCapable,
8922 };
8923
8924 let response = this
8925 .update(&mut cx, |this, cx| {
8926 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8927 })
8928 .await?;
8929 this.update(&mut cx, |this, cx| {
8930 Ok(GetCompletions::response_to_proto(
8931 response,
8932 this,
8933 sender_id,
8934 &buffer_handle.read(cx).version(),
8935 cx,
8936 ))
8937 })
8938 }
8939
8940 async fn handle_lsp_command<T: LspCommand>(
8941 this: Entity<Self>,
8942 envelope: TypedEnvelope<T::ProtoRequest>,
8943 mut cx: AsyncApp,
8944 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8945 where
8946 <T::LspRequest as lsp::request::Request>::Params: Send,
8947 <T::LspRequest as lsp::request::Request>::Result: Send,
8948 {
8949 let sender_id = envelope.original_sender_id().unwrap_or_default();
8950 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8951 let buffer_handle = this.update(&mut cx, |this, cx| {
8952 this.buffer_store.read(cx).get_existing(buffer_id)
8953 })?;
8954 let request = T::from_proto(
8955 envelope.payload,
8956 this.clone(),
8957 buffer_handle.clone(),
8958 cx.clone(),
8959 )
8960 .await?;
8961 let response = this
8962 .update(&mut cx, |this, cx| {
8963 this.request_lsp(
8964 buffer_handle.clone(),
8965 LanguageServerToQuery::FirstCapable,
8966 request,
8967 cx,
8968 )
8969 })
8970 .await?;
8971 this.update(&mut cx, |this, cx| {
8972 Ok(T::response_to_proto(
8973 response,
8974 this,
8975 sender_id,
8976 &buffer_handle.read(cx).version(),
8977 cx,
8978 ))
8979 })
8980 }
8981
8982 async fn handle_lsp_query(
8983 lsp_store: Entity<Self>,
8984 envelope: TypedEnvelope<proto::LspQuery>,
8985 mut cx: AsyncApp,
8986 ) -> Result<proto::Ack> {
8987 use proto::lsp_query::Request;
8988 let sender_id = envelope.original_sender_id().unwrap_or_default();
8989 let lsp_query = envelope.payload;
8990 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8991 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8992 match lsp_query.request.context("invalid LSP query request")? {
8993 Request::GetReferences(get_references) => {
8994 let position = get_references.position.clone().and_then(deserialize_anchor);
8995 Self::query_lsp_locally::<GetReferences>(
8996 lsp_store,
8997 server_id,
8998 sender_id,
8999 lsp_request_id,
9000 get_references,
9001 position,
9002 &mut cx,
9003 )
9004 .await?;
9005 }
9006 Request::GetDocumentColor(get_document_color) => {
9007 Self::query_lsp_locally::<GetDocumentColor>(
9008 lsp_store,
9009 server_id,
9010 sender_id,
9011 lsp_request_id,
9012 get_document_color,
9013 None,
9014 &mut cx,
9015 )
9016 .await?;
9017 }
9018 Request::GetFoldingRanges(get_folding_ranges) => {
9019 Self::query_lsp_locally::<GetFoldingRanges>(
9020 lsp_store,
9021 server_id,
9022 sender_id,
9023 lsp_request_id,
9024 get_folding_ranges,
9025 None,
9026 &mut cx,
9027 )
9028 .await?;
9029 }
9030 Request::GetDocumentSymbols(get_document_symbols) => {
9031 Self::query_lsp_locally::<GetDocumentSymbols>(
9032 lsp_store,
9033 server_id,
9034 sender_id,
9035 lsp_request_id,
9036 get_document_symbols,
9037 None,
9038 &mut cx,
9039 )
9040 .await?;
9041 }
9042 Request::GetHover(get_hover) => {
9043 let position = get_hover.position.clone().and_then(deserialize_anchor);
9044 Self::query_lsp_locally::<GetHover>(
9045 lsp_store,
9046 server_id,
9047 sender_id,
9048 lsp_request_id,
9049 get_hover,
9050 position,
9051 &mut cx,
9052 )
9053 .await?;
9054 }
9055 Request::GetCodeActions(get_code_actions) => {
9056 Self::query_lsp_locally::<GetCodeActions>(
9057 lsp_store,
9058 server_id,
9059 sender_id,
9060 lsp_request_id,
9061 get_code_actions,
9062 None,
9063 &mut cx,
9064 )
9065 .await?;
9066 }
9067 Request::GetSignatureHelp(get_signature_help) => {
9068 let position = get_signature_help
9069 .position
9070 .clone()
9071 .and_then(deserialize_anchor);
9072 Self::query_lsp_locally::<GetSignatureHelp>(
9073 lsp_store,
9074 server_id,
9075 sender_id,
9076 lsp_request_id,
9077 get_signature_help,
9078 position,
9079 &mut cx,
9080 )
9081 .await?;
9082 }
9083 Request::GetCodeLens(get_code_lens) => {
9084 Self::query_lsp_locally::<GetCodeLens>(
9085 lsp_store,
9086 server_id,
9087 sender_id,
9088 lsp_request_id,
9089 get_code_lens,
9090 None,
9091 &mut cx,
9092 )
9093 .await?;
9094 }
9095 Request::GetDefinition(get_definition) => {
9096 let position = get_definition.position.clone().and_then(deserialize_anchor);
9097 Self::query_lsp_locally::<GetDefinitions>(
9098 lsp_store,
9099 server_id,
9100 sender_id,
9101 lsp_request_id,
9102 get_definition,
9103 position,
9104 &mut cx,
9105 )
9106 .await?;
9107 }
9108 Request::GetDeclaration(get_declaration) => {
9109 let position = get_declaration
9110 .position
9111 .clone()
9112 .and_then(deserialize_anchor);
9113 Self::query_lsp_locally::<GetDeclarations>(
9114 lsp_store,
9115 server_id,
9116 sender_id,
9117 lsp_request_id,
9118 get_declaration,
9119 position,
9120 &mut cx,
9121 )
9122 .await?;
9123 }
9124 Request::GetTypeDefinition(get_type_definition) => {
9125 let position = get_type_definition
9126 .position
9127 .clone()
9128 .and_then(deserialize_anchor);
9129 Self::query_lsp_locally::<GetTypeDefinitions>(
9130 lsp_store,
9131 server_id,
9132 sender_id,
9133 lsp_request_id,
9134 get_type_definition,
9135 position,
9136 &mut cx,
9137 )
9138 .await?;
9139 }
9140 Request::GetImplementation(get_implementation) => {
9141 let position = get_implementation
9142 .position
9143 .clone()
9144 .and_then(deserialize_anchor);
9145 Self::query_lsp_locally::<GetImplementations>(
9146 lsp_store,
9147 server_id,
9148 sender_id,
9149 lsp_request_id,
9150 get_implementation,
9151 position,
9152 &mut cx,
9153 )
9154 .await?;
9155 }
9156 Request::InlayHints(inlay_hints) => {
9157 let query_start = inlay_hints
9158 .start
9159 .clone()
9160 .and_then(deserialize_anchor)
9161 .context("invalid inlay hints range start")?;
9162 let query_end = inlay_hints
9163 .end
9164 .clone()
9165 .and_then(deserialize_anchor)
9166 .context("invalid inlay hints range end")?;
9167 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9168 &lsp_store,
9169 server_id,
9170 lsp_request_id,
9171 &inlay_hints,
9172 query_start..query_end,
9173 &mut cx,
9174 )
9175 .await
9176 .context("preparing inlay hints request")?;
9177 Self::query_lsp_locally::<InlayHints>(
9178 lsp_store,
9179 server_id,
9180 sender_id,
9181 lsp_request_id,
9182 inlay_hints,
9183 None,
9184 &mut cx,
9185 )
9186 .await
9187 .context("querying for inlay hints")?
9188 }
9189 //////////////////////////////
9190 // Below are LSP queries that need to fetch more data,
9191 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9192 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9193 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9194 &lsp_store,
9195 &get_document_diagnostics,
9196 &mut cx,
9197 )
9198 .await?;
9199 lsp_store.update(&mut cx, |lsp_store, cx| {
9200 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9201 let key = LspKey {
9202 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9203 server_queried: server_id,
9204 };
9205 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9206 ) {
9207 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9208 lsp_requests.clear();
9209 };
9210 }
9211
9212 lsp_data.lsp_requests.entry(key).or_default().insert(
9213 lsp_request_id,
9214 cx.spawn(async move |lsp_store, cx| {
9215 let diagnostics_pull = lsp_store
9216 .update(cx, |lsp_store, cx| {
9217 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9218 })
9219 .ok();
9220 if let Some(diagnostics_pull) = diagnostics_pull {
9221 match diagnostics_pull.await {
9222 Ok(()) => {}
9223 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9224 };
9225 }
9226 }),
9227 );
9228 });
9229 }
9230 Request::SemanticTokens(semantic_tokens) => {
9231 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9232 &lsp_store,
9233 &semantic_tokens,
9234 &mut cx,
9235 )
9236 .await?;
9237 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9238 lsp_store.update(&mut cx, |lsp_store, cx| {
9239 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9240 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9241 let key = LspKey {
9242 request_type: TypeId::of::<SemanticTokensFull>(),
9243 server_queried: server_id,
9244 };
9245 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9246 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9247 lsp_requests.clear();
9248 };
9249 }
9250
9251 lsp_data.lsp_requests.entry(key).or_default().insert(
9252 lsp_request_id,
9253 cx.spawn(async move |lsp_store, cx| {
9254 let tokens_fetch = lsp_store
9255 .update(cx, |lsp_store, cx| {
9256 lsp_store
9257 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9258 })
9259 .ok();
9260 if let Some(tokens_fetch) = tokens_fetch {
9261 let new_tokens = tokens_fetch.await;
9262 if let Some(new_tokens) = new_tokens {
9263 lsp_store
9264 .update(cx, |lsp_store, cx| {
9265 let response = new_tokens
9266 .into_iter()
9267 .map(|(server_id, response)| {
9268 (
9269 server_id.to_proto(),
9270 SemanticTokensFull::response_to_proto(
9271 response,
9272 lsp_store,
9273 sender_id,
9274 &buffer_version,
9275 cx,
9276 ),
9277 )
9278 })
9279 .collect::<HashMap<_, _>>();
9280 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9281 project_id,
9282 lsp_request_id,
9283 response,
9284 ) {
9285 Ok(()) => {}
9286 Err(e) => {
9287 log::error!(
9288 "Failed to send semantic tokens LSP response: {e:#}",
9289 )
9290 }
9291 }
9292 })
9293 .ok();
9294 }
9295 }
9296 }),
9297 );
9298 }
9299 });
9300 }
9301 }
9302 Ok(proto::Ack {})
9303 }
9304
9305 async fn handle_lsp_query_response(
9306 lsp_store: Entity<Self>,
9307 envelope: TypedEnvelope<proto::LspQueryResponse>,
9308 cx: AsyncApp,
9309 ) -> Result<()> {
9310 lsp_store.read_with(&cx, |lsp_store, _| {
9311 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9312 upstream_client.handle_lsp_response(envelope.clone());
9313 }
9314 });
9315 Ok(())
9316 }
9317
9318 async fn handle_apply_code_action(
9319 this: Entity<Self>,
9320 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9321 mut cx: AsyncApp,
9322 ) -> Result<proto::ApplyCodeActionResponse> {
9323 let sender_id = envelope.original_sender_id().unwrap_or_default();
9324 let action =
9325 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9326 let apply_code_action = this.update(&mut cx, |this, cx| {
9327 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9328 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9329 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9330 })?;
9331
9332 let project_transaction = apply_code_action.await?;
9333 let project_transaction = this.update(&mut cx, |this, cx| {
9334 this.buffer_store.update(cx, |buffer_store, cx| {
9335 buffer_store.serialize_project_transaction_for_peer(
9336 project_transaction,
9337 sender_id,
9338 cx,
9339 )
9340 })
9341 });
9342 Ok(proto::ApplyCodeActionResponse {
9343 transaction: Some(project_transaction),
9344 })
9345 }
9346
9347 async fn handle_register_buffer_with_language_servers(
9348 this: Entity<Self>,
9349 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9350 mut cx: AsyncApp,
9351 ) -> Result<proto::Ack> {
9352 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9353 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9354 this.update(&mut cx, |this, cx| {
9355 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9356 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9357 project_id: upstream_project_id,
9358 buffer_id: buffer_id.to_proto(),
9359 only_servers: envelope.payload.only_servers,
9360 });
9361 }
9362
9363 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9364 anyhow::bail!("buffer is not open");
9365 };
9366
9367 let handle = this.register_buffer_with_language_servers(
9368 &buffer,
9369 envelope
9370 .payload
9371 .only_servers
9372 .into_iter()
9373 .filter_map(|selector| {
9374 Some(match selector.selector? {
9375 proto::language_server_selector::Selector::ServerId(server_id) => {
9376 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9377 }
9378 proto::language_server_selector::Selector::Name(name) => {
9379 LanguageServerSelector::Name(LanguageServerName(
9380 SharedString::from(name),
9381 ))
9382 }
9383 })
9384 })
9385 .collect(),
9386 false,
9387 cx,
9388 );
9389 // Pull diagnostics for the buffer even if it was already registered.
9390 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9391 // but it's unclear if we need it.
9392 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9393 .detach();
9394 this.buffer_store().update(cx, |buffer_store, _| {
9395 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9396 });
9397
9398 Ok(())
9399 })?;
9400 Ok(proto::Ack {})
9401 }
9402
9403 async fn handle_rename_project_entry(
9404 this: Entity<Self>,
9405 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9406 mut cx: AsyncApp,
9407 ) -> Result<proto::ProjectEntryResponse> {
9408 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9409 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9410 let new_path =
9411 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9412
9413 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9414 .update(&mut cx, |this, cx| {
9415 let (worktree, entry) = this
9416 .worktree_store
9417 .read(cx)
9418 .worktree_and_entry_for_id(entry_id, cx)?;
9419 let new_worktree = this
9420 .worktree_store
9421 .read(cx)
9422 .worktree_for_id(new_worktree_id, cx)?;
9423 Some((
9424 this.worktree_store.clone(),
9425 worktree,
9426 new_worktree,
9427 entry.clone(),
9428 ))
9429 })
9430 .context("worktree not found")?;
9431 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9432 (worktree.absolutize(&old_entry.path), worktree.id())
9433 });
9434 let new_abs_path =
9435 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9436
9437 let _transaction = Self::will_rename_entry(
9438 this.downgrade(),
9439 old_worktree_id,
9440 &old_abs_path,
9441 &new_abs_path,
9442 old_entry.is_dir(),
9443 cx.clone(),
9444 )
9445 .await;
9446 let response = WorktreeStore::handle_rename_project_entry(
9447 worktree_store,
9448 envelope.payload,
9449 cx.clone(),
9450 )
9451 .await;
9452 this.read_with(&cx, |this, _| {
9453 this.did_rename_entry(
9454 old_worktree_id,
9455 &old_abs_path,
9456 &new_abs_path,
9457 old_entry.is_dir(),
9458 );
9459 });
9460 response
9461 }
9462
9463 async fn handle_update_diagnostic_summary(
9464 this: Entity<Self>,
9465 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9466 mut cx: AsyncApp,
9467 ) -> Result<()> {
9468 this.update(&mut cx, |lsp_store, cx| {
9469 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9470 let mut updated_diagnostics_paths = HashMap::default();
9471 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9472 for message_summary in envelope
9473 .payload
9474 .summary
9475 .into_iter()
9476 .chain(envelope.payload.more_summaries)
9477 {
9478 let project_path = ProjectPath {
9479 worktree_id,
9480 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9481 };
9482 let path = project_path.path.clone();
9483 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9484 let summary = DiagnosticSummary {
9485 error_count: message_summary.error_count as usize,
9486 warning_count: message_summary.warning_count as usize,
9487 };
9488
9489 if summary.is_empty() {
9490 if let Some(worktree_summaries) =
9491 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9492 && let Some(summaries) = worktree_summaries.get_mut(&path)
9493 {
9494 summaries.remove(&server_id);
9495 if summaries.is_empty() {
9496 worktree_summaries.remove(&path);
9497 }
9498 }
9499 } else {
9500 lsp_store
9501 .diagnostic_summaries
9502 .entry(worktree_id)
9503 .or_default()
9504 .entry(path)
9505 .or_default()
9506 .insert(server_id, summary);
9507 }
9508
9509 if let Some((_, project_id)) = &lsp_store.downstream_client {
9510 match &mut diagnostics_summary {
9511 Some(diagnostics_summary) => {
9512 diagnostics_summary
9513 .more_summaries
9514 .push(proto::DiagnosticSummary {
9515 path: project_path.path.as_ref().to_proto(),
9516 language_server_id: server_id.0 as u64,
9517 error_count: summary.error_count as u32,
9518 warning_count: summary.warning_count as u32,
9519 })
9520 }
9521 None => {
9522 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9523 project_id: *project_id,
9524 worktree_id: worktree_id.to_proto(),
9525 summary: Some(proto::DiagnosticSummary {
9526 path: project_path.path.as_ref().to_proto(),
9527 language_server_id: server_id.0 as u64,
9528 error_count: summary.error_count as u32,
9529 warning_count: summary.warning_count as u32,
9530 }),
9531 more_summaries: Vec::new(),
9532 })
9533 }
9534 }
9535 }
9536 updated_diagnostics_paths
9537 .entry(server_id)
9538 .or_insert_with(Vec::new)
9539 .push(project_path);
9540 }
9541
9542 if let Some((diagnostics_summary, (downstream_client, _))) =
9543 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9544 {
9545 downstream_client.send(diagnostics_summary).log_err();
9546 }
9547 for (server_id, paths) in updated_diagnostics_paths {
9548 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9549 }
9550 Ok(())
9551 })
9552 }
9553
9554 async fn handle_start_language_server(
9555 lsp_store: Entity<Self>,
9556 envelope: TypedEnvelope<proto::StartLanguageServer>,
9557 mut cx: AsyncApp,
9558 ) -> Result<()> {
9559 let server = envelope.payload.server.context("invalid server")?;
9560 let server_capabilities =
9561 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9562 .with_context(|| {
9563 format!(
9564 "incorrect server capabilities {}",
9565 envelope.payload.capabilities
9566 )
9567 })?;
9568 lsp_store.update(&mut cx, |lsp_store, cx| {
9569 let server_id = LanguageServerId(server.id as usize);
9570 let server_name = LanguageServerName::from_proto(server.name.clone());
9571 lsp_store
9572 .lsp_server_capabilities
9573 .insert(server_id, server_capabilities);
9574 lsp_store.language_server_statuses.insert(
9575 server_id,
9576 LanguageServerStatus {
9577 name: server_name.clone(),
9578 server_version: None,
9579 server_readable_version: None,
9580 pending_work: Default::default(),
9581 has_pending_diagnostic_updates: false,
9582 progress_tokens: Default::default(),
9583 worktree: server.worktree_id.map(WorktreeId::from_proto),
9584 binary: None,
9585 configuration: None,
9586 workspace_folders: BTreeSet::new(),
9587 process_id: None,
9588 },
9589 );
9590 cx.emit(LspStoreEvent::LanguageServerAdded(
9591 server_id,
9592 server_name,
9593 server.worktree_id.map(WorktreeId::from_proto),
9594 ));
9595 cx.notify();
9596 });
9597 Ok(())
9598 }
9599
9600 async fn handle_update_language_server(
9601 lsp_store: Entity<Self>,
9602 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9603 mut cx: AsyncApp,
9604 ) -> Result<()> {
9605 lsp_store.update(&mut cx, |lsp_store, cx| {
9606 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9607
9608 match envelope.payload.variant.context("invalid variant")? {
9609 proto::update_language_server::Variant::WorkStart(payload) => {
9610 lsp_store.on_lsp_work_start(
9611 language_server_id,
9612 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9613 .context("invalid progress token value")?,
9614 LanguageServerProgress {
9615 title: payload.title,
9616 is_disk_based_diagnostics_progress: false,
9617 is_cancellable: payload.is_cancellable.unwrap_or(false),
9618 message: payload.message,
9619 percentage: payload.percentage.map(|p| p as usize),
9620 last_update_at: cx.background_executor().now(),
9621 },
9622 cx,
9623 );
9624 }
9625 proto::update_language_server::Variant::WorkProgress(payload) => {
9626 lsp_store.on_lsp_work_progress(
9627 language_server_id,
9628 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9629 .context("invalid progress token value")?,
9630 LanguageServerProgress {
9631 title: None,
9632 is_disk_based_diagnostics_progress: false,
9633 is_cancellable: payload.is_cancellable.unwrap_or(false),
9634 message: payload.message,
9635 percentage: payload.percentage.map(|p| p as usize),
9636 last_update_at: cx.background_executor().now(),
9637 },
9638 cx,
9639 );
9640 }
9641
9642 proto::update_language_server::Variant::WorkEnd(payload) => {
9643 lsp_store.on_lsp_work_end(
9644 language_server_id,
9645 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9646 .context("invalid progress token value")?,
9647 cx,
9648 );
9649 }
9650
9651 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9652 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9653 }
9654
9655 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9656 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9657 }
9658
9659 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9660 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9661 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9662 cx.emit(LspStoreEvent::LanguageServerUpdate {
9663 language_server_id,
9664 name: envelope
9665 .payload
9666 .server_name
9667 .map(SharedString::new)
9668 .map(LanguageServerName),
9669 message: non_lsp,
9670 });
9671 }
9672 }
9673
9674 Ok(())
9675 })
9676 }
9677
9678 async fn handle_language_server_log(
9679 this: Entity<Self>,
9680 envelope: TypedEnvelope<proto::LanguageServerLog>,
9681 mut cx: AsyncApp,
9682 ) -> Result<()> {
9683 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9684 let log_type = envelope
9685 .payload
9686 .log_type
9687 .map(LanguageServerLogType::from_proto)
9688 .context("invalid language server log type")?;
9689
9690 let message = envelope.payload.message;
9691
9692 this.update(&mut cx, |_, cx| {
9693 cx.emit(LspStoreEvent::LanguageServerLog(
9694 language_server_id,
9695 log_type,
9696 message,
9697 ));
9698 });
9699 Ok(())
9700 }
9701
9702 async fn handle_lsp_ext_cancel_flycheck(
9703 lsp_store: Entity<Self>,
9704 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9705 cx: AsyncApp,
9706 ) -> Result<proto::Ack> {
9707 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9708 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9709 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9710 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9711 } else {
9712 None
9713 }
9714 });
9715 if let Some(task) = task {
9716 task.context("handling lsp ext cancel flycheck")?;
9717 }
9718
9719 Ok(proto::Ack {})
9720 }
9721
9722 async fn handle_lsp_ext_run_flycheck(
9723 lsp_store: Entity<Self>,
9724 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9725 mut cx: AsyncApp,
9726 ) -> Result<proto::Ack> {
9727 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9728 lsp_store.update(&mut cx, |lsp_store, cx| {
9729 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9730 let text_document = if envelope.payload.current_file_only {
9731 let buffer_id = envelope
9732 .payload
9733 .buffer_id
9734 .map(|id| BufferId::new(id))
9735 .transpose()?;
9736 buffer_id
9737 .and_then(|buffer_id| {
9738 lsp_store
9739 .buffer_store()
9740 .read(cx)
9741 .get(buffer_id)
9742 .and_then(|buffer| {
9743 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9744 })
9745 .map(|path| make_text_document_identifier(&path))
9746 })
9747 .transpose()?
9748 } else {
9749 None
9750 };
9751 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9752 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9753 )?;
9754 }
9755 anyhow::Ok(())
9756 })?;
9757
9758 Ok(proto::Ack {})
9759 }
9760
9761 async fn handle_lsp_ext_clear_flycheck(
9762 lsp_store: Entity<Self>,
9763 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9764 cx: AsyncApp,
9765 ) -> Result<proto::Ack> {
9766 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9767 lsp_store.read_with(&cx, |lsp_store, _| {
9768 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9769 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9770 } else {
9771 None
9772 }
9773 });
9774
9775 Ok(proto::Ack {})
9776 }
9777
9778 pub fn disk_based_diagnostics_started(
9779 &mut self,
9780 language_server_id: LanguageServerId,
9781 cx: &mut Context<Self>,
9782 ) {
9783 if let Some(language_server_status) =
9784 self.language_server_statuses.get_mut(&language_server_id)
9785 {
9786 language_server_status.has_pending_diagnostic_updates = true;
9787 }
9788
9789 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9790 cx.emit(LspStoreEvent::LanguageServerUpdate {
9791 language_server_id,
9792 name: self
9793 .language_server_adapter_for_id(language_server_id)
9794 .map(|adapter| adapter.name()),
9795 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9796 Default::default(),
9797 ),
9798 })
9799 }
9800
9801 pub fn disk_based_diagnostics_finished(
9802 &mut self,
9803 language_server_id: LanguageServerId,
9804 cx: &mut Context<Self>,
9805 ) {
9806 if let Some(language_server_status) =
9807 self.language_server_statuses.get_mut(&language_server_id)
9808 {
9809 language_server_status.has_pending_diagnostic_updates = false;
9810 }
9811
9812 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9813 cx.emit(LspStoreEvent::LanguageServerUpdate {
9814 language_server_id,
9815 name: self
9816 .language_server_adapter_for_id(language_server_id)
9817 .map(|adapter| adapter.name()),
9818 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9819 Default::default(),
9820 ),
9821 })
9822 }
9823
9824 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9825 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9826 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9827 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9828 // the language server might take some time to publish diagnostics.
9829 fn simulate_disk_based_diagnostics_events_if_needed(
9830 &mut self,
9831 language_server_id: LanguageServerId,
9832 cx: &mut Context<Self>,
9833 ) {
9834 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9835
9836 let Some(LanguageServerState::Running {
9837 simulate_disk_based_diagnostics_completion,
9838 adapter,
9839 ..
9840 }) = self
9841 .as_local_mut()
9842 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9843 else {
9844 return;
9845 };
9846
9847 if adapter.disk_based_diagnostics_progress_token.is_some() {
9848 return;
9849 }
9850
9851 let prev_task =
9852 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9853 cx.background_executor()
9854 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9855 .await;
9856
9857 this.update(cx, |this, cx| {
9858 this.disk_based_diagnostics_finished(language_server_id, cx);
9859
9860 if let Some(LanguageServerState::Running {
9861 simulate_disk_based_diagnostics_completion,
9862 ..
9863 }) = this.as_local_mut().and_then(|local_store| {
9864 local_store.language_servers.get_mut(&language_server_id)
9865 }) {
9866 *simulate_disk_based_diagnostics_completion = None;
9867 }
9868 })
9869 .ok();
9870 }));
9871
9872 if prev_task.is_none() {
9873 self.disk_based_diagnostics_started(language_server_id, cx);
9874 }
9875 }
9876
9877 pub fn language_server_statuses(
9878 &self,
9879 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9880 self.language_server_statuses
9881 .iter()
9882 .map(|(key, value)| (*key, value))
9883 }
9884
9885 pub(super) fn did_rename_entry(
9886 &self,
9887 worktree_id: WorktreeId,
9888 old_path: &Path,
9889 new_path: &Path,
9890 is_dir: bool,
9891 ) {
9892 maybe!({
9893 let local_store = self.as_local()?;
9894
9895 let old_uri = lsp::Uri::from_file_path(old_path)
9896 .ok()
9897 .map(|uri| uri.to_string())?;
9898 let new_uri = lsp::Uri::from_file_path(new_path)
9899 .ok()
9900 .map(|uri| uri.to_string())?;
9901
9902 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9903 let Some(filter) = local_store
9904 .language_server_paths_watched_for_rename
9905 .get(&language_server.server_id())
9906 else {
9907 continue;
9908 };
9909
9910 if filter.should_send_did_rename(&old_uri, is_dir) {
9911 language_server
9912 .notify::<DidRenameFiles>(RenameFilesParams {
9913 files: vec![FileRename {
9914 old_uri: old_uri.clone(),
9915 new_uri: new_uri.clone(),
9916 }],
9917 })
9918 .ok();
9919 }
9920 }
9921 Some(())
9922 });
9923 }
9924
9925 pub(super) fn will_rename_entry(
9926 this: WeakEntity<Self>,
9927 worktree_id: WorktreeId,
9928 old_path: &Path,
9929 new_path: &Path,
9930 is_dir: bool,
9931 cx: AsyncApp,
9932 ) -> Task<ProjectTransaction> {
9933 let old_uri = lsp::Uri::from_file_path(old_path)
9934 .ok()
9935 .map(|uri| uri.to_string());
9936 let new_uri = lsp::Uri::from_file_path(new_path)
9937 .ok()
9938 .map(|uri| uri.to_string());
9939 cx.spawn(async move |cx| {
9940 let mut tasks = vec![];
9941 this.update(cx, |this, cx| {
9942 let local_store = this.as_local()?;
9943 let old_uri = old_uri?;
9944 let new_uri = new_uri?;
9945 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9946 let Some(filter) = local_store
9947 .language_server_paths_watched_for_rename
9948 .get(&language_server.server_id())
9949 else {
9950 continue;
9951 };
9952
9953 if !filter.should_send_will_rename(&old_uri, is_dir) {
9954 continue;
9955 }
9956 let request_timeout = ProjectSettings::get_global(cx)
9957 .global_lsp_settings
9958 .get_request_timeout();
9959
9960 let apply_edit = cx.spawn({
9961 let old_uri = old_uri.clone();
9962 let new_uri = new_uri.clone();
9963 let language_server = language_server.clone();
9964 async move |this, cx| {
9965 let edit = language_server
9966 .request::<WillRenameFiles>(
9967 RenameFilesParams {
9968 files: vec![FileRename { old_uri, new_uri }],
9969 },
9970 request_timeout,
9971 )
9972 .await
9973 .into_response()
9974 .context("will rename files")
9975 .log_err()
9976 .flatten()?;
9977
9978 LocalLspStore::deserialize_workspace_edit(
9979 this.upgrade()?,
9980 edit,
9981 false,
9982 language_server.clone(),
9983 cx,
9984 )
9985 .await
9986 .ok()
9987 }
9988 });
9989 tasks.push(apply_edit);
9990 }
9991 Some(())
9992 })
9993 .ok()
9994 .flatten();
9995 let mut merged_transaction = ProjectTransaction::default();
9996 for task in tasks {
9997 // Await on tasks sequentially so that the order of application of edits is deterministic
9998 // (at least with regards to the order of registration of language servers)
9999 if let Some(transaction) = task.await {
10000 for (buffer, buffer_transaction) in transaction.0 {
10001 merged_transaction.0.insert(buffer, buffer_transaction);
10002 }
10003 }
10004 }
10005 merged_transaction
10006 })
10007 }
10008
10009 fn lsp_notify_abs_paths_changed(
10010 &mut self,
10011 server_id: LanguageServerId,
10012 changes: Vec<PathEvent>,
10013 ) {
10014 maybe!({
10015 let server = self.language_server_for_id(server_id)?;
10016 let changes = changes
10017 .into_iter()
10018 .filter_map(|event| {
10019 let typ = match event.kind? {
10020 PathEventKind::Created => lsp::FileChangeType::CREATED,
10021 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10022 PathEventKind::Changed | PathEventKind::Rescan => {
10023 lsp::FileChangeType::CHANGED
10024 }
10025 };
10026 Some(lsp::FileEvent {
10027 uri: file_path_to_lsp_url(&event.path).log_err()?,
10028 typ,
10029 })
10030 })
10031 .collect::<Vec<_>>();
10032 if !changes.is_empty() {
10033 server
10034 .notify::<lsp::notification::DidChangeWatchedFiles>(
10035 lsp::DidChangeWatchedFilesParams { changes },
10036 )
10037 .ok();
10038 }
10039 Some(())
10040 });
10041 }
10042
10043 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10044 self.as_local()?.language_server_for_id(id)
10045 }
10046
10047 fn on_lsp_progress(
10048 &mut self,
10049 progress_params: lsp::ProgressParams,
10050 language_server_id: LanguageServerId,
10051 disk_based_diagnostics_progress_token: Option<String>,
10052 cx: &mut Context<Self>,
10053 ) {
10054 match progress_params.value {
10055 lsp::ProgressParamsValue::WorkDone(progress) => {
10056 self.handle_work_done_progress(
10057 progress,
10058 language_server_id,
10059 disk_based_diagnostics_progress_token,
10060 ProgressToken::from_lsp(progress_params.token),
10061 cx,
10062 );
10063 }
10064 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10065 let registration_id = match progress_params.token {
10066 lsp::NumberOrString::Number(_) => None,
10067 lsp::NumberOrString::String(token) => token
10068 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10069 .map(|(_, id)| id.to_owned()),
10070 };
10071 if let Some(LanguageServerState::Running {
10072 workspace_diagnostics_refresh_tasks,
10073 ..
10074 }) = self
10075 .as_local_mut()
10076 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10077 && let Some(workspace_diagnostics) =
10078 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10079 {
10080 workspace_diagnostics.progress_tx.try_send(()).ok();
10081 self.apply_workspace_diagnostic_report(
10082 language_server_id,
10083 report,
10084 registration_id.map(SharedString::from),
10085 cx,
10086 )
10087 }
10088 }
10089 }
10090 }
10091
10092 fn handle_work_done_progress(
10093 &mut self,
10094 progress: lsp::WorkDoneProgress,
10095 language_server_id: LanguageServerId,
10096 disk_based_diagnostics_progress_token: Option<String>,
10097 token: ProgressToken,
10098 cx: &mut Context<Self>,
10099 ) {
10100 let language_server_status =
10101 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10102 status
10103 } else {
10104 return;
10105 };
10106
10107 if !language_server_status.progress_tokens.contains(&token) {
10108 return;
10109 }
10110
10111 let is_disk_based_diagnostics_progress =
10112 if let (Some(disk_based_token), ProgressToken::String(token)) =
10113 (&disk_based_diagnostics_progress_token, &token)
10114 {
10115 token.starts_with(disk_based_token)
10116 } else {
10117 false
10118 };
10119
10120 match progress {
10121 lsp::WorkDoneProgress::Begin(report) => {
10122 if is_disk_based_diagnostics_progress {
10123 self.disk_based_diagnostics_started(language_server_id, cx);
10124 }
10125 self.on_lsp_work_start(
10126 language_server_id,
10127 token.clone(),
10128 LanguageServerProgress {
10129 title: Some(report.title),
10130 is_disk_based_diagnostics_progress,
10131 is_cancellable: report.cancellable.unwrap_or(false),
10132 message: report.message.clone(),
10133 percentage: report.percentage.map(|p| p as usize),
10134 last_update_at: cx.background_executor().now(),
10135 },
10136 cx,
10137 );
10138 }
10139 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10140 language_server_id,
10141 token,
10142 LanguageServerProgress {
10143 title: None,
10144 is_disk_based_diagnostics_progress,
10145 is_cancellable: report.cancellable.unwrap_or(false),
10146 message: report.message,
10147 percentage: report.percentage.map(|p| p as usize),
10148 last_update_at: cx.background_executor().now(),
10149 },
10150 cx,
10151 ),
10152 lsp::WorkDoneProgress::End(_) => {
10153 language_server_status.progress_tokens.remove(&token);
10154 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10155 if is_disk_based_diagnostics_progress {
10156 self.disk_based_diagnostics_finished(language_server_id, cx);
10157 }
10158 }
10159 }
10160 }
10161
10162 fn on_lsp_work_start(
10163 &mut self,
10164 language_server_id: LanguageServerId,
10165 token: ProgressToken,
10166 progress: LanguageServerProgress,
10167 cx: &mut Context<Self>,
10168 ) {
10169 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10170 status.pending_work.insert(token.clone(), progress.clone());
10171 cx.notify();
10172 }
10173 cx.emit(LspStoreEvent::LanguageServerUpdate {
10174 language_server_id,
10175 name: self
10176 .language_server_adapter_for_id(language_server_id)
10177 .map(|adapter| adapter.name()),
10178 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10179 token: Some(token.to_proto()),
10180 title: progress.title,
10181 message: progress.message,
10182 percentage: progress.percentage.map(|p| p as u32),
10183 is_cancellable: Some(progress.is_cancellable),
10184 }),
10185 })
10186 }
10187
10188 fn on_lsp_work_progress(
10189 &mut self,
10190 language_server_id: LanguageServerId,
10191 token: ProgressToken,
10192 progress: LanguageServerProgress,
10193 cx: &mut Context<Self>,
10194 ) {
10195 let mut did_update = false;
10196 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10197 match status.pending_work.entry(token.clone()) {
10198 btree_map::Entry::Vacant(entry) => {
10199 entry.insert(progress.clone());
10200 did_update = true;
10201 }
10202 btree_map::Entry::Occupied(mut entry) => {
10203 let entry = entry.get_mut();
10204 if (progress.last_update_at - entry.last_update_at)
10205 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10206 {
10207 entry.last_update_at = progress.last_update_at;
10208 if progress.message.is_some() {
10209 entry.message = progress.message.clone();
10210 }
10211 if progress.percentage.is_some() {
10212 entry.percentage = progress.percentage;
10213 }
10214 if progress.is_cancellable != entry.is_cancellable {
10215 entry.is_cancellable = progress.is_cancellable;
10216 }
10217 did_update = true;
10218 }
10219 }
10220 }
10221 }
10222
10223 if did_update {
10224 cx.emit(LspStoreEvent::LanguageServerUpdate {
10225 language_server_id,
10226 name: self
10227 .language_server_adapter_for_id(language_server_id)
10228 .map(|adapter| adapter.name()),
10229 message: proto::update_language_server::Variant::WorkProgress(
10230 proto::LspWorkProgress {
10231 token: Some(token.to_proto()),
10232 message: progress.message,
10233 percentage: progress.percentage.map(|p| p as u32),
10234 is_cancellable: Some(progress.is_cancellable),
10235 },
10236 ),
10237 })
10238 }
10239 }
10240
10241 fn on_lsp_work_end(
10242 &mut self,
10243 language_server_id: LanguageServerId,
10244 token: ProgressToken,
10245 cx: &mut Context<Self>,
10246 ) {
10247 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10248 if let Some(work) = status.pending_work.remove(&token)
10249 && !work.is_disk_based_diagnostics_progress
10250 {
10251 cx.emit(LspStoreEvent::RefreshInlayHints {
10252 server_id: language_server_id,
10253 request_id: None,
10254 });
10255 }
10256 cx.notify();
10257 }
10258
10259 cx.emit(LspStoreEvent::LanguageServerUpdate {
10260 language_server_id,
10261 name: self
10262 .language_server_adapter_for_id(language_server_id)
10263 .map(|adapter| adapter.name()),
10264 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10265 token: Some(token.to_proto()),
10266 }),
10267 })
10268 }
10269
10270 pub async fn handle_resolve_completion_documentation(
10271 this: Entity<Self>,
10272 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10273 mut cx: AsyncApp,
10274 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10275 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10276
10277 let completion = this
10278 .read_with(&cx, |this, cx| {
10279 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10280 let server = this
10281 .language_server_for_id(id)
10282 .with_context(|| format!("No language server {id}"))?;
10283
10284 let request_timeout = ProjectSettings::get_global(cx)
10285 .global_lsp_settings
10286 .get_request_timeout();
10287
10288 anyhow::Ok(cx.background_spawn(async move {
10289 let can_resolve = server
10290 .capabilities()
10291 .completion_provider
10292 .as_ref()
10293 .and_then(|options| options.resolve_provider)
10294 .unwrap_or(false);
10295 if can_resolve {
10296 server
10297 .request::<lsp::request::ResolveCompletionItem>(
10298 lsp_completion,
10299 request_timeout,
10300 )
10301 .await
10302 .into_response()
10303 .context("resolve completion item")
10304 } else {
10305 anyhow::Ok(lsp_completion)
10306 }
10307 }))
10308 })?
10309 .await?;
10310
10311 let mut documentation_is_markdown = false;
10312 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10313 let documentation = match completion.documentation {
10314 Some(lsp::Documentation::String(text)) => text,
10315
10316 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10317 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10318 value
10319 }
10320
10321 _ => String::new(),
10322 };
10323
10324 // If we have a new buffer_id, that means we're talking to a new client
10325 // and want to check for new text_edits in the completion too.
10326 let mut old_replace_start = None;
10327 let mut old_replace_end = None;
10328 let mut old_insert_start = None;
10329 let mut old_insert_end = None;
10330 let mut new_text = String::default();
10331 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10332 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10333 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10334 anyhow::Ok(buffer.read(cx).snapshot())
10335 })?;
10336
10337 if let Some(text_edit) = completion.text_edit.as_ref() {
10338 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10339
10340 if let Some(mut edit) = edit {
10341 LineEnding::normalize(&mut edit.new_text);
10342
10343 new_text = edit.new_text;
10344 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10345 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10346 if let Some(insert_range) = edit.insert_range {
10347 old_insert_start = Some(serialize_anchor(&insert_range.start));
10348 old_insert_end = Some(serialize_anchor(&insert_range.end));
10349 }
10350 }
10351 }
10352 }
10353
10354 Ok(proto::ResolveCompletionDocumentationResponse {
10355 documentation,
10356 documentation_is_markdown,
10357 old_replace_start,
10358 old_replace_end,
10359 new_text,
10360 lsp_completion,
10361 old_insert_start,
10362 old_insert_end,
10363 })
10364 }
10365
10366 async fn handle_on_type_formatting(
10367 this: Entity<Self>,
10368 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10369 mut cx: AsyncApp,
10370 ) -> Result<proto::OnTypeFormattingResponse> {
10371 let on_type_formatting = this.update(&mut cx, |this, cx| {
10372 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10373 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10374 let position = envelope
10375 .payload
10376 .position
10377 .and_then(deserialize_anchor)
10378 .context("invalid position")?;
10379 anyhow::Ok(this.apply_on_type_formatting(
10380 buffer,
10381 position,
10382 envelope.payload.trigger.clone(),
10383 cx,
10384 ))
10385 })?;
10386
10387 let transaction = on_type_formatting
10388 .await?
10389 .as_ref()
10390 .map(language::proto::serialize_transaction);
10391 Ok(proto::OnTypeFormattingResponse { transaction })
10392 }
10393
10394 async fn handle_pull_workspace_diagnostics(
10395 lsp_store: Entity<Self>,
10396 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10397 mut cx: AsyncApp,
10398 ) -> Result<proto::Ack> {
10399 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10400 lsp_store.update(&mut cx, |lsp_store, _| {
10401 lsp_store.pull_workspace_diagnostics(server_id);
10402 });
10403 Ok(proto::Ack {})
10404 }
10405
10406 async fn handle_open_buffer_for_symbol(
10407 this: Entity<Self>,
10408 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10409 mut cx: AsyncApp,
10410 ) -> Result<proto::OpenBufferForSymbolResponse> {
10411 let peer_id = envelope.original_sender_id().unwrap_or_default();
10412 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10413 let symbol = Self::deserialize_symbol(symbol)?;
10414 this.read_with(&cx, |this, _| {
10415 if let SymbolLocation::OutsideProject {
10416 abs_path,
10417 signature,
10418 } = &symbol.path
10419 {
10420 let new_signature = this.symbol_signature(&abs_path);
10421 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10422 }
10423 Ok(())
10424 })?;
10425 let buffer = this
10426 .update(&mut cx, |this, cx| {
10427 this.open_buffer_for_symbol(
10428 &Symbol {
10429 language_server_name: symbol.language_server_name,
10430 source_worktree_id: symbol.source_worktree_id,
10431 source_language_server_id: symbol.source_language_server_id,
10432 path: symbol.path,
10433 name: symbol.name,
10434 kind: symbol.kind,
10435 range: symbol.range,
10436 label: CodeLabel::default(),
10437 container_name: symbol.container_name,
10438 },
10439 cx,
10440 )
10441 })
10442 .await?;
10443
10444 this.update(&mut cx, |this, cx| {
10445 let is_private = buffer
10446 .read(cx)
10447 .file()
10448 .map(|f| f.is_private())
10449 .unwrap_or_default();
10450 if is_private {
10451 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10452 } else {
10453 this.buffer_store
10454 .update(cx, |buffer_store, cx| {
10455 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10456 })
10457 .detach_and_log_err(cx);
10458 let buffer_id = buffer.read(cx).remote_id().to_proto();
10459 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10460 }
10461 })
10462 }
10463
10464 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10465 let mut hasher = Sha256::new();
10466 hasher.update(abs_path.to_string_lossy().as_bytes());
10467 hasher.update(self.nonce.to_be_bytes());
10468 hasher.finalize().as_slice().try_into().unwrap()
10469 }
10470
10471 pub async fn handle_get_project_symbols(
10472 this: Entity<Self>,
10473 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10474 mut cx: AsyncApp,
10475 ) -> Result<proto::GetProjectSymbolsResponse> {
10476 let symbols = this
10477 .update(&mut cx, |this, cx| {
10478 this.symbols(&envelope.payload.query, cx)
10479 })
10480 .await?;
10481
10482 Ok(proto::GetProjectSymbolsResponse {
10483 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10484 })
10485 }
10486
10487 pub async fn handle_restart_language_servers(
10488 this: Entity<Self>,
10489 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10490 mut cx: AsyncApp,
10491 ) -> Result<proto::Ack> {
10492 this.update(&mut cx, |lsp_store, cx| {
10493 let buffers =
10494 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10495 lsp_store.restart_language_servers_for_buffers(
10496 buffers,
10497 envelope
10498 .payload
10499 .only_servers
10500 .into_iter()
10501 .filter_map(|selector| {
10502 Some(match selector.selector? {
10503 proto::language_server_selector::Selector::ServerId(server_id) => {
10504 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10505 }
10506 proto::language_server_selector::Selector::Name(name) => {
10507 LanguageServerSelector::Name(LanguageServerName(
10508 SharedString::from(name),
10509 ))
10510 }
10511 })
10512 })
10513 .collect(),
10514 cx,
10515 );
10516 });
10517
10518 Ok(proto::Ack {})
10519 }
10520
10521 pub async fn handle_stop_language_servers(
10522 lsp_store: Entity<Self>,
10523 envelope: TypedEnvelope<proto::StopLanguageServers>,
10524 mut cx: AsyncApp,
10525 ) -> Result<proto::Ack> {
10526 lsp_store.update(&mut cx, |lsp_store, cx| {
10527 if envelope.payload.all
10528 && envelope.payload.also_servers.is_empty()
10529 && envelope.payload.buffer_ids.is_empty()
10530 {
10531 lsp_store.stop_all_language_servers(cx);
10532 } else {
10533 let buffers =
10534 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10535 lsp_store
10536 .stop_language_servers_for_buffers(
10537 buffers,
10538 envelope
10539 .payload
10540 .also_servers
10541 .into_iter()
10542 .filter_map(|selector| {
10543 Some(match selector.selector? {
10544 proto::language_server_selector::Selector::ServerId(
10545 server_id,
10546 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10547 server_id,
10548 )),
10549 proto::language_server_selector::Selector::Name(name) => {
10550 LanguageServerSelector::Name(LanguageServerName(
10551 SharedString::from(name),
10552 ))
10553 }
10554 })
10555 })
10556 .collect(),
10557 cx,
10558 )
10559 .detach_and_log_err(cx);
10560 }
10561 });
10562
10563 Ok(proto::Ack {})
10564 }
10565
10566 pub async fn handle_cancel_language_server_work(
10567 lsp_store: Entity<Self>,
10568 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10569 mut cx: AsyncApp,
10570 ) -> Result<proto::Ack> {
10571 lsp_store.update(&mut cx, |lsp_store, cx| {
10572 if let Some(work) = envelope.payload.work {
10573 match work {
10574 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10575 let buffers =
10576 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10577 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10578 }
10579 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10580 let server_id = LanguageServerId::from_proto(work.language_server_id);
10581 let token = work
10582 .token
10583 .map(|token| {
10584 ProgressToken::from_proto(token)
10585 .context("invalid work progress token")
10586 })
10587 .transpose()?;
10588 lsp_store.cancel_language_server_work(server_id, token, cx);
10589 }
10590 }
10591 }
10592 anyhow::Ok(())
10593 })?;
10594
10595 Ok(proto::Ack {})
10596 }
10597
10598 fn buffer_ids_to_buffers(
10599 &mut self,
10600 buffer_ids: impl Iterator<Item = u64>,
10601 cx: &mut Context<Self>,
10602 ) -> Vec<Entity<Buffer>> {
10603 buffer_ids
10604 .into_iter()
10605 .flat_map(|buffer_id| {
10606 self.buffer_store
10607 .read(cx)
10608 .get(BufferId::new(buffer_id).log_err()?)
10609 })
10610 .collect::<Vec<_>>()
10611 }
10612
10613 async fn handle_apply_additional_edits_for_completion(
10614 this: Entity<Self>,
10615 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10616 mut cx: AsyncApp,
10617 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10618 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10619 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10620 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10621 let completion = Self::deserialize_completion(
10622 envelope.payload.completion.context("invalid completion")?,
10623 )?;
10624 let all_commit_ranges = envelope
10625 .payload
10626 .all_commit_ranges
10627 .into_iter()
10628 .map(language::proto::deserialize_anchor_range)
10629 .collect::<Result<Vec<_>, _>>()?;
10630 anyhow::Ok((buffer, completion, all_commit_ranges))
10631 })?;
10632
10633 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10634 this.apply_additional_edits_for_completion(
10635 buffer,
10636 Rc::new(RefCell::new(Box::new([Completion {
10637 replace_range: completion.replace_range,
10638 new_text: completion.new_text,
10639 source: completion.source,
10640 documentation: None,
10641 label: CodeLabel::default(),
10642 match_start: None,
10643 snippet_deduplication_key: None,
10644 insert_text_mode: None,
10645 icon_path: None,
10646 confirm: None,
10647 }]))),
10648 0,
10649 false,
10650 all_commit_ranges,
10651 cx,
10652 )
10653 });
10654
10655 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10656 transaction: apply_additional_edits
10657 .await?
10658 .as_ref()
10659 .map(language::proto::serialize_transaction),
10660 })
10661 }
10662
10663 pub fn last_formatting_failure(&self) -> Option<&str> {
10664 self.last_formatting_failure.as_deref()
10665 }
10666
10667 pub fn reset_last_formatting_failure(&mut self) {
10668 self.last_formatting_failure = None;
10669 }
10670
10671 pub fn environment_for_buffer(
10672 &self,
10673 buffer: &Entity<Buffer>,
10674 cx: &mut Context<Self>,
10675 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10676 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10677 environment.update(cx, |env, cx| {
10678 env.buffer_environment(buffer, &self.worktree_store, cx)
10679 })
10680 } else {
10681 Task::ready(None).shared()
10682 }
10683 }
10684
10685 pub fn format(
10686 &mut self,
10687 buffers: HashSet<Entity<Buffer>>,
10688 target: LspFormatTarget,
10689 push_to_history: bool,
10690 trigger: FormatTrigger,
10691 cx: &mut Context<Self>,
10692 ) -> Task<anyhow::Result<ProjectTransaction>> {
10693 let logger = zlog::scoped!("format");
10694 if self.as_local().is_some() {
10695 zlog::trace!(logger => "Formatting locally");
10696 let logger = zlog::scoped!(logger => "local");
10697 let buffers = buffers
10698 .into_iter()
10699 .map(|buffer_handle| {
10700 let buffer = buffer_handle.read(cx);
10701 let buffer_abs_path = File::from_dyn(buffer.file())
10702 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10703
10704 (buffer_handle, buffer_abs_path, buffer.remote_id())
10705 })
10706 .collect::<Vec<_>>();
10707
10708 cx.spawn(async move |lsp_store, cx| {
10709 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10710
10711 for (handle, abs_path, id) in buffers {
10712 let env = lsp_store
10713 .update(cx, |lsp_store, cx| {
10714 lsp_store.environment_for_buffer(&handle, cx)
10715 })?
10716 .await;
10717
10718 let ranges = match &target {
10719 LspFormatTarget::Buffers => None,
10720 LspFormatTarget::Ranges(ranges) => {
10721 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10722 }
10723 };
10724
10725 formattable_buffers.push(FormattableBuffer {
10726 handle,
10727 abs_path,
10728 env,
10729 ranges,
10730 });
10731 }
10732 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10733
10734 let format_timer = zlog::time!(logger => "Formatting buffers");
10735 let result = LocalLspStore::format_locally(
10736 lsp_store.clone(),
10737 formattable_buffers,
10738 push_to_history,
10739 trigger,
10740 logger,
10741 cx,
10742 )
10743 .await;
10744 format_timer.end();
10745
10746 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10747
10748 lsp_store.update(cx, |lsp_store, _| {
10749 lsp_store.update_last_formatting_failure(&result);
10750 })?;
10751
10752 result
10753 })
10754 } else if let Some((client, project_id)) = self.upstream_client() {
10755 zlog::trace!(logger => "Formatting remotely");
10756 let logger = zlog::scoped!(logger => "remote");
10757
10758 let buffer_ranges = match &target {
10759 LspFormatTarget::Buffers => Vec::new(),
10760 LspFormatTarget::Ranges(ranges) => ranges
10761 .iter()
10762 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10763 buffer_id: buffer_id.to_proto(),
10764 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10765 })
10766 .collect(),
10767 };
10768
10769 let buffer_store = self.buffer_store();
10770 cx.spawn(async move |lsp_store, cx| {
10771 zlog::trace!(logger => "Sending remote format request");
10772 let request_timer = zlog::time!(logger => "remote format request");
10773 let result = client
10774 .request(proto::FormatBuffers {
10775 project_id,
10776 trigger: trigger as i32,
10777 buffer_ids: buffers
10778 .iter()
10779 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10780 .collect(),
10781 buffer_ranges,
10782 })
10783 .await
10784 .and_then(|result| result.transaction.context("missing transaction"));
10785 request_timer.end();
10786
10787 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10788
10789 lsp_store.update(cx, |lsp_store, _| {
10790 lsp_store.update_last_formatting_failure(&result);
10791 })?;
10792
10793 let transaction_response = result?;
10794 let _timer = zlog::time!(logger => "deserializing project transaction");
10795 buffer_store
10796 .update(cx, |buffer_store, cx| {
10797 buffer_store.deserialize_project_transaction(
10798 transaction_response,
10799 push_to_history,
10800 cx,
10801 )
10802 })
10803 .await
10804 })
10805 } else {
10806 zlog::trace!(logger => "Not formatting");
10807 Task::ready(Ok(ProjectTransaction::default()))
10808 }
10809 }
10810
10811 async fn handle_format_buffers(
10812 this: Entity<Self>,
10813 envelope: TypedEnvelope<proto::FormatBuffers>,
10814 mut cx: AsyncApp,
10815 ) -> Result<proto::FormatBuffersResponse> {
10816 let sender_id = envelope.original_sender_id().unwrap_or_default();
10817 let format = this.update(&mut cx, |this, cx| {
10818 let mut buffers = HashSet::default();
10819 for buffer_id in &envelope.payload.buffer_ids {
10820 let buffer_id = BufferId::new(*buffer_id)?;
10821 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10822 }
10823
10824 let target = if envelope.payload.buffer_ranges.is_empty() {
10825 LspFormatTarget::Buffers
10826 } else {
10827 let mut ranges_map = BTreeMap::new();
10828 for buffer_range in &envelope.payload.buffer_ranges {
10829 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10830 let ranges: Result<Vec<_>> = buffer_range
10831 .ranges
10832 .iter()
10833 .map(|range| {
10834 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10835 })
10836 .collect();
10837 ranges_map.insert(buffer_id, ranges?);
10838 }
10839 LspFormatTarget::Ranges(ranges_map)
10840 };
10841
10842 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10843 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10844 })?;
10845
10846 let project_transaction = format.await?;
10847 let project_transaction = this.update(&mut cx, |this, cx| {
10848 this.buffer_store.update(cx, |buffer_store, cx| {
10849 buffer_store.serialize_project_transaction_for_peer(
10850 project_transaction,
10851 sender_id,
10852 cx,
10853 )
10854 })
10855 });
10856 Ok(proto::FormatBuffersResponse {
10857 transaction: Some(project_transaction),
10858 })
10859 }
10860
10861 async fn handle_apply_code_action_kind(
10862 this: Entity<Self>,
10863 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10864 mut cx: AsyncApp,
10865 ) -> Result<proto::ApplyCodeActionKindResponse> {
10866 let sender_id = envelope.original_sender_id().unwrap_or_default();
10867 let format = this.update(&mut cx, |this, cx| {
10868 let mut buffers = HashSet::default();
10869 for buffer_id in &envelope.payload.buffer_ids {
10870 let buffer_id = BufferId::new(*buffer_id)?;
10871 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10872 }
10873 let kind = match envelope.payload.kind.as_str() {
10874 "" => CodeActionKind::EMPTY,
10875 "quickfix" => CodeActionKind::QUICKFIX,
10876 "refactor" => CodeActionKind::REFACTOR,
10877 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10878 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10879 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10880 "source" => CodeActionKind::SOURCE,
10881 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10882 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10883 _ => anyhow::bail!(
10884 "Invalid code action kind {}",
10885 envelope.payload.kind.as_str()
10886 ),
10887 };
10888 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10889 })?;
10890
10891 let project_transaction = format.await?;
10892 let project_transaction = this.update(&mut cx, |this, cx| {
10893 this.buffer_store.update(cx, |buffer_store, cx| {
10894 buffer_store.serialize_project_transaction_for_peer(
10895 project_transaction,
10896 sender_id,
10897 cx,
10898 )
10899 })
10900 });
10901 Ok(proto::ApplyCodeActionKindResponse {
10902 transaction: Some(project_transaction),
10903 })
10904 }
10905
10906 async fn shutdown_language_server(
10907 server_state: Option<LanguageServerState>,
10908 name: LanguageServerName,
10909 cx: &mut AsyncApp,
10910 ) {
10911 let server = match server_state {
10912 Some(LanguageServerState::Starting { startup, .. }) => {
10913 let mut timer = cx
10914 .background_executor()
10915 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10916 .fuse();
10917
10918 select! {
10919 server = startup.fuse() => server,
10920 () = timer => {
10921 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10922 None
10923 },
10924 }
10925 }
10926
10927 Some(LanguageServerState::Running { server, .. }) => Some(server),
10928
10929 None => None,
10930 };
10931
10932 let Some(server) = server else { return };
10933 if let Some(shutdown) = server.shutdown() {
10934 shutdown.await;
10935 }
10936 }
10937
10938 // Returns a list of all of the worktrees which no longer have a language server and the root path
10939 // for the stopped server
10940 fn stop_local_language_server(
10941 &mut self,
10942 server_id: LanguageServerId,
10943 cx: &mut Context<Self>,
10944 ) -> Task<()> {
10945 let local = match &mut self.mode {
10946 LspStoreMode::Local(local) => local,
10947 _ => {
10948 return Task::ready(());
10949 }
10950 };
10951
10952 // Remove this server ID from all entries in the given worktree.
10953 local
10954 .language_server_ids
10955 .retain(|_, state| state.id != server_id);
10956 self.buffer_store.update(cx, |buffer_store, cx| {
10957 for buffer in buffer_store.buffers() {
10958 buffer.update(cx, |buffer, cx| {
10959 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10960 buffer.set_completion_triggers(server_id, Default::default(), cx);
10961 });
10962 }
10963 });
10964
10965 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10966 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10967 summaries.retain(|path, summaries_by_server_id| {
10968 if summaries_by_server_id.remove(&server_id).is_some() {
10969 if let Some((client, project_id)) = self.downstream_client.clone() {
10970 client
10971 .send(proto::UpdateDiagnosticSummary {
10972 project_id,
10973 worktree_id: worktree_id.to_proto(),
10974 summary: Some(proto::DiagnosticSummary {
10975 path: path.as_ref().to_proto(),
10976 language_server_id: server_id.0 as u64,
10977 error_count: 0,
10978 warning_count: 0,
10979 }),
10980 more_summaries: Vec::new(),
10981 })
10982 .log_err();
10983 }
10984 cleared_paths.push(ProjectPath {
10985 worktree_id: *worktree_id,
10986 path: path.clone(),
10987 });
10988 !summaries_by_server_id.is_empty()
10989 } else {
10990 true
10991 }
10992 });
10993 }
10994 if !cleared_paths.is_empty() {
10995 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10996 server_id,
10997 paths: cleared_paths,
10998 });
10999 }
11000
11001 let local = self.as_local_mut().unwrap();
11002 for diagnostics in local.diagnostics.values_mut() {
11003 diagnostics.retain(|_, diagnostics_by_server_id| {
11004 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11005 diagnostics_by_server_id.remove(ix);
11006 !diagnostics_by_server_id.is_empty()
11007 } else {
11008 true
11009 }
11010 });
11011 }
11012 local.language_server_watched_paths.remove(&server_id);
11013
11014 let server_state = local.language_servers.remove(&server_id);
11015 self.cleanup_lsp_data(server_id);
11016 let name = self
11017 .language_server_statuses
11018 .remove(&server_id)
11019 .map(|status| status.name)
11020 .or_else(|| {
11021 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11022 Some(adapter.name())
11023 } else {
11024 None
11025 }
11026 });
11027
11028 if let Some(name) = name {
11029 log::info!("stopping language server {name}");
11030 self.languages
11031 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11032 cx.notify();
11033
11034 return cx.spawn(async move |lsp_store, cx| {
11035 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11036 lsp_store
11037 .update(cx, |lsp_store, cx| {
11038 lsp_store
11039 .languages
11040 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11041 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11042 cx.notify();
11043 })
11044 .ok();
11045 });
11046 }
11047
11048 if server_state.is_some() {
11049 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11050 }
11051 Task::ready(())
11052 }
11053
11054 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11055 self.shutdown_all_language_servers(cx).detach();
11056 }
11057
11058 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11059 if let Some((client, project_id)) = self.upstream_client() {
11060 let request = client.request(proto::StopLanguageServers {
11061 project_id,
11062 buffer_ids: Vec::new(),
11063 also_servers: Vec::new(),
11064 all: true,
11065 });
11066 cx.background_spawn(async move {
11067 request.await.ok();
11068 })
11069 } else {
11070 let Some(local) = self.as_local_mut() else {
11071 return Task::ready(());
11072 };
11073 let language_servers_to_stop = local
11074 .language_server_ids
11075 .values()
11076 .map(|state| state.id)
11077 .collect();
11078 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11079 let tasks = language_servers_to_stop
11080 .into_iter()
11081 .map(|server| self.stop_local_language_server(server, cx))
11082 .collect::<Vec<_>>();
11083 cx.background_spawn(async move {
11084 futures::future::join_all(tasks).await;
11085 })
11086 }
11087 }
11088
11089 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11090 let buffers = self.buffer_store.read(cx).buffers().collect();
11091 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11092 }
11093
11094 pub fn restart_language_servers_for_buffers(
11095 &mut self,
11096 buffers: Vec<Entity<Buffer>>,
11097 only_restart_servers: HashSet<LanguageServerSelector>,
11098 cx: &mut Context<Self>,
11099 ) {
11100 if let Some((client, project_id)) = self.upstream_client() {
11101 let request = client.request(proto::RestartLanguageServers {
11102 project_id,
11103 buffer_ids: buffers
11104 .into_iter()
11105 .map(|b| b.read(cx).remote_id().to_proto())
11106 .collect(),
11107 only_servers: only_restart_servers
11108 .into_iter()
11109 .map(|selector| {
11110 let selector = match selector {
11111 LanguageServerSelector::Id(language_server_id) => {
11112 proto::language_server_selector::Selector::ServerId(
11113 language_server_id.to_proto(),
11114 )
11115 }
11116 LanguageServerSelector::Name(language_server_name) => {
11117 proto::language_server_selector::Selector::Name(
11118 language_server_name.to_string(),
11119 )
11120 }
11121 };
11122 proto::LanguageServerSelector {
11123 selector: Some(selector),
11124 }
11125 })
11126 .collect(),
11127 all: false,
11128 });
11129 cx.background_spawn(request).detach_and_log_err(cx);
11130 } else {
11131 let stop_task = if only_restart_servers.is_empty() {
11132 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11133 } else {
11134 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11135 };
11136 cx.spawn(async move |lsp_store, cx| {
11137 stop_task.await;
11138 lsp_store.update(cx, |lsp_store, cx| {
11139 for buffer in buffers {
11140 lsp_store.register_buffer_with_language_servers(
11141 &buffer,
11142 only_restart_servers.clone(),
11143 true,
11144 cx,
11145 );
11146 }
11147 })
11148 })
11149 .detach();
11150 }
11151 }
11152
11153 pub fn stop_language_servers_for_buffers(
11154 &mut self,
11155 buffers: Vec<Entity<Buffer>>,
11156 also_stop_servers: HashSet<LanguageServerSelector>,
11157 cx: &mut Context<Self>,
11158 ) -> Task<Result<()>> {
11159 if let Some((client, project_id)) = self.upstream_client() {
11160 let request = client.request(proto::StopLanguageServers {
11161 project_id,
11162 buffer_ids: buffers
11163 .into_iter()
11164 .map(|b| b.read(cx).remote_id().to_proto())
11165 .collect(),
11166 also_servers: also_stop_servers
11167 .into_iter()
11168 .map(|selector| {
11169 let selector = match selector {
11170 LanguageServerSelector::Id(language_server_id) => {
11171 proto::language_server_selector::Selector::ServerId(
11172 language_server_id.to_proto(),
11173 )
11174 }
11175 LanguageServerSelector::Name(language_server_name) => {
11176 proto::language_server_selector::Selector::Name(
11177 language_server_name.to_string(),
11178 )
11179 }
11180 };
11181 proto::LanguageServerSelector {
11182 selector: Some(selector),
11183 }
11184 })
11185 .collect(),
11186 all: false,
11187 });
11188 cx.background_spawn(async move {
11189 let _ = request.await?;
11190 Ok(())
11191 })
11192 } else {
11193 let task =
11194 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11195 cx.background_spawn(async move {
11196 task.await;
11197 Ok(())
11198 })
11199 }
11200 }
11201
11202 fn stop_local_language_servers_for_buffers(
11203 &mut self,
11204 buffers: &[Entity<Buffer>],
11205 also_stop_servers: HashSet<LanguageServerSelector>,
11206 cx: &mut Context<Self>,
11207 ) -> Task<()> {
11208 let Some(local) = self.as_local_mut() else {
11209 return Task::ready(());
11210 };
11211 let mut language_server_names_to_stop = BTreeSet::default();
11212 let mut language_servers_to_stop = also_stop_servers
11213 .into_iter()
11214 .flat_map(|selector| match selector {
11215 LanguageServerSelector::Id(id) => Some(id),
11216 LanguageServerSelector::Name(name) => {
11217 language_server_names_to_stop.insert(name);
11218 None
11219 }
11220 })
11221 .collect::<BTreeSet<_>>();
11222
11223 let mut covered_worktrees = HashSet::default();
11224 for buffer in buffers {
11225 buffer.update(cx, |buffer, cx| {
11226 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11227 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11228 && covered_worktrees.insert(worktree_id)
11229 {
11230 language_server_names_to_stop.retain(|name| {
11231 let old_ids_count = language_servers_to_stop.len();
11232 let all_language_servers_with_this_name = local
11233 .language_server_ids
11234 .iter()
11235 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11236 language_servers_to_stop.extend(all_language_servers_with_this_name);
11237 old_ids_count == language_servers_to_stop.len()
11238 });
11239 }
11240 });
11241 }
11242 for name in language_server_names_to_stop {
11243 language_servers_to_stop.extend(
11244 local
11245 .language_server_ids
11246 .iter()
11247 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11248 );
11249 }
11250
11251 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11252 let tasks = language_servers_to_stop
11253 .into_iter()
11254 .map(|server| self.stop_local_language_server(server, cx))
11255 .collect::<Vec<_>>();
11256
11257 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11258 }
11259
11260 #[cfg(any(test, feature = "test-support"))]
11261 pub fn update_diagnostics(
11262 &mut self,
11263 server_id: LanguageServerId,
11264 diagnostics: lsp::PublishDiagnosticsParams,
11265 result_id: Option<SharedString>,
11266 source_kind: DiagnosticSourceKind,
11267 disk_based_sources: &[String],
11268 cx: &mut Context<Self>,
11269 ) -> Result<()> {
11270 self.merge_lsp_diagnostics(
11271 source_kind,
11272 vec![DocumentDiagnosticsUpdate {
11273 diagnostics,
11274 result_id,
11275 server_id,
11276 disk_based_sources: Cow::Borrowed(disk_based_sources),
11277 registration_id: None,
11278 }],
11279 |_, _, _| false,
11280 cx,
11281 )
11282 }
11283
11284 pub fn merge_lsp_diagnostics(
11285 &mut self,
11286 source_kind: DiagnosticSourceKind,
11287 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11288 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11289 cx: &mut Context<Self>,
11290 ) -> Result<()> {
11291 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11292 let updates = lsp_diagnostics
11293 .into_iter()
11294 .filter_map(|update| {
11295 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11296 Some(DocumentDiagnosticsUpdate {
11297 diagnostics: self.lsp_to_document_diagnostics(
11298 abs_path,
11299 source_kind,
11300 update.server_id,
11301 update.diagnostics,
11302 &update.disk_based_sources,
11303 update.registration_id.clone(),
11304 ),
11305 result_id: update.result_id,
11306 server_id: update.server_id,
11307 disk_based_sources: update.disk_based_sources,
11308 registration_id: update.registration_id,
11309 })
11310 })
11311 .collect();
11312 self.merge_diagnostic_entries(updates, merge, cx)?;
11313 Ok(())
11314 }
11315
11316 fn lsp_to_document_diagnostics(
11317 &mut self,
11318 document_abs_path: PathBuf,
11319 source_kind: DiagnosticSourceKind,
11320 server_id: LanguageServerId,
11321 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11322 disk_based_sources: &[String],
11323 registration_id: Option<SharedString>,
11324 ) -> DocumentDiagnostics {
11325 let mut diagnostics = Vec::default();
11326 let mut primary_diagnostic_group_ids = HashMap::default();
11327 let mut sources_by_group_id = HashMap::default();
11328 let mut supporting_diagnostics = HashMap::default();
11329
11330 let adapter = self.language_server_adapter_for_id(server_id);
11331
11332 // Ensure that primary diagnostics are always the most severe
11333 lsp_diagnostics
11334 .diagnostics
11335 .sort_by_key(|item| item.severity);
11336
11337 for diagnostic in &lsp_diagnostics.diagnostics {
11338 let source = diagnostic.source.as_ref();
11339 let range = range_from_lsp(diagnostic.range);
11340 let is_supporting = diagnostic
11341 .related_information
11342 .as_ref()
11343 .is_some_and(|infos| {
11344 infos.iter().any(|info| {
11345 primary_diagnostic_group_ids.contains_key(&(
11346 source,
11347 diagnostic.code.clone(),
11348 range_from_lsp(info.location.range),
11349 ))
11350 })
11351 });
11352
11353 let is_unnecessary = diagnostic
11354 .tags
11355 .as_ref()
11356 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11357
11358 let underline = self
11359 .language_server_adapter_for_id(server_id)
11360 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11361
11362 if is_supporting {
11363 supporting_diagnostics.insert(
11364 (source, diagnostic.code.clone(), range),
11365 (diagnostic.severity, is_unnecessary),
11366 );
11367 } else {
11368 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11369 let is_disk_based =
11370 source.is_some_and(|source| disk_based_sources.contains(source));
11371
11372 sources_by_group_id.insert(group_id, source);
11373 primary_diagnostic_group_ids
11374 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11375
11376 diagnostics.push(DiagnosticEntry {
11377 range,
11378 diagnostic: Diagnostic {
11379 source: diagnostic.source.clone(),
11380 source_kind,
11381 code: diagnostic.code.clone(),
11382 code_description: diagnostic
11383 .code_description
11384 .as_ref()
11385 .and_then(|d| d.href.clone()),
11386 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11387 markdown: adapter.as_ref().and_then(|adapter| {
11388 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11389 }),
11390 message: diagnostic.message.trim().to_string(),
11391 group_id,
11392 is_primary: true,
11393 is_disk_based,
11394 is_unnecessary,
11395 underline,
11396 data: diagnostic.data.clone(),
11397 registration_id: registration_id.clone(),
11398 },
11399 });
11400 if let Some(infos) = &diagnostic.related_information {
11401 for info in infos {
11402 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11403 let range = range_from_lsp(info.location.range);
11404 diagnostics.push(DiagnosticEntry {
11405 range,
11406 diagnostic: Diagnostic {
11407 source: diagnostic.source.clone(),
11408 source_kind,
11409 code: diagnostic.code.clone(),
11410 code_description: diagnostic
11411 .code_description
11412 .as_ref()
11413 .and_then(|d| d.href.clone()),
11414 severity: DiagnosticSeverity::INFORMATION,
11415 markdown: adapter.as_ref().and_then(|adapter| {
11416 adapter.diagnostic_message_to_markdown(&info.message)
11417 }),
11418 message: info.message.trim().to_string(),
11419 group_id,
11420 is_primary: false,
11421 is_disk_based,
11422 is_unnecessary: false,
11423 underline,
11424 data: diagnostic.data.clone(),
11425 registration_id: registration_id.clone(),
11426 },
11427 });
11428 }
11429 }
11430 }
11431 }
11432 }
11433
11434 for entry in &mut diagnostics {
11435 let diagnostic = &mut entry.diagnostic;
11436 if !diagnostic.is_primary {
11437 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11438 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11439 source,
11440 diagnostic.code.clone(),
11441 entry.range.clone(),
11442 )) {
11443 if let Some(severity) = severity {
11444 diagnostic.severity = severity;
11445 }
11446 diagnostic.is_unnecessary = is_unnecessary;
11447 }
11448 }
11449 }
11450
11451 DocumentDiagnostics {
11452 diagnostics,
11453 document_abs_path,
11454 version: lsp_diagnostics.version,
11455 }
11456 }
11457
11458 fn insert_newly_running_language_server(
11459 &mut self,
11460 adapter: Arc<CachedLspAdapter>,
11461 language_server: Arc<LanguageServer>,
11462 server_id: LanguageServerId,
11463 key: LanguageServerSeed,
11464 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11465 cx: &mut Context<Self>,
11466 ) {
11467 let Some(local) = self.as_local_mut() else {
11468 return;
11469 };
11470 // If the language server for this key doesn't match the server id, don't store the
11471 // server. Which will cause it to be dropped, killing the process
11472 if local
11473 .language_server_ids
11474 .get(&key)
11475 .map(|state| state.id != server_id)
11476 .unwrap_or(false)
11477 {
11478 return;
11479 }
11480
11481 // Update language_servers collection with Running variant of LanguageServerState
11482 // indicating that the server is up and running and ready
11483 let workspace_folders = workspace_folders.lock().clone();
11484 language_server.set_workspace_folders(workspace_folders);
11485
11486 let workspace_diagnostics_refresh_tasks = language_server
11487 .capabilities()
11488 .diagnostic_provider
11489 .and_then(|provider| {
11490 local
11491 .language_server_dynamic_registrations
11492 .entry(server_id)
11493 .or_default()
11494 .diagnostics
11495 .entry(None)
11496 .or_insert(provider.clone());
11497 let workspace_refresher =
11498 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11499
11500 Some((None, workspace_refresher))
11501 })
11502 .into_iter()
11503 .collect();
11504 local.language_servers.insert(
11505 server_id,
11506 LanguageServerState::Running {
11507 workspace_diagnostics_refresh_tasks,
11508 adapter: adapter.clone(),
11509 server: language_server.clone(),
11510 simulate_disk_based_diagnostics_completion: None,
11511 },
11512 );
11513 local
11514 .languages
11515 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11516 if let Some(file_ops_caps) = language_server
11517 .capabilities()
11518 .workspace
11519 .as_ref()
11520 .and_then(|ws| ws.file_operations.as_ref())
11521 {
11522 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11523 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11524 if did_rename_caps.or(will_rename_caps).is_some() {
11525 let watcher = RenamePathsWatchedForServer::default()
11526 .with_did_rename_patterns(did_rename_caps)
11527 .with_will_rename_patterns(will_rename_caps);
11528 local
11529 .language_server_paths_watched_for_rename
11530 .insert(server_id, watcher);
11531 }
11532 }
11533
11534 self.language_server_statuses.insert(
11535 server_id,
11536 LanguageServerStatus {
11537 name: language_server.name(),
11538 server_version: language_server.version(),
11539 server_readable_version: language_server.readable_version(),
11540 pending_work: Default::default(),
11541 has_pending_diagnostic_updates: false,
11542 progress_tokens: Default::default(),
11543 worktree: Some(key.worktree_id),
11544 binary: Some(language_server.binary().clone()),
11545 configuration: Some(language_server.configuration().clone()),
11546 workspace_folders: language_server.workspace_folders(),
11547 process_id: language_server.process_id(),
11548 },
11549 );
11550
11551 cx.emit(LspStoreEvent::LanguageServerAdded(
11552 server_id,
11553 language_server.name(),
11554 Some(key.worktree_id),
11555 ));
11556
11557 let server_capabilities = language_server.capabilities();
11558 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11559 downstream_client
11560 .send(proto::StartLanguageServer {
11561 project_id: *project_id,
11562 server: Some(proto::LanguageServer {
11563 id: server_id.to_proto(),
11564 name: language_server.name().to_string(),
11565 worktree_id: Some(key.worktree_id.to_proto()),
11566 }),
11567 capabilities: serde_json::to_string(&server_capabilities)
11568 .expect("serializing server LSP capabilities"),
11569 })
11570 .log_err();
11571 }
11572 self.lsp_server_capabilities
11573 .insert(server_id, server_capabilities);
11574
11575 // Tell the language server about every open buffer in the worktree that matches the language.
11576 // Also check for buffers in worktrees that reused this server
11577 let mut worktrees_using_server = vec![key.worktree_id];
11578 if let Some(local) = self.as_local() {
11579 // Find all worktrees that have this server in their language server tree
11580 for (worktree_id, servers) in &local.lsp_tree.instances {
11581 if *worktree_id != key.worktree_id {
11582 for server_map in servers.roots.values() {
11583 if server_map
11584 .values()
11585 .any(|(node, _)| node.id() == Some(server_id))
11586 {
11587 worktrees_using_server.push(*worktree_id);
11588 }
11589 }
11590 }
11591 }
11592 }
11593
11594 let mut buffer_paths_registered = Vec::new();
11595 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11596 let mut lsp_adapters = HashMap::default();
11597 for buffer_handle in buffer_store.buffers() {
11598 let buffer = buffer_handle.read(cx);
11599 let file = match File::from_dyn(buffer.file()) {
11600 Some(file) => file,
11601 None => continue,
11602 };
11603 let language = match buffer.language() {
11604 Some(language) => language,
11605 None => continue,
11606 };
11607
11608 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11609 || !lsp_adapters
11610 .entry(language.name())
11611 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11612 .iter()
11613 .any(|a| a.name == key.name)
11614 {
11615 continue;
11616 }
11617 // didOpen
11618 let file = match file.as_local() {
11619 Some(file) => file,
11620 None => continue,
11621 };
11622
11623 let local = self.as_local_mut().unwrap();
11624
11625 let buffer_id = buffer.remote_id();
11626 if local.registered_buffers.contains_key(&buffer_id) {
11627 let abs_path = file.abs_path(cx);
11628 let uri = match lsp::Uri::from_file_path(&abs_path) {
11629 Ok(uri) => uri,
11630 Err(()) => {
11631 log::error!("failed to convert path to URI: {:?}", abs_path);
11632 continue;
11633 }
11634 };
11635
11636 let versions = local
11637 .buffer_snapshots
11638 .entry(buffer_id)
11639 .or_default()
11640 .entry(server_id)
11641 .and_modify(|_| {
11642 assert!(
11643 false,
11644 "There should not be an existing snapshot for a newly inserted buffer"
11645 )
11646 })
11647 .or_insert_with(|| {
11648 vec![LspBufferSnapshot {
11649 version: 0,
11650 snapshot: buffer.text_snapshot(),
11651 }]
11652 });
11653
11654 let snapshot = versions.last().unwrap();
11655 let version = snapshot.version;
11656 let initial_snapshot = &snapshot.snapshot;
11657 language_server.register_buffer(
11658 uri,
11659 adapter.language_id(&language.name()),
11660 version,
11661 initial_snapshot.text(),
11662 );
11663 buffer_paths_registered.push((buffer_id, abs_path));
11664 local
11665 .buffers_opened_in_servers
11666 .entry(buffer_id)
11667 .or_default()
11668 .insert(server_id);
11669 }
11670 buffer_handle.update(cx, |buffer, cx| {
11671 buffer.set_completion_triggers(
11672 server_id,
11673 language_server
11674 .capabilities()
11675 .completion_provider
11676 .as_ref()
11677 .and_then(|provider| {
11678 provider
11679 .trigger_characters
11680 .as_ref()
11681 .map(|characters| characters.iter().cloned().collect())
11682 })
11683 .unwrap_or_default(),
11684 cx,
11685 )
11686 });
11687 }
11688 });
11689
11690 for (buffer_id, abs_path) in buffer_paths_registered {
11691 cx.emit(LspStoreEvent::LanguageServerUpdate {
11692 language_server_id: server_id,
11693 name: Some(adapter.name()),
11694 message: proto::update_language_server::Variant::RegisteredForBuffer(
11695 proto::RegisteredForBuffer {
11696 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11697 buffer_id: buffer_id.to_proto(),
11698 },
11699 ),
11700 });
11701 }
11702
11703 cx.notify();
11704 }
11705
11706 pub fn language_servers_running_disk_based_diagnostics(
11707 &self,
11708 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11709 self.language_server_statuses
11710 .iter()
11711 .filter_map(|(id, status)| {
11712 if status.has_pending_diagnostic_updates {
11713 Some(*id)
11714 } else {
11715 None
11716 }
11717 })
11718 }
11719
11720 pub(crate) fn cancel_language_server_work_for_buffers(
11721 &mut self,
11722 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11723 cx: &mut Context<Self>,
11724 ) {
11725 if let Some((client, project_id)) = self.upstream_client() {
11726 let request = client.request(proto::CancelLanguageServerWork {
11727 project_id,
11728 work: Some(proto::cancel_language_server_work::Work::Buffers(
11729 proto::cancel_language_server_work::Buffers {
11730 buffer_ids: buffers
11731 .into_iter()
11732 .map(|b| b.read(cx).remote_id().to_proto())
11733 .collect(),
11734 },
11735 )),
11736 });
11737 cx.background_spawn(request).detach_and_log_err(cx);
11738 } else if let Some(local) = self.as_local() {
11739 let servers = buffers
11740 .into_iter()
11741 .flat_map(|buffer| {
11742 buffer.update(cx, |buffer, cx| {
11743 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11744 })
11745 })
11746 .collect::<HashSet<_>>();
11747 for server_id in servers {
11748 self.cancel_language_server_work(server_id, None, cx);
11749 }
11750 }
11751 }
11752
11753 pub(crate) fn cancel_language_server_work(
11754 &mut self,
11755 server_id: LanguageServerId,
11756 token_to_cancel: Option<ProgressToken>,
11757 cx: &mut Context<Self>,
11758 ) {
11759 if let Some(local) = self.as_local() {
11760 let status = self.language_server_statuses.get(&server_id);
11761 let server = local.language_servers.get(&server_id);
11762 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11763 {
11764 for (token, progress) in &status.pending_work {
11765 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11766 && token != token_to_cancel
11767 {
11768 continue;
11769 }
11770 if progress.is_cancellable {
11771 server
11772 .notify::<lsp::notification::WorkDoneProgressCancel>(
11773 WorkDoneProgressCancelParams {
11774 token: token.to_lsp(),
11775 },
11776 )
11777 .ok();
11778 }
11779 }
11780 }
11781 } else if let Some((client, project_id)) = self.upstream_client() {
11782 let request = client.request(proto::CancelLanguageServerWork {
11783 project_id,
11784 work: Some(
11785 proto::cancel_language_server_work::Work::LanguageServerWork(
11786 proto::cancel_language_server_work::LanguageServerWork {
11787 language_server_id: server_id.to_proto(),
11788 token: token_to_cancel.map(|token| token.to_proto()),
11789 },
11790 ),
11791 ),
11792 });
11793 cx.background_spawn(request).detach_and_log_err(cx);
11794 }
11795 }
11796
11797 fn register_supplementary_language_server(
11798 &mut self,
11799 id: LanguageServerId,
11800 name: LanguageServerName,
11801 server: Arc<LanguageServer>,
11802 cx: &mut Context<Self>,
11803 ) {
11804 if let Some(local) = self.as_local_mut() {
11805 local
11806 .supplementary_language_servers
11807 .insert(id, (name.clone(), server));
11808 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11809 }
11810 }
11811
11812 fn unregister_supplementary_language_server(
11813 &mut self,
11814 id: LanguageServerId,
11815 cx: &mut Context<Self>,
11816 ) {
11817 if let Some(local) = self.as_local_mut() {
11818 local.supplementary_language_servers.remove(&id);
11819 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11820 }
11821 }
11822
11823 pub(crate) fn supplementary_language_servers(
11824 &self,
11825 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11826 self.as_local().into_iter().flat_map(|local| {
11827 local
11828 .supplementary_language_servers
11829 .iter()
11830 .map(|(id, (name, _))| (*id, name.clone()))
11831 })
11832 }
11833
11834 pub fn language_server_adapter_for_id(
11835 &self,
11836 id: LanguageServerId,
11837 ) -> Option<Arc<CachedLspAdapter>> {
11838 self.as_local()
11839 .and_then(|local| local.language_servers.get(&id))
11840 .and_then(|language_server_state| match language_server_state {
11841 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11842 _ => None,
11843 })
11844 }
11845
11846 pub(super) fn update_local_worktree_language_servers(
11847 &mut self,
11848 worktree_handle: &Entity<Worktree>,
11849 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11850 cx: &mut Context<Self>,
11851 ) {
11852 if changes.is_empty() {
11853 return;
11854 }
11855
11856 let Some(local) = self.as_local() else { return };
11857
11858 local.prettier_store.update(cx, |prettier_store, cx| {
11859 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11860 });
11861
11862 let worktree_id = worktree_handle.read(cx).id();
11863 let mut language_server_ids = local
11864 .language_server_ids
11865 .iter()
11866 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11867 .collect::<Vec<_>>();
11868 language_server_ids.sort();
11869 language_server_ids.dedup();
11870
11871 // let abs_path = worktree_handle.read(cx).abs_path();
11872 for server_id in &language_server_ids {
11873 if let Some(LanguageServerState::Running { server, .. }) =
11874 local.language_servers.get(server_id)
11875 && let Some(watched_paths) = local
11876 .language_server_watched_paths
11877 .get(server_id)
11878 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11879 {
11880 let params = lsp::DidChangeWatchedFilesParams {
11881 changes: changes
11882 .iter()
11883 .filter_map(|(path, _, change)| {
11884 if !watched_paths.is_match(path.as_std_path()) {
11885 return None;
11886 }
11887 let typ = match change {
11888 PathChange::Loaded => return None,
11889 PathChange::Added => lsp::FileChangeType::CREATED,
11890 PathChange::Removed => lsp::FileChangeType::DELETED,
11891 PathChange::Updated => lsp::FileChangeType::CHANGED,
11892 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11893 };
11894 let uri = lsp::Uri::from_file_path(
11895 worktree_handle.read(cx).absolutize(&path),
11896 )
11897 .ok()?;
11898 Some(lsp::FileEvent { uri, typ })
11899 })
11900 .collect(),
11901 };
11902 if !params.changes.is_empty() {
11903 server
11904 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11905 .ok();
11906 }
11907 }
11908 }
11909 for (path, _, _) in changes {
11910 if let Some(file_name) = path.file_name()
11911 && local.watched_manifest_filenames.contains(file_name)
11912 {
11913 self.request_workspace_config_refresh();
11914 break;
11915 }
11916 }
11917 }
11918
11919 pub fn wait_for_remote_buffer(
11920 &mut self,
11921 id: BufferId,
11922 cx: &mut Context<Self>,
11923 ) -> Task<Result<Entity<Buffer>>> {
11924 self.buffer_store.update(cx, |buffer_store, cx| {
11925 buffer_store.wait_for_remote_buffer(id, cx)
11926 })
11927 }
11928
11929 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11930 let mut result = proto::Symbol {
11931 language_server_name: symbol.language_server_name.0.to_string(),
11932 source_worktree_id: symbol.source_worktree_id.to_proto(),
11933 language_server_id: symbol.source_language_server_id.to_proto(),
11934 name: symbol.name.clone(),
11935 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11936 start: Some(proto::PointUtf16 {
11937 row: symbol.range.start.0.row,
11938 column: symbol.range.start.0.column,
11939 }),
11940 end: Some(proto::PointUtf16 {
11941 row: symbol.range.end.0.row,
11942 column: symbol.range.end.0.column,
11943 }),
11944 worktree_id: Default::default(),
11945 path: Default::default(),
11946 signature: Default::default(),
11947 container_name: symbol.container_name.clone(),
11948 };
11949 match &symbol.path {
11950 SymbolLocation::InProject(path) => {
11951 result.worktree_id = path.worktree_id.to_proto();
11952 result.path = path.path.to_proto();
11953 }
11954 SymbolLocation::OutsideProject {
11955 abs_path,
11956 signature,
11957 } => {
11958 result.path = abs_path.to_string_lossy().into_owned();
11959 result.signature = signature.to_vec();
11960 }
11961 }
11962 result
11963 }
11964
11965 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11966 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11967 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11968 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11969
11970 let path = if serialized_symbol.signature.is_empty() {
11971 SymbolLocation::InProject(ProjectPath {
11972 worktree_id,
11973 path: RelPath::from_proto(&serialized_symbol.path)
11974 .context("invalid symbol path")?,
11975 })
11976 } else {
11977 SymbolLocation::OutsideProject {
11978 abs_path: Path::new(&serialized_symbol.path).into(),
11979 signature: serialized_symbol
11980 .signature
11981 .try_into()
11982 .map_err(|_| anyhow!("invalid signature"))?,
11983 }
11984 };
11985
11986 let start = serialized_symbol.start.context("invalid start")?;
11987 let end = serialized_symbol.end.context("invalid end")?;
11988 Ok(CoreSymbol {
11989 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11990 source_worktree_id,
11991 source_language_server_id: LanguageServerId::from_proto(
11992 serialized_symbol.language_server_id,
11993 ),
11994 path,
11995 name: serialized_symbol.name,
11996 range: Unclipped(PointUtf16::new(start.row, start.column))
11997 ..Unclipped(PointUtf16::new(end.row, end.column)),
11998 kind,
11999 container_name: serialized_symbol.container_name,
12000 })
12001 }
12002
12003 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12004 let mut serialized_completion = proto::Completion {
12005 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12006 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12007 new_text: completion.new_text.clone(),
12008 ..proto::Completion::default()
12009 };
12010 match &completion.source {
12011 CompletionSource::Lsp {
12012 insert_range,
12013 server_id,
12014 lsp_completion,
12015 lsp_defaults,
12016 resolved,
12017 } => {
12018 let (old_insert_start, old_insert_end) = insert_range
12019 .as_ref()
12020 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12021 .unzip();
12022
12023 serialized_completion.old_insert_start = old_insert_start;
12024 serialized_completion.old_insert_end = old_insert_end;
12025 serialized_completion.source = proto::completion::Source::Lsp as i32;
12026 serialized_completion.server_id = server_id.0 as u64;
12027 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12028 serialized_completion.lsp_defaults = lsp_defaults
12029 .as_deref()
12030 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12031 serialized_completion.resolved = *resolved;
12032 }
12033 CompletionSource::BufferWord {
12034 word_range,
12035 resolved,
12036 } => {
12037 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12038 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12039 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12040 serialized_completion.resolved = *resolved;
12041 }
12042 CompletionSource::Custom => {
12043 serialized_completion.source = proto::completion::Source::Custom as i32;
12044 serialized_completion.resolved = true;
12045 }
12046 CompletionSource::Dap { sort_text } => {
12047 serialized_completion.source = proto::completion::Source::Dap as i32;
12048 serialized_completion.sort_text = Some(sort_text.clone());
12049 }
12050 }
12051
12052 serialized_completion
12053 }
12054
12055 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12056 let old_replace_start = completion
12057 .old_replace_start
12058 .and_then(deserialize_anchor)
12059 .context("invalid old start")?;
12060 let old_replace_end = completion
12061 .old_replace_end
12062 .and_then(deserialize_anchor)
12063 .context("invalid old end")?;
12064 let insert_range = {
12065 match completion.old_insert_start.zip(completion.old_insert_end) {
12066 Some((start, end)) => {
12067 let start = deserialize_anchor(start).context("invalid insert old start")?;
12068 let end = deserialize_anchor(end).context("invalid insert old end")?;
12069 Some(start..end)
12070 }
12071 None => None,
12072 }
12073 };
12074 Ok(CoreCompletion {
12075 replace_range: old_replace_start..old_replace_end,
12076 new_text: completion.new_text,
12077 source: match proto::completion::Source::from_i32(completion.source) {
12078 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12079 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12080 insert_range,
12081 server_id: LanguageServerId::from_proto(completion.server_id),
12082 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12083 lsp_defaults: completion
12084 .lsp_defaults
12085 .as_deref()
12086 .map(serde_json::from_slice)
12087 .transpose()?,
12088 resolved: completion.resolved,
12089 },
12090 Some(proto::completion::Source::BufferWord) => {
12091 let word_range = completion
12092 .buffer_word_start
12093 .and_then(deserialize_anchor)
12094 .context("invalid buffer word start")?
12095 ..completion
12096 .buffer_word_end
12097 .and_then(deserialize_anchor)
12098 .context("invalid buffer word end")?;
12099 CompletionSource::BufferWord {
12100 word_range,
12101 resolved: completion.resolved,
12102 }
12103 }
12104 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12105 sort_text: completion
12106 .sort_text
12107 .context("expected sort text to exist")?,
12108 },
12109 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12110 },
12111 })
12112 }
12113
12114 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12115 let (kind, lsp_action) = match &action.lsp_action {
12116 LspAction::Action(code_action) => (
12117 proto::code_action::Kind::Action as i32,
12118 serde_json::to_vec(code_action).unwrap(),
12119 ),
12120 LspAction::Command(command) => (
12121 proto::code_action::Kind::Command as i32,
12122 serde_json::to_vec(command).unwrap(),
12123 ),
12124 LspAction::CodeLens(code_lens) => (
12125 proto::code_action::Kind::CodeLens as i32,
12126 serde_json::to_vec(code_lens).unwrap(),
12127 ),
12128 };
12129
12130 proto::CodeAction {
12131 server_id: action.server_id.0 as u64,
12132 start: Some(serialize_anchor(&action.range.start)),
12133 end: Some(serialize_anchor(&action.range.end)),
12134 lsp_action,
12135 kind,
12136 resolved: action.resolved,
12137 }
12138 }
12139
12140 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12141 let start = action
12142 .start
12143 .and_then(deserialize_anchor)
12144 .context("invalid start")?;
12145 let end = action
12146 .end
12147 .and_then(deserialize_anchor)
12148 .context("invalid end")?;
12149 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12150 Some(proto::code_action::Kind::Action) => {
12151 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12152 }
12153 Some(proto::code_action::Kind::Command) => {
12154 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12155 }
12156 Some(proto::code_action::Kind::CodeLens) => {
12157 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12158 }
12159 None => anyhow::bail!("Unknown action kind {}", action.kind),
12160 };
12161 Ok(CodeAction {
12162 server_id: LanguageServerId(action.server_id as usize),
12163 range: start..end,
12164 resolved: action.resolved,
12165 lsp_action,
12166 })
12167 }
12168
12169 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12170 match &formatting_result {
12171 Ok(_) => self.last_formatting_failure = None,
12172 Err(error) => {
12173 let error_string = format!("{error:#}");
12174 log::error!("Formatting failed: {error_string}");
12175 self.last_formatting_failure
12176 .replace(error_string.lines().join(" "));
12177 }
12178 }
12179 }
12180
12181 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12182 self.lsp_server_capabilities.remove(&for_server);
12183 self.semantic_token_config.remove_server_data(for_server);
12184 for lsp_data in self.lsp_data.values_mut() {
12185 lsp_data.remove_server_data(for_server);
12186 }
12187 if let Some(local) = self.as_local_mut() {
12188 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12189 local
12190 .workspace_pull_diagnostics_result_ids
12191 .remove(&for_server);
12192 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12193 buffer_servers.remove(&for_server);
12194 }
12195 }
12196 }
12197
12198 pub fn result_id_for_buffer_pull(
12199 &self,
12200 server_id: LanguageServerId,
12201 buffer_id: BufferId,
12202 registration_id: &Option<SharedString>,
12203 cx: &App,
12204 ) -> Option<SharedString> {
12205 let abs_path = self
12206 .buffer_store
12207 .read(cx)
12208 .get(buffer_id)
12209 .and_then(|b| File::from_dyn(b.read(cx).file()))
12210 .map(|f| f.abs_path(cx))?;
12211 self.as_local()?
12212 .buffer_pull_diagnostics_result_ids
12213 .get(&server_id)?
12214 .get(registration_id)?
12215 .get(&abs_path)?
12216 .clone()
12217 }
12218
12219 /// Gets all result_ids for a workspace diagnostics pull request.
12220 /// 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.
12221 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12222 pub fn result_ids_for_workspace_refresh(
12223 &self,
12224 server_id: LanguageServerId,
12225 registration_id: &Option<SharedString>,
12226 ) -> HashMap<PathBuf, SharedString> {
12227 let Some(local) = self.as_local() else {
12228 return HashMap::default();
12229 };
12230 local
12231 .workspace_pull_diagnostics_result_ids
12232 .get(&server_id)
12233 .into_iter()
12234 .filter_map(|diagnostics| diagnostics.get(registration_id))
12235 .flatten()
12236 .filter_map(|(abs_path, result_id)| {
12237 let result_id = local
12238 .buffer_pull_diagnostics_result_ids
12239 .get(&server_id)
12240 .and_then(|buffer_ids_result_ids| {
12241 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12242 })
12243 .cloned()
12244 .flatten()
12245 .or_else(|| result_id.clone())?;
12246 Some((abs_path.clone(), result_id))
12247 })
12248 .collect()
12249 }
12250
12251 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12252 if let Some(LanguageServerState::Running {
12253 workspace_diagnostics_refresh_tasks,
12254 ..
12255 }) = self
12256 .as_local_mut()
12257 .and_then(|local| local.language_servers.get_mut(&server_id))
12258 {
12259 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12260 diagnostics.refresh_tx.try_send(()).ok();
12261 }
12262 }
12263 }
12264
12265 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12266 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12267 /// which requires refreshing both workspace and document diagnostics.
12268 pub fn pull_document_diagnostics_for_server(
12269 &mut self,
12270 server_id: LanguageServerId,
12271 source_buffer_id: Option<BufferId>,
12272 cx: &mut Context<Self>,
12273 ) -> Shared<Task<()>> {
12274 let Some(local) = self.as_local_mut() else {
12275 return Task::ready(()).shared();
12276 };
12277 let mut buffers_to_refresh = HashSet::default();
12278 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12279 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12280 buffers_to_refresh.insert(*buffer_id);
12281 }
12282 }
12283
12284 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12285 }
12286
12287 pub fn pull_document_diagnostics_for_buffer_edit(
12288 &mut self,
12289 buffer_id: BufferId,
12290 cx: &mut Context<Self>,
12291 ) {
12292 let Some(local) = self.as_local_mut() else {
12293 return;
12294 };
12295 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12296 else {
12297 return;
12298 };
12299 for server_id in languages_servers {
12300 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12301 }
12302 }
12303
12304 fn apply_workspace_diagnostic_report(
12305 &mut self,
12306 server_id: LanguageServerId,
12307 report: lsp::WorkspaceDiagnosticReportResult,
12308 registration_id: Option<SharedString>,
12309 cx: &mut Context<Self>,
12310 ) {
12311 let mut workspace_diagnostics =
12312 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12313 report,
12314 server_id,
12315 registration_id,
12316 );
12317 workspace_diagnostics.retain(|d| match &d.diagnostics {
12318 LspPullDiagnostics::Response {
12319 server_id,
12320 registration_id,
12321 ..
12322 } => self.diagnostic_registration_exists(*server_id, registration_id),
12323 LspPullDiagnostics::Default => false,
12324 });
12325 let mut unchanged_buffers = HashMap::default();
12326 let workspace_diagnostics_updates = workspace_diagnostics
12327 .into_iter()
12328 .filter_map(
12329 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12330 LspPullDiagnostics::Response {
12331 server_id,
12332 uri,
12333 diagnostics,
12334 registration_id,
12335 } => Some((
12336 server_id,
12337 uri,
12338 diagnostics,
12339 workspace_diagnostics.version,
12340 registration_id,
12341 )),
12342 LspPullDiagnostics::Default => None,
12343 },
12344 )
12345 .fold(
12346 HashMap::default(),
12347 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12348 let (result_id, diagnostics) = match diagnostics {
12349 PulledDiagnostics::Unchanged { result_id } => {
12350 unchanged_buffers
12351 .entry(new_registration_id.clone())
12352 .or_insert_with(HashSet::default)
12353 .insert(uri.clone());
12354 (Some(result_id), Vec::new())
12355 }
12356 PulledDiagnostics::Changed {
12357 result_id,
12358 diagnostics,
12359 } => (result_id, diagnostics),
12360 };
12361 let disk_based_sources = Cow::Owned(
12362 self.language_server_adapter_for_id(server_id)
12363 .as_ref()
12364 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12365 .unwrap_or(&[])
12366 .to_vec(),
12367 );
12368
12369 let Some(abs_path) = uri.to_file_path().ok() else {
12370 return acc;
12371 };
12372 let Some((worktree, relative_path)) =
12373 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12374 else {
12375 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12376 return acc;
12377 };
12378 let worktree_id = worktree.read(cx).id();
12379 let project_path = ProjectPath {
12380 worktree_id,
12381 path: relative_path,
12382 };
12383 if let Some(local_lsp_store) = self.as_local_mut() {
12384 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12385 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12386 }
12387 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12388 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12389 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12390 acc.entry(server_id)
12391 .or_insert_with(HashMap::default)
12392 .entry(new_registration_id.clone())
12393 .or_insert_with(Vec::new)
12394 .push(DocumentDiagnosticsUpdate {
12395 server_id,
12396 diagnostics: lsp::PublishDiagnosticsParams {
12397 uri,
12398 diagnostics,
12399 version,
12400 },
12401 result_id: result_id.map(SharedString::new),
12402 disk_based_sources,
12403 registration_id: new_registration_id,
12404 });
12405 }
12406 acc
12407 },
12408 );
12409
12410 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12411 for (registration_id, diagnostic_updates) in diagnostic_updates {
12412 self.merge_lsp_diagnostics(
12413 DiagnosticSourceKind::Pulled,
12414 diagnostic_updates,
12415 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12416 DiagnosticSourceKind::Pulled => {
12417 old_diagnostic.registration_id != registration_id
12418 || unchanged_buffers
12419 .get(&old_diagnostic.registration_id)
12420 .is_some_and(|unchanged_buffers| {
12421 unchanged_buffers.contains(&document_uri)
12422 })
12423 }
12424 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12425 },
12426 cx,
12427 )
12428 .log_err();
12429 }
12430 }
12431 }
12432
12433 fn register_server_capabilities(
12434 &mut self,
12435 server_id: LanguageServerId,
12436 params: lsp::RegistrationParams,
12437 cx: &mut Context<Self>,
12438 ) -> anyhow::Result<()> {
12439 let server = self
12440 .language_server_for_id(server_id)
12441 .with_context(|| format!("no server {server_id} found"))?;
12442 for reg in params.registrations {
12443 match reg.method.as_str() {
12444 "workspace/didChangeWatchedFiles" => {
12445 if let Some(options) = reg.register_options {
12446 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12447 let caps = serde_json::from_value(options)?;
12448 local_lsp_store
12449 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12450 true
12451 } else {
12452 false
12453 };
12454 if notify {
12455 notify_server_capabilities_updated(&server, cx);
12456 }
12457 }
12458 }
12459 "workspace/didChangeConfiguration" => {
12460 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12461 }
12462 "workspace/didChangeWorkspaceFolders" => {
12463 // In this case register options is an empty object, we can ignore it
12464 let caps = lsp::WorkspaceFoldersServerCapabilities {
12465 supported: Some(true),
12466 change_notifications: Some(OneOf::Right(reg.id)),
12467 };
12468 server.update_capabilities(|capabilities| {
12469 capabilities
12470 .workspace
12471 .get_or_insert_default()
12472 .workspace_folders = Some(caps);
12473 });
12474 notify_server_capabilities_updated(&server, cx);
12475 }
12476 "workspace/symbol" => {
12477 let options = parse_register_capabilities(reg)?;
12478 server.update_capabilities(|capabilities| {
12479 capabilities.workspace_symbol_provider = Some(options);
12480 });
12481 notify_server_capabilities_updated(&server, cx);
12482 }
12483 "workspace/fileOperations" => {
12484 if let Some(options) = reg.register_options {
12485 let caps = serde_json::from_value(options)?;
12486 server.update_capabilities(|capabilities| {
12487 capabilities
12488 .workspace
12489 .get_or_insert_default()
12490 .file_operations = Some(caps);
12491 });
12492 notify_server_capabilities_updated(&server, cx);
12493 }
12494 }
12495 "workspace/executeCommand" => {
12496 if let Some(options) = reg.register_options {
12497 let options = serde_json::from_value(options)?;
12498 server.update_capabilities(|capabilities| {
12499 capabilities.execute_command_provider = Some(options);
12500 });
12501 notify_server_capabilities_updated(&server, cx);
12502 }
12503 }
12504 "textDocument/rangeFormatting" => {
12505 let options = parse_register_capabilities(reg)?;
12506 server.update_capabilities(|capabilities| {
12507 capabilities.document_range_formatting_provider = Some(options);
12508 });
12509 notify_server_capabilities_updated(&server, cx);
12510 }
12511 "textDocument/onTypeFormatting" => {
12512 if let Some(options) = reg
12513 .register_options
12514 .map(serde_json::from_value)
12515 .transpose()?
12516 {
12517 server.update_capabilities(|capabilities| {
12518 capabilities.document_on_type_formatting_provider = Some(options);
12519 });
12520 notify_server_capabilities_updated(&server, cx);
12521 }
12522 }
12523 "textDocument/formatting" => {
12524 let options = parse_register_capabilities(reg)?;
12525 server.update_capabilities(|capabilities| {
12526 capabilities.document_formatting_provider = Some(options);
12527 });
12528 notify_server_capabilities_updated(&server, cx);
12529 }
12530 "textDocument/rename" => {
12531 let options = parse_register_capabilities(reg)?;
12532 server.update_capabilities(|capabilities| {
12533 capabilities.rename_provider = Some(options);
12534 });
12535 notify_server_capabilities_updated(&server, cx);
12536 }
12537 "textDocument/inlayHint" => {
12538 let options = parse_register_capabilities(reg)?;
12539 server.update_capabilities(|capabilities| {
12540 capabilities.inlay_hint_provider = Some(options);
12541 });
12542 notify_server_capabilities_updated(&server, cx);
12543 }
12544 "textDocument/documentSymbol" => {
12545 let options = parse_register_capabilities(reg)?;
12546 server.update_capabilities(|capabilities| {
12547 capabilities.document_symbol_provider = Some(options);
12548 });
12549 notify_server_capabilities_updated(&server, cx);
12550 }
12551 "textDocument/codeAction" => {
12552 let options = parse_register_capabilities(reg)?;
12553 let provider = match options {
12554 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12555 OneOf::Right(caps) => caps,
12556 };
12557 server.update_capabilities(|capabilities| {
12558 capabilities.code_action_provider = Some(provider);
12559 });
12560 notify_server_capabilities_updated(&server, cx);
12561 }
12562 "textDocument/definition" => {
12563 let options = parse_register_capabilities(reg)?;
12564 server.update_capabilities(|capabilities| {
12565 capabilities.definition_provider = Some(options);
12566 });
12567 notify_server_capabilities_updated(&server, cx);
12568 }
12569 "textDocument/completion" => {
12570 if let Some(caps) = reg
12571 .register_options
12572 .map(serde_json::from_value::<CompletionOptions>)
12573 .transpose()?
12574 {
12575 server.update_capabilities(|capabilities| {
12576 capabilities.completion_provider = Some(caps.clone());
12577 });
12578
12579 if let Some(local) = self.as_local() {
12580 let mut buffers_with_language_server = Vec::new();
12581 for handle in self.buffer_store.read(cx).buffers() {
12582 let buffer_id = handle.read(cx).remote_id();
12583 if local
12584 .buffers_opened_in_servers
12585 .get(&buffer_id)
12586 .filter(|s| s.contains(&server_id))
12587 .is_some()
12588 {
12589 buffers_with_language_server.push(handle);
12590 }
12591 }
12592 let triggers = caps
12593 .trigger_characters
12594 .unwrap_or_default()
12595 .into_iter()
12596 .collect::<BTreeSet<_>>();
12597 for handle in buffers_with_language_server {
12598 let triggers = triggers.clone();
12599 let _ = handle.update(cx, move |buffer, cx| {
12600 buffer.set_completion_triggers(server_id, triggers, cx);
12601 });
12602 }
12603 }
12604 notify_server_capabilities_updated(&server, cx);
12605 }
12606 }
12607 "textDocument/hover" => {
12608 let options = parse_register_capabilities(reg)?;
12609 let provider = match options {
12610 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12611 OneOf::Right(caps) => caps,
12612 };
12613 server.update_capabilities(|capabilities| {
12614 capabilities.hover_provider = Some(provider);
12615 });
12616 notify_server_capabilities_updated(&server, cx);
12617 }
12618 "textDocument/signatureHelp" => {
12619 if let Some(caps) = reg
12620 .register_options
12621 .map(serde_json::from_value)
12622 .transpose()?
12623 {
12624 server.update_capabilities(|capabilities| {
12625 capabilities.signature_help_provider = Some(caps);
12626 });
12627 notify_server_capabilities_updated(&server, cx);
12628 }
12629 }
12630 "textDocument/didChange" => {
12631 if let Some(sync_kind) = reg
12632 .register_options
12633 .and_then(|opts| opts.get("syncKind").cloned())
12634 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12635 .transpose()?
12636 {
12637 server.update_capabilities(|capabilities| {
12638 let mut sync_options =
12639 Self::take_text_document_sync_options(capabilities);
12640 sync_options.change = Some(sync_kind);
12641 capabilities.text_document_sync =
12642 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12643 });
12644 notify_server_capabilities_updated(&server, cx);
12645 }
12646 }
12647 "textDocument/didSave" => {
12648 if let Some(include_text) = reg
12649 .register_options
12650 .map(|opts| {
12651 let transpose = opts
12652 .get("includeText")
12653 .cloned()
12654 .map(serde_json::from_value::<Option<bool>>)
12655 .transpose();
12656 match transpose {
12657 Ok(value) => Ok(value.flatten()),
12658 Err(e) => Err(e),
12659 }
12660 })
12661 .transpose()?
12662 {
12663 server.update_capabilities(|capabilities| {
12664 let mut sync_options =
12665 Self::take_text_document_sync_options(capabilities);
12666 sync_options.save =
12667 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12668 include_text,
12669 }));
12670 capabilities.text_document_sync =
12671 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12672 });
12673 notify_server_capabilities_updated(&server, cx);
12674 }
12675 }
12676 "textDocument/codeLens" => {
12677 if let Some(caps) = reg
12678 .register_options
12679 .map(serde_json::from_value)
12680 .transpose()?
12681 {
12682 server.update_capabilities(|capabilities| {
12683 capabilities.code_lens_provider = Some(caps);
12684 });
12685 notify_server_capabilities_updated(&server, cx);
12686 }
12687 }
12688 "textDocument/diagnostic" => {
12689 if let Some(caps) = reg
12690 .register_options
12691 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12692 .transpose()?
12693 {
12694 let local = self
12695 .as_local_mut()
12696 .context("Expected LSP Store to be local")?;
12697 let state = local
12698 .language_servers
12699 .get_mut(&server_id)
12700 .context("Could not obtain Language Servers state")?;
12701 local
12702 .language_server_dynamic_registrations
12703 .entry(server_id)
12704 .or_default()
12705 .diagnostics
12706 .insert(Some(reg.id.clone()), caps.clone());
12707
12708 let supports_workspace_diagnostics =
12709 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12710 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12711 diagnostic_options.workspace_diagnostics
12712 }
12713 DiagnosticServerCapabilities::RegistrationOptions(
12714 diagnostic_registration_options,
12715 ) => {
12716 diagnostic_registration_options
12717 .diagnostic_options
12718 .workspace_diagnostics
12719 }
12720 };
12721
12722 if supports_workspace_diagnostics(&caps) {
12723 if let LanguageServerState::Running {
12724 workspace_diagnostics_refresh_tasks,
12725 ..
12726 } = state
12727 && let Some(task) = lsp_workspace_diagnostics_refresh(
12728 Some(reg.id.clone()),
12729 caps.clone(),
12730 server.clone(),
12731 cx,
12732 )
12733 {
12734 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12735 }
12736 }
12737
12738 server.update_capabilities(|capabilities| {
12739 capabilities.diagnostic_provider = Some(caps);
12740 });
12741
12742 notify_server_capabilities_updated(&server, cx);
12743
12744 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12745 }
12746 }
12747 "textDocument/documentColor" => {
12748 let options = parse_register_capabilities(reg)?;
12749 let provider = match options {
12750 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12751 OneOf::Right(caps) => caps,
12752 };
12753 server.update_capabilities(|capabilities| {
12754 capabilities.color_provider = Some(provider);
12755 });
12756 notify_server_capabilities_updated(&server, cx);
12757 }
12758 "textDocument/foldingRange" => {
12759 let options = parse_register_capabilities(reg)?;
12760 let provider = match options {
12761 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12762 OneOf::Right(caps) => caps,
12763 };
12764 server.update_capabilities(|capabilities| {
12765 capabilities.folding_range_provider = Some(provider);
12766 });
12767 notify_server_capabilities_updated(&server, cx);
12768 }
12769 _ => log::warn!("unhandled capability registration: {reg:?}"),
12770 }
12771 }
12772
12773 Ok(())
12774 }
12775
12776 fn unregister_server_capabilities(
12777 &mut self,
12778 server_id: LanguageServerId,
12779 params: lsp::UnregistrationParams,
12780 cx: &mut Context<Self>,
12781 ) -> anyhow::Result<()> {
12782 let server = self
12783 .language_server_for_id(server_id)
12784 .with_context(|| format!("no server {server_id} found"))?;
12785 for unreg in params.unregisterations.iter() {
12786 match unreg.method.as_str() {
12787 "workspace/didChangeWatchedFiles" => {
12788 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12789 local_lsp_store
12790 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12791 true
12792 } else {
12793 false
12794 };
12795 if notify {
12796 notify_server_capabilities_updated(&server, cx);
12797 }
12798 }
12799 "workspace/didChangeConfiguration" => {
12800 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12801 }
12802 "workspace/didChangeWorkspaceFolders" => {
12803 server.update_capabilities(|capabilities| {
12804 capabilities
12805 .workspace
12806 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12807 workspace_folders: None,
12808 file_operations: None,
12809 })
12810 .workspace_folders = None;
12811 });
12812 notify_server_capabilities_updated(&server, cx);
12813 }
12814 "workspace/symbol" => {
12815 server.update_capabilities(|capabilities| {
12816 capabilities.workspace_symbol_provider = None
12817 });
12818 notify_server_capabilities_updated(&server, cx);
12819 }
12820 "workspace/fileOperations" => {
12821 server.update_capabilities(|capabilities| {
12822 capabilities
12823 .workspace
12824 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12825 workspace_folders: None,
12826 file_operations: None,
12827 })
12828 .file_operations = None;
12829 });
12830 notify_server_capabilities_updated(&server, cx);
12831 }
12832 "workspace/executeCommand" => {
12833 server.update_capabilities(|capabilities| {
12834 capabilities.execute_command_provider = None;
12835 });
12836 notify_server_capabilities_updated(&server, cx);
12837 }
12838 "textDocument/rangeFormatting" => {
12839 server.update_capabilities(|capabilities| {
12840 capabilities.document_range_formatting_provider = None
12841 });
12842 notify_server_capabilities_updated(&server, cx);
12843 }
12844 "textDocument/onTypeFormatting" => {
12845 server.update_capabilities(|capabilities| {
12846 capabilities.document_on_type_formatting_provider = None;
12847 });
12848 notify_server_capabilities_updated(&server, cx);
12849 }
12850 "textDocument/formatting" => {
12851 server.update_capabilities(|capabilities| {
12852 capabilities.document_formatting_provider = None;
12853 });
12854 notify_server_capabilities_updated(&server, cx);
12855 }
12856 "textDocument/rename" => {
12857 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12858 notify_server_capabilities_updated(&server, cx);
12859 }
12860 "textDocument/codeAction" => {
12861 server.update_capabilities(|capabilities| {
12862 capabilities.code_action_provider = None;
12863 });
12864 notify_server_capabilities_updated(&server, cx);
12865 }
12866 "textDocument/definition" => {
12867 server.update_capabilities(|capabilities| {
12868 capabilities.definition_provider = None;
12869 });
12870 notify_server_capabilities_updated(&server, cx);
12871 }
12872 "textDocument/completion" => {
12873 server.update_capabilities(|capabilities| {
12874 capabilities.completion_provider = None;
12875 });
12876 notify_server_capabilities_updated(&server, cx);
12877 }
12878 "textDocument/hover" => {
12879 server.update_capabilities(|capabilities| {
12880 capabilities.hover_provider = None;
12881 });
12882 notify_server_capabilities_updated(&server, cx);
12883 }
12884 "textDocument/signatureHelp" => {
12885 server.update_capabilities(|capabilities| {
12886 capabilities.signature_help_provider = None;
12887 });
12888 notify_server_capabilities_updated(&server, cx);
12889 }
12890 "textDocument/didChange" => {
12891 server.update_capabilities(|capabilities| {
12892 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12893 sync_options.change = None;
12894 capabilities.text_document_sync =
12895 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12896 });
12897 notify_server_capabilities_updated(&server, cx);
12898 }
12899 "textDocument/didSave" => {
12900 server.update_capabilities(|capabilities| {
12901 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12902 sync_options.save = None;
12903 capabilities.text_document_sync =
12904 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12905 });
12906 notify_server_capabilities_updated(&server, cx);
12907 }
12908 "textDocument/codeLens" => {
12909 server.update_capabilities(|capabilities| {
12910 capabilities.code_lens_provider = None;
12911 });
12912 notify_server_capabilities_updated(&server, cx);
12913 }
12914 "textDocument/diagnostic" => {
12915 let local = self
12916 .as_local_mut()
12917 .context("Expected LSP Store to be local")?;
12918
12919 let state = local
12920 .language_servers
12921 .get_mut(&server_id)
12922 .context("Could not obtain Language Servers state")?;
12923 let registrations = local
12924 .language_server_dynamic_registrations
12925 .get_mut(&server_id)
12926 .with_context(|| {
12927 format!("Expected dynamic registration to exist for server {server_id}")
12928 })?;
12929 registrations.diagnostics
12930 .remove(&Some(unreg.id.clone()))
12931 .with_context(|| format!(
12932 "Attempted to unregister non-existent diagnostic registration with ID {}",
12933 unreg.id)
12934 )?;
12935 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12936
12937 if let LanguageServerState::Running {
12938 workspace_diagnostics_refresh_tasks,
12939 ..
12940 } = state
12941 {
12942 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12943 }
12944
12945 self.clear_unregistered_diagnostics(
12946 server_id,
12947 SharedString::from(unreg.id.clone()),
12948 cx,
12949 )?;
12950
12951 if removed_last_diagnostic_provider {
12952 server.update_capabilities(|capabilities| {
12953 debug_assert!(capabilities.diagnostic_provider.is_some());
12954 capabilities.diagnostic_provider = None;
12955 });
12956 }
12957
12958 notify_server_capabilities_updated(&server, cx);
12959 }
12960 "textDocument/documentColor" => {
12961 server.update_capabilities(|capabilities| {
12962 capabilities.color_provider = None;
12963 });
12964 notify_server_capabilities_updated(&server, cx);
12965 }
12966 "textDocument/foldingRange" => {
12967 server.update_capabilities(|capabilities| {
12968 capabilities.folding_range_provider = None;
12969 });
12970 notify_server_capabilities_updated(&server, cx);
12971 }
12972 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12973 }
12974 }
12975
12976 Ok(())
12977 }
12978
12979 fn clear_unregistered_diagnostics(
12980 &mut self,
12981 server_id: LanguageServerId,
12982 cleared_registration_id: SharedString,
12983 cx: &mut Context<Self>,
12984 ) -> anyhow::Result<()> {
12985 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12986
12987 self.buffer_store.update(cx, |buffer_store, cx| {
12988 for buffer_handle in buffer_store.buffers() {
12989 let buffer = buffer_handle.read(cx);
12990 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12991 let Some(abs_path) = abs_path else {
12992 continue;
12993 };
12994 affected_abs_paths.insert(abs_path);
12995 }
12996 });
12997
12998 let local = self.as_local().context("Expected LSP Store to be local")?;
12999 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13000 let Some(worktree) = self
13001 .worktree_store
13002 .read(cx)
13003 .worktree_for_id(*worktree_id, cx)
13004 else {
13005 continue;
13006 };
13007
13008 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13009 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13010 let has_matching_registration =
13011 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13012 entry.diagnostic.registration_id.as_ref()
13013 == Some(&cleared_registration_id)
13014 });
13015 if has_matching_registration {
13016 let abs_path = worktree.read(cx).absolutize(rel_path);
13017 affected_abs_paths.insert(abs_path);
13018 }
13019 }
13020 }
13021 }
13022
13023 if affected_abs_paths.is_empty() {
13024 return Ok(());
13025 }
13026
13027 // Send a fake diagnostic update which clears the state for the registration ID
13028 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13029 affected_abs_paths
13030 .into_iter()
13031 .map(|abs_path| DocumentDiagnosticsUpdate {
13032 diagnostics: DocumentDiagnostics {
13033 diagnostics: Vec::new(),
13034 document_abs_path: abs_path,
13035 version: None,
13036 },
13037 result_id: None,
13038 registration_id: Some(cleared_registration_id.clone()),
13039 server_id,
13040 disk_based_sources: Cow::Borrowed(&[]),
13041 })
13042 .collect();
13043
13044 let merge_registration_id = cleared_registration_id.clone();
13045 self.merge_diagnostic_entries(
13046 clears,
13047 move |_, diagnostic, _| {
13048 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13049 diagnostic.registration_id != Some(merge_registration_id.clone())
13050 } else {
13051 true
13052 }
13053 },
13054 cx,
13055 )?;
13056
13057 Ok(())
13058 }
13059
13060 async fn deduplicate_range_based_lsp_requests<T>(
13061 lsp_store: &Entity<Self>,
13062 server_id: Option<LanguageServerId>,
13063 lsp_request_id: LspRequestId,
13064 proto_request: &T::ProtoRequest,
13065 range: Range<Anchor>,
13066 cx: &mut AsyncApp,
13067 ) -> Result<()>
13068 where
13069 T: LspCommand,
13070 T::ProtoRequest: proto::LspRequestMessage,
13071 {
13072 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13073 let version = deserialize_version(proto_request.buffer_version());
13074 let buffer = lsp_store.update(cx, |this, cx| {
13075 this.buffer_store.read(cx).get_existing(buffer_id)
13076 })?;
13077 buffer
13078 .update(cx, |buffer, _| buffer.wait_for_version(version))
13079 .await?;
13080 lsp_store.update(cx, |lsp_store, cx| {
13081 let buffer_snapshot = buffer.read(cx).snapshot();
13082 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13083 let chunks_queried_for = lsp_data
13084 .inlay_hints
13085 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13086 .collect::<Vec<_>>();
13087 match chunks_queried_for.as_slice() {
13088 &[chunk] => {
13089 let key = LspKey {
13090 request_type: TypeId::of::<T>(),
13091 server_queried: server_id,
13092 };
13093 let previous_request = lsp_data
13094 .chunk_lsp_requests
13095 .entry(key)
13096 .or_default()
13097 .insert(chunk, lsp_request_id);
13098 if let Some((previous_request, running_requests)) =
13099 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13100 {
13101 running_requests.remove(&previous_request);
13102 }
13103 }
13104 _ambiguous_chunks => {
13105 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13106 // there, a buffer version-based check will be performed and outdated requests discarded.
13107 }
13108 }
13109 anyhow::Ok(())
13110 })?;
13111
13112 Ok(())
13113 }
13114
13115 async fn query_lsp_locally<T>(
13116 lsp_store: Entity<Self>,
13117 for_server_id: Option<LanguageServerId>,
13118 sender_id: proto::PeerId,
13119 lsp_request_id: LspRequestId,
13120 proto_request: T::ProtoRequest,
13121 position: Option<Anchor>,
13122 cx: &mut AsyncApp,
13123 ) -> Result<()>
13124 where
13125 T: LspCommand + Clone,
13126 T::ProtoRequest: proto::LspRequestMessage,
13127 <T::ProtoRequest as proto::RequestMessage>::Response:
13128 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13129 {
13130 let (buffer_version, buffer) =
13131 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13132 let request =
13133 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13134 let key = LspKey {
13135 request_type: TypeId::of::<T>(),
13136 server_queried: for_server_id,
13137 };
13138 lsp_store.update(cx, |lsp_store, cx| {
13139 let request_task = match for_server_id {
13140 Some(server_id) => {
13141 let server_task = lsp_store.request_lsp(
13142 buffer.clone(),
13143 LanguageServerToQuery::Other(server_id),
13144 request.clone(),
13145 cx,
13146 );
13147 cx.background_spawn(async move {
13148 let mut responses = Vec::new();
13149 match server_task.await {
13150 Ok(response) => responses.push((server_id, response)),
13151 // rust-analyzer likes to error with this when its still loading up
13152 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13153 Err(e) => log::error!(
13154 "Error handling response for request {request:?}: {e:#}"
13155 ),
13156 }
13157 responses
13158 })
13159 }
13160 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13161 };
13162 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13163 if T::ProtoRequest::stop_previous_requests() {
13164 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13165 lsp_requests.clear();
13166 }
13167 }
13168 lsp_data.lsp_requests.entry(key).or_default().insert(
13169 lsp_request_id,
13170 cx.spawn(async move |lsp_store, cx| {
13171 let response = request_task.await;
13172 lsp_store
13173 .update(cx, |lsp_store, cx| {
13174 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13175 {
13176 let response = response
13177 .into_iter()
13178 .map(|(server_id, response)| {
13179 (
13180 server_id.to_proto(),
13181 T::response_to_proto(
13182 response,
13183 lsp_store,
13184 sender_id,
13185 &buffer_version,
13186 cx,
13187 )
13188 .into(),
13189 )
13190 })
13191 .collect::<HashMap<_, _>>();
13192 match client.send_lsp_response::<T::ProtoRequest>(
13193 project_id,
13194 lsp_request_id,
13195 response,
13196 ) {
13197 Ok(()) => {}
13198 Err(e) => {
13199 log::error!("Failed to send LSP response: {e:#}",)
13200 }
13201 }
13202 }
13203 })
13204 .ok();
13205 }),
13206 );
13207 });
13208 Ok(())
13209 }
13210
13211 async fn wait_for_buffer_version<T>(
13212 lsp_store: &Entity<Self>,
13213 proto_request: &T::ProtoRequest,
13214 cx: &mut AsyncApp,
13215 ) -> Result<(Global, Entity<Buffer>)>
13216 where
13217 T: LspCommand,
13218 T::ProtoRequest: proto::LspRequestMessage,
13219 {
13220 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13221 let version = deserialize_version(proto_request.buffer_version());
13222 let buffer = lsp_store.update(cx, |this, cx| {
13223 this.buffer_store.read(cx).get_existing(buffer_id)
13224 })?;
13225 buffer
13226 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13227 .await?;
13228 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13229 Ok((buffer_version, buffer))
13230 }
13231
13232 fn take_text_document_sync_options(
13233 capabilities: &mut lsp::ServerCapabilities,
13234 ) -> lsp::TextDocumentSyncOptions {
13235 match capabilities.text_document_sync.take() {
13236 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13237 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13238 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13239 sync_options.change = Some(sync_kind);
13240 sync_options
13241 }
13242 None => lsp::TextDocumentSyncOptions::default(),
13243 }
13244 }
13245
13246 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13247 self.downstream_client.clone()
13248 }
13249
13250 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13251 self.worktree_store.clone()
13252 }
13253
13254 /// Gets what's stored in the LSP data for the given buffer.
13255 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13256 self.lsp_data.get_mut(&buffer_id)
13257 }
13258
13259 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13260 /// new [`BufferLspData`] will be created to replace the previous state.
13261 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13262 let (buffer_id, buffer_version) =
13263 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13264 let lsp_data = self
13265 .lsp_data
13266 .entry(buffer_id)
13267 .or_insert_with(|| BufferLspData::new(buffer, cx));
13268 if buffer_version.changed_since(&lsp_data.buffer_version) {
13269 // To send delta requests for semantic tokens, the previous tokens
13270 // need to be kept between buffer changes.
13271 let semantic_tokens = lsp_data.semantic_tokens.take();
13272 *lsp_data = BufferLspData::new(buffer, cx);
13273 lsp_data.semantic_tokens = semantic_tokens;
13274 }
13275 lsp_data
13276 }
13277}
13278
13279// Registration with registerOptions as null, should fallback to true.
13280// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13281fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13282 reg: lsp::Registration,
13283) -> Result<OneOf<bool, T>> {
13284 Ok(match reg.register_options {
13285 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13286 None => OneOf::Left(true),
13287 })
13288}
13289
13290fn subscribe_to_binary_statuses(
13291 languages: &Arc<LanguageRegistry>,
13292 cx: &mut Context<'_, LspStore>,
13293) -> Task<()> {
13294 let mut server_statuses = languages.language_server_binary_statuses();
13295 cx.spawn(async move |lsp_store, cx| {
13296 while let Some((server_name, binary_status)) = server_statuses.next().await {
13297 if lsp_store
13298 .update(cx, |_, cx| {
13299 let mut message = None;
13300 let binary_status = match binary_status {
13301 BinaryStatus::None => proto::ServerBinaryStatus::None,
13302 BinaryStatus::CheckingForUpdate => {
13303 proto::ServerBinaryStatus::CheckingForUpdate
13304 }
13305 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13306 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13307 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13308 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13309 BinaryStatus::Failed { error } => {
13310 message = Some(error);
13311 proto::ServerBinaryStatus::Failed
13312 }
13313 };
13314 cx.emit(LspStoreEvent::LanguageServerUpdate {
13315 // Binary updates are about the binary that might not have any language server id at that point.
13316 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13317 language_server_id: LanguageServerId(0),
13318 name: Some(server_name),
13319 message: proto::update_language_server::Variant::StatusUpdate(
13320 proto::StatusUpdate {
13321 message,
13322 status: Some(proto::status_update::Status::Binary(
13323 binary_status as i32,
13324 )),
13325 },
13326 ),
13327 });
13328 })
13329 .is_err()
13330 {
13331 break;
13332 }
13333 }
13334 })
13335}
13336
13337fn lsp_workspace_diagnostics_refresh(
13338 registration_id: Option<String>,
13339 options: DiagnosticServerCapabilities,
13340 server: Arc<LanguageServer>,
13341 cx: &mut Context<'_, LspStore>,
13342) -> Option<WorkspaceRefreshTask> {
13343 let identifier = workspace_diagnostic_identifier(&options)?;
13344 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13345
13346 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13347 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13348 refresh_tx.try_send(()).ok();
13349
13350 let request_timeout = ProjectSettings::get_global(cx)
13351 .global_lsp_settings
13352 .get_request_timeout();
13353
13354 // 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.
13355 // This allows users to increase the duration if need be
13356 let timeout = if request_timeout != Duration::ZERO {
13357 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13358 } else {
13359 request_timeout
13360 };
13361
13362 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13363 let mut attempts = 0;
13364 let max_attempts = 50;
13365 let mut requests = 0;
13366
13367 loop {
13368 let Some(()) = refresh_rx.recv().await else {
13369 return;
13370 };
13371
13372 'request: loop {
13373 requests += 1;
13374 if attempts > max_attempts {
13375 log::error!(
13376 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13377 );
13378 return;
13379 }
13380 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13381 cx.background_executor()
13382 .timer(Duration::from_millis(backoff_millis))
13383 .await;
13384 attempts += 1;
13385
13386 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13387 lsp_store
13388 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13389 .into_iter()
13390 .filter_map(|(abs_path, result_id)| {
13391 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13392 Some(lsp::PreviousResultId {
13393 uri,
13394 value: result_id.to_string(),
13395 })
13396 })
13397 .collect()
13398 }) else {
13399 return;
13400 };
13401
13402 let token = if let Some(registration_id) = ®istration_id {
13403 format!(
13404 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13405 server.server_id(),
13406 )
13407 } else {
13408 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13409 };
13410
13411 progress_rx.try_recv().ok();
13412 let timer = server.request_timer(timeout).fuse();
13413 let progress = pin!(progress_rx.recv().fuse());
13414 let response_result = server
13415 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13416 lsp::WorkspaceDiagnosticParams {
13417 previous_result_ids,
13418 identifier: identifier.clone(),
13419 work_done_progress_params: Default::default(),
13420 partial_result_params: lsp::PartialResultParams {
13421 partial_result_token: Some(lsp::ProgressToken::String(token)),
13422 },
13423 },
13424 select(timer, progress).then(|either| match either {
13425 Either::Left((message, ..)) => ready(message).left_future(),
13426 Either::Right(..) => pending::<String>().right_future(),
13427 }),
13428 )
13429 .await;
13430
13431 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13432 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13433 match response_result {
13434 ConnectionResult::Timeout => {
13435 log::error!("Timeout during workspace diagnostics pull");
13436 continue 'request;
13437 }
13438 ConnectionResult::ConnectionReset => {
13439 log::error!("Server closed a workspace diagnostics pull request");
13440 continue 'request;
13441 }
13442 ConnectionResult::Result(Err(e)) => {
13443 log::error!("Error during workspace diagnostics pull: {e:#}");
13444 break 'request;
13445 }
13446 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13447 attempts = 0;
13448 if lsp_store
13449 .update(cx, |lsp_store, cx| {
13450 lsp_store.apply_workspace_diagnostic_report(
13451 server.server_id(),
13452 pulled_diagnostics,
13453 registration_id_shared.clone(),
13454 cx,
13455 )
13456 })
13457 .is_err()
13458 {
13459 return;
13460 }
13461 break 'request;
13462 }
13463 }
13464 }
13465 }
13466 });
13467
13468 Some(WorkspaceRefreshTask {
13469 refresh_tx,
13470 progress_tx,
13471 task: workspace_query_language_server,
13472 })
13473}
13474
13475fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13476 match &options {
13477 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13478 .identifier
13479 .as_deref()
13480 .map(SharedString::new),
13481 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13482 let diagnostic_options = ®istration_options.diagnostic_options;
13483 diagnostic_options
13484 .identifier
13485 .as_deref()
13486 .map(SharedString::new)
13487 }
13488 }
13489}
13490
13491fn workspace_diagnostic_identifier(
13492 options: &DiagnosticServerCapabilities,
13493) -> Option<Option<String>> {
13494 match &options {
13495 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13496 if !diagnostic_options.workspace_diagnostics {
13497 return None;
13498 }
13499 Some(diagnostic_options.identifier.clone())
13500 }
13501 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13502 let diagnostic_options = ®istration_options.diagnostic_options;
13503 if !diagnostic_options.workspace_diagnostics {
13504 return None;
13505 }
13506 Some(diagnostic_options.identifier.clone())
13507 }
13508 }
13509}
13510
13511fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13512 let CompletionSource::BufferWord {
13513 word_range,
13514 resolved,
13515 } = &mut completion.source
13516 else {
13517 return;
13518 };
13519 if *resolved {
13520 return;
13521 }
13522
13523 if completion.new_text
13524 != snapshot
13525 .text_for_range(word_range.clone())
13526 .collect::<String>()
13527 {
13528 return;
13529 }
13530
13531 let mut offset = 0;
13532 for chunk in snapshot.chunks(
13533 word_range.clone(),
13534 LanguageAwareStyling {
13535 tree_sitter: true,
13536 diagnostics: true,
13537 },
13538 ) {
13539 let end_offset = offset + chunk.text.len();
13540 if let Some(highlight_id) = chunk.syntax_highlight_id {
13541 completion
13542 .label
13543 .runs
13544 .push((offset..end_offset, highlight_id));
13545 }
13546 offset = end_offset;
13547 }
13548 *resolved = true;
13549}
13550
13551impl EventEmitter<LspStoreEvent> for LspStore {}
13552
13553fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13554 hover
13555 .contents
13556 .retain(|hover_block| !hover_block.text.trim().is_empty());
13557 if hover.contents.is_empty() {
13558 None
13559 } else {
13560 Some(hover)
13561 }
13562}
13563
13564async fn populate_labels_for_completions(
13565 new_completions: Vec<CoreCompletion>,
13566 language: Option<Arc<Language>>,
13567 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13568) -> Vec<Completion> {
13569 let lsp_completions = new_completions
13570 .iter()
13571 .filter_map(|new_completion| {
13572 new_completion
13573 .source
13574 .lsp_completion(true)
13575 .map(|lsp_completion| lsp_completion.into_owned())
13576 })
13577 .collect::<Vec<_>>();
13578
13579 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13580 lsp_adapter
13581 .labels_for_completions(&lsp_completions, language)
13582 .await
13583 .log_err()
13584 .unwrap_or_default()
13585 } else {
13586 Vec::new()
13587 }
13588 .into_iter()
13589 .fuse();
13590
13591 let mut completions = Vec::new();
13592 for completion in new_completions {
13593 match completion.source.lsp_completion(true) {
13594 Some(lsp_completion) => {
13595 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13596
13597 let mut label = labels.next().flatten().unwrap_or_else(|| {
13598 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13599 });
13600 ensure_uniform_list_compatible_label(&mut label);
13601 completions.push(Completion {
13602 label,
13603 documentation,
13604 replace_range: completion.replace_range,
13605 new_text: completion.new_text,
13606 insert_text_mode: lsp_completion.insert_text_mode,
13607 source: completion.source,
13608 icon_path: None,
13609 confirm: None,
13610 match_start: None,
13611 snippet_deduplication_key: None,
13612 });
13613 }
13614 None => {
13615 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13616 ensure_uniform_list_compatible_label(&mut label);
13617 completions.push(Completion {
13618 label,
13619 documentation: None,
13620 replace_range: completion.replace_range,
13621 new_text: completion.new_text,
13622 source: completion.source,
13623 insert_text_mode: None,
13624 icon_path: None,
13625 confirm: None,
13626 match_start: None,
13627 snippet_deduplication_key: None,
13628 });
13629 }
13630 }
13631 }
13632 completions
13633}
13634
13635#[derive(Debug)]
13636pub enum LanguageServerToQuery {
13637 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13638 FirstCapable,
13639 /// Query a specific language server.
13640 Other(LanguageServerId),
13641}
13642
13643#[derive(Default)]
13644struct RenamePathsWatchedForServer {
13645 did_rename: Vec<RenameActionPredicate>,
13646 will_rename: Vec<RenameActionPredicate>,
13647}
13648
13649impl RenamePathsWatchedForServer {
13650 fn with_did_rename_patterns(
13651 mut self,
13652 did_rename: Option<&FileOperationRegistrationOptions>,
13653 ) -> Self {
13654 if let Some(did_rename) = did_rename {
13655 self.did_rename = did_rename
13656 .filters
13657 .iter()
13658 .filter_map(|filter| filter.try_into().log_err())
13659 .collect();
13660 }
13661 self
13662 }
13663 fn with_will_rename_patterns(
13664 mut self,
13665 will_rename: Option<&FileOperationRegistrationOptions>,
13666 ) -> Self {
13667 if let Some(will_rename) = will_rename {
13668 self.will_rename = will_rename
13669 .filters
13670 .iter()
13671 .filter_map(|filter| filter.try_into().log_err())
13672 .collect();
13673 }
13674 self
13675 }
13676
13677 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13678 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13679 }
13680 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13681 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13682 }
13683}
13684
13685impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13686 type Error = globset::Error;
13687 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13688 Ok(Self {
13689 kind: ops.pattern.matches.clone(),
13690 glob: GlobBuilder::new(&ops.pattern.glob)
13691 .case_insensitive(
13692 ops.pattern
13693 .options
13694 .as_ref()
13695 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13696 )
13697 .build()?
13698 .compile_matcher(),
13699 })
13700 }
13701}
13702struct RenameActionPredicate {
13703 glob: GlobMatcher,
13704 kind: Option<FileOperationPatternKind>,
13705}
13706
13707impl RenameActionPredicate {
13708 // Returns true if language server should be notified
13709 fn eval(&self, path: &str, is_dir: bool) -> bool {
13710 self.kind.as_ref().is_none_or(|kind| {
13711 let expected_kind = if is_dir {
13712 FileOperationPatternKind::Folder
13713 } else {
13714 FileOperationPatternKind::File
13715 };
13716 kind == &expected_kind
13717 }) && self.glob.is_match(path)
13718 }
13719}
13720
13721#[derive(Default)]
13722struct LanguageServerWatchedPaths {
13723 worktree_paths: HashMap<WorktreeId, GlobSet>,
13724 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13725}
13726
13727#[derive(Default)]
13728struct LanguageServerWatchedPathsBuilder {
13729 worktree_paths: HashMap<WorktreeId, GlobSet>,
13730 abs_paths: HashMap<Arc<Path>, GlobSet>,
13731}
13732
13733impl LanguageServerWatchedPathsBuilder {
13734 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13735 self.worktree_paths.insert(worktree_id, glob_set);
13736 }
13737 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13738 self.abs_paths.insert(path, glob_set);
13739 }
13740 fn build(
13741 self,
13742 fs: Arc<dyn Fs>,
13743 language_server_id: LanguageServerId,
13744 cx: &mut Context<LspStore>,
13745 ) -> LanguageServerWatchedPaths {
13746 let lsp_store = cx.weak_entity();
13747
13748 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13749 let abs_paths = self
13750 .abs_paths
13751 .into_iter()
13752 .map(|(abs_path, globset)| {
13753 let task = cx.spawn({
13754 let abs_path = abs_path.clone();
13755 let fs = fs.clone();
13756
13757 let lsp_store = lsp_store.clone();
13758 async move |_, cx| {
13759 maybe!(async move {
13760 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13761 while let Some(update) = push_updates.0.next().await {
13762 let action = lsp_store
13763 .update(cx, |this, _| {
13764 let Some(local) = this.as_local() else {
13765 return ControlFlow::Break(());
13766 };
13767 let Some(watcher) = local
13768 .language_server_watched_paths
13769 .get(&language_server_id)
13770 else {
13771 return ControlFlow::Break(());
13772 };
13773 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13774 "Watched abs path is not registered with a watcher",
13775 );
13776 let matching_entries = update
13777 .into_iter()
13778 .filter(|event| globs.is_match(&event.path))
13779 .collect::<Vec<_>>();
13780 this.lsp_notify_abs_paths_changed(
13781 language_server_id,
13782 matching_entries,
13783 );
13784 ControlFlow::Continue(())
13785 })
13786 .ok()?;
13787
13788 if action.is_break() {
13789 break;
13790 }
13791 }
13792 Some(())
13793 })
13794 .await;
13795 }
13796 });
13797 (abs_path, (globset, task))
13798 })
13799 .collect();
13800 LanguageServerWatchedPaths {
13801 worktree_paths: self.worktree_paths,
13802 abs_paths,
13803 }
13804 }
13805}
13806
13807struct LspBufferSnapshot {
13808 version: i32,
13809 snapshot: TextBufferSnapshot,
13810}
13811
13812/// A prompt requested by LSP server.
13813#[derive(Clone, Debug)]
13814pub struct LanguageServerPromptRequest {
13815 pub id: usize,
13816 pub level: PromptLevel,
13817 pub message: String,
13818 pub actions: Vec<MessageActionItem>,
13819 pub lsp_name: String,
13820 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13821}
13822
13823impl LanguageServerPromptRequest {
13824 pub fn new(
13825 level: PromptLevel,
13826 message: String,
13827 actions: Vec<MessageActionItem>,
13828 lsp_name: String,
13829 response_channel: smol::channel::Sender<MessageActionItem>,
13830 ) -> Self {
13831 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13832 LanguageServerPromptRequest {
13833 id,
13834 level,
13835 message,
13836 actions,
13837 lsp_name,
13838 response_channel,
13839 }
13840 }
13841 pub async fn respond(self, index: usize) -> Option<()> {
13842 if let Some(response) = self.actions.into_iter().nth(index) {
13843 self.response_channel.send(response).await.ok()
13844 } else {
13845 None
13846 }
13847 }
13848
13849 #[cfg(any(test, feature = "test-support"))]
13850 pub fn test(
13851 level: PromptLevel,
13852 message: String,
13853 actions: Vec<MessageActionItem>,
13854 lsp_name: String,
13855 ) -> Self {
13856 let (tx, _rx) = smol::channel::unbounded();
13857 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13858 }
13859}
13860impl PartialEq for LanguageServerPromptRequest {
13861 fn eq(&self, other: &Self) -> bool {
13862 self.message == other.message && self.actions == other.actions
13863 }
13864}
13865
13866#[derive(Clone, Debug, PartialEq)]
13867pub enum LanguageServerLogType {
13868 Log(MessageType),
13869 Trace { verbose_info: Option<String> },
13870 Rpc { received: bool },
13871}
13872
13873impl LanguageServerLogType {
13874 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13875 match self {
13876 Self::Log(log_type) => {
13877 use proto::log_message::LogLevel;
13878 let level = match *log_type {
13879 MessageType::ERROR => LogLevel::Error,
13880 MessageType::WARNING => LogLevel::Warning,
13881 MessageType::INFO => LogLevel::Info,
13882 MessageType::LOG => LogLevel::Log,
13883 other => {
13884 log::warn!("Unknown lsp log message type: {other:?}");
13885 LogLevel::Log
13886 }
13887 };
13888 proto::language_server_log::LogType::Log(proto::LogMessage {
13889 level: level as i32,
13890 })
13891 }
13892 Self::Trace { verbose_info } => {
13893 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13894 verbose_info: verbose_info.to_owned(),
13895 })
13896 }
13897 Self::Rpc { received } => {
13898 let kind = if *received {
13899 proto::rpc_message::Kind::Received
13900 } else {
13901 proto::rpc_message::Kind::Sent
13902 };
13903 let kind = kind as i32;
13904 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13905 }
13906 }
13907 }
13908
13909 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13910 use proto::log_message::LogLevel;
13911 use proto::rpc_message;
13912 match log_type {
13913 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13914 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13915 LogLevel::Error => MessageType::ERROR,
13916 LogLevel::Warning => MessageType::WARNING,
13917 LogLevel::Info => MessageType::INFO,
13918 LogLevel::Log => MessageType::LOG,
13919 },
13920 ),
13921 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13922 verbose_info: trace_message.verbose_info,
13923 },
13924 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13925 received: match rpc_message::Kind::from_i32(message.kind)
13926 .unwrap_or(rpc_message::Kind::Received)
13927 {
13928 rpc_message::Kind::Received => true,
13929 rpc_message::Kind::Sent => false,
13930 },
13931 },
13932 }
13933 }
13934}
13935
13936pub struct WorkspaceRefreshTask {
13937 refresh_tx: mpsc::Sender<()>,
13938 progress_tx: mpsc::Sender<()>,
13939 #[allow(dead_code)]
13940 task: Task<()>,
13941}
13942
13943pub enum LanguageServerState {
13944 Starting {
13945 startup: Task<Option<Arc<LanguageServer>>>,
13946 /// List of language servers that will be added to the workspace once it's initialization completes.
13947 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13948 },
13949
13950 Running {
13951 adapter: Arc<CachedLspAdapter>,
13952 server: Arc<LanguageServer>,
13953 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13954 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13955 },
13956}
13957
13958impl LanguageServerState {
13959 fn add_workspace_folder(&self, uri: Uri) {
13960 match self {
13961 LanguageServerState::Starting {
13962 pending_workspace_folders,
13963 ..
13964 } => {
13965 pending_workspace_folders.lock().insert(uri);
13966 }
13967 LanguageServerState::Running { server, .. } => {
13968 server.add_workspace_folder(uri);
13969 }
13970 }
13971 }
13972 fn _remove_workspace_folder(&self, uri: Uri) {
13973 match self {
13974 LanguageServerState::Starting {
13975 pending_workspace_folders,
13976 ..
13977 } => {
13978 pending_workspace_folders.lock().remove(&uri);
13979 }
13980 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13981 }
13982 }
13983}
13984
13985impl std::fmt::Debug for LanguageServerState {
13986 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13987 match self {
13988 LanguageServerState::Starting { .. } => {
13989 f.debug_struct("LanguageServerState::Starting").finish()
13990 }
13991 LanguageServerState::Running { .. } => {
13992 f.debug_struct("LanguageServerState::Running").finish()
13993 }
13994 }
13995 }
13996}
13997
13998#[derive(Clone, Debug, Serialize)]
13999pub struct LanguageServerProgress {
14000 pub is_disk_based_diagnostics_progress: bool,
14001 pub is_cancellable: bool,
14002 pub title: Option<String>,
14003 pub message: Option<String>,
14004 pub percentage: Option<usize>,
14005 #[serde(skip_serializing)]
14006 pub last_update_at: Instant,
14007}
14008
14009#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14010pub struct DiagnosticSummary {
14011 pub error_count: usize,
14012 pub warning_count: usize,
14013}
14014
14015impl DiagnosticSummary {
14016 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14017 let mut this = Self {
14018 error_count: 0,
14019 warning_count: 0,
14020 };
14021
14022 for entry in diagnostics {
14023 if entry.diagnostic.is_primary {
14024 match entry.diagnostic.severity {
14025 DiagnosticSeverity::ERROR => this.error_count += 1,
14026 DiagnosticSeverity::WARNING => this.warning_count += 1,
14027 _ => {}
14028 }
14029 }
14030 }
14031
14032 this
14033 }
14034
14035 pub fn is_empty(&self) -> bool {
14036 self.error_count == 0 && self.warning_count == 0
14037 }
14038
14039 pub fn to_proto(
14040 self,
14041 language_server_id: LanguageServerId,
14042 path: &RelPath,
14043 ) -> proto::DiagnosticSummary {
14044 proto::DiagnosticSummary {
14045 path: path.to_proto(),
14046 language_server_id: language_server_id.0 as u64,
14047 error_count: self.error_count as u32,
14048 warning_count: self.warning_count as u32,
14049 }
14050 }
14051}
14052
14053#[derive(Clone, Debug)]
14054pub enum CompletionDocumentation {
14055 /// There is no documentation for this completion.
14056 Undocumented,
14057 /// A single line of documentation.
14058 SingleLine(SharedString),
14059 /// Multiple lines of plain text documentation.
14060 MultiLinePlainText(SharedString),
14061 /// Markdown documentation.
14062 MultiLineMarkdown(SharedString),
14063 /// Both single line and multiple lines of plain text documentation.
14064 SingleLineAndMultiLinePlainText {
14065 single_line: SharedString,
14066 plain_text: Option<SharedString>,
14067 },
14068}
14069
14070impl CompletionDocumentation {
14071 #[cfg(any(test, feature = "test-support"))]
14072 pub fn text(&self) -> SharedString {
14073 match self {
14074 CompletionDocumentation::Undocumented => "".into(),
14075 CompletionDocumentation::SingleLine(s) => s.clone(),
14076 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14077 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14078 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14079 single_line.clone()
14080 }
14081 }
14082 }
14083}
14084
14085impl From<lsp::Documentation> for CompletionDocumentation {
14086 fn from(docs: lsp::Documentation) -> Self {
14087 match docs {
14088 lsp::Documentation::String(text) => {
14089 if text.lines().count() <= 1 {
14090 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14091 } else {
14092 CompletionDocumentation::MultiLinePlainText(text.into())
14093 }
14094 }
14095
14096 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14097 lsp::MarkupKind::PlainText => {
14098 if value.lines().count() <= 1 {
14099 CompletionDocumentation::SingleLine(value.into())
14100 } else {
14101 CompletionDocumentation::MultiLinePlainText(value.into())
14102 }
14103 }
14104
14105 lsp::MarkupKind::Markdown => {
14106 CompletionDocumentation::MultiLineMarkdown(value.into())
14107 }
14108 },
14109 }
14110 }
14111}
14112
14113pub enum ResolvedHint {
14114 Resolved(InlayHint),
14115 Resolving(Shared<Task<()>>),
14116}
14117
14118pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14119 glob.components()
14120 .take_while(|component| match component {
14121 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14122 _ => true,
14123 })
14124 .collect()
14125}
14126
14127pub struct SshLspAdapter {
14128 name: LanguageServerName,
14129 binary: LanguageServerBinary,
14130 initialization_options: Option<String>,
14131 code_action_kinds: Option<Vec<CodeActionKind>>,
14132}
14133
14134impl SshLspAdapter {
14135 pub fn new(
14136 name: LanguageServerName,
14137 binary: LanguageServerBinary,
14138 initialization_options: Option<String>,
14139 code_action_kinds: Option<String>,
14140 ) -> Self {
14141 Self {
14142 name,
14143 binary,
14144 initialization_options,
14145 code_action_kinds: code_action_kinds
14146 .as_ref()
14147 .and_then(|c| serde_json::from_str(c).ok()),
14148 }
14149 }
14150}
14151
14152impl LspInstaller for SshLspAdapter {
14153 type BinaryVersion = ();
14154 async fn check_if_user_installed(
14155 &self,
14156 _: &dyn LspAdapterDelegate,
14157 _: Option<Toolchain>,
14158 _: &AsyncApp,
14159 ) -> Option<LanguageServerBinary> {
14160 Some(self.binary.clone())
14161 }
14162
14163 async fn cached_server_binary(
14164 &self,
14165 _: PathBuf,
14166 _: &dyn LspAdapterDelegate,
14167 ) -> Option<LanguageServerBinary> {
14168 None
14169 }
14170
14171 async fn fetch_latest_server_version(
14172 &self,
14173 _: &dyn LspAdapterDelegate,
14174 _: bool,
14175 _: &mut AsyncApp,
14176 ) -> Result<()> {
14177 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14178 }
14179
14180 async fn fetch_server_binary(
14181 &self,
14182 _: (),
14183 _: PathBuf,
14184 _: &dyn LspAdapterDelegate,
14185 ) -> Result<LanguageServerBinary> {
14186 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14187 }
14188}
14189
14190#[async_trait(?Send)]
14191impl LspAdapter for SshLspAdapter {
14192 fn name(&self) -> LanguageServerName {
14193 self.name.clone()
14194 }
14195
14196 async fn initialization_options(
14197 self: Arc<Self>,
14198 _: &Arc<dyn LspAdapterDelegate>,
14199 _: &mut AsyncApp,
14200 ) -> Result<Option<serde_json::Value>> {
14201 let Some(options) = &self.initialization_options else {
14202 return Ok(None);
14203 };
14204 let result = serde_json::from_str(options)?;
14205 Ok(result)
14206 }
14207
14208 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14209 self.code_action_kinds.clone()
14210 }
14211}
14212
14213pub fn language_server_settings<'a>(
14214 delegate: &'a dyn LspAdapterDelegate,
14215 language: &LanguageServerName,
14216 cx: &'a App,
14217) -> Option<&'a LspSettings> {
14218 language_server_settings_for(
14219 SettingsLocation {
14220 worktree_id: delegate.worktree_id(),
14221 path: RelPath::empty(),
14222 },
14223 language,
14224 cx,
14225 )
14226}
14227
14228pub fn language_server_settings_for<'a>(
14229 location: SettingsLocation<'a>,
14230 language: &LanguageServerName,
14231 cx: &'a App,
14232) -> Option<&'a LspSettings> {
14233 ProjectSettings::get(Some(location), cx).lsp.get(language)
14234}
14235
14236pub struct LocalLspAdapterDelegate {
14237 lsp_store: WeakEntity<LspStore>,
14238 worktree: worktree::Snapshot,
14239 fs: Arc<dyn Fs>,
14240 http_client: Arc<dyn HttpClient>,
14241 language_registry: Arc<LanguageRegistry>,
14242 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14243}
14244
14245impl LocalLspAdapterDelegate {
14246 pub fn new(
14247 language_registry: Arc<LanguageRegistry>,
14248 environment: &Entity<ProjectEnvironment>,
14249 lsp_store: WeakEntity<LspStore>,
14250 worktree: &Entity<Worktree>,
14251 http_client: Arc<dyn HttpClient>,
14252 fs: Arc<dyn Fs>,
14253 cx: &mut App,
14254 ) -> Arc<Self> {
14255 let load_shell_env_task =
14256 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14257
14258 Arc::new(Self {
14259 lsp_store,
14260 worktree: worktree.read(cx).snapshot(),
14261 fs,
14262 http_client,
14263 language_registry,
14264 load_shell_env_task,
14265 })
14266 }
14267
14268 pub fn from_local_lsp(
14269 local: &LocalLspStore,
14270 worktree: &Entity<Worktree>,
14271 cx: &mut App,
14272 ) -> Arc<Self> {
14273 Self::new(
14274 local.languages.clone(),
14275 &local.environment,
14276 local.weak.clone(),
14277 worktree,
14278 local.http_client.clone(),
14279 local.fs.clone(),
14280 cx,
14281 )
14282 }
14283}
14284
14285#[async_trait]
14286impl LspAdapterDelegate for LocalLspAdapterDelegate {
14287 fn show_notification(&self, message: &str, cx: &mut App) {
14288 self.lsp_store
14289 .update(cx, |_, cx| {
14290 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14291 })
14292 .ok();
14293 }
14294
14295 fn http_client(&self) -> Arc<dyn HttpClient> {
14296 self.http_client.clone()
14297 }
14298
14299 fn worktree_id(&self) -> WorktreeId {
14300 self.worktree.id()
14301 }
14302
14303 fn worktree_root_path(&self) -> &Path {
14304 self.worktree.abs_path().as_ref()
14305 }
14306
14307 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14308 self.worktree.resolve_relative_path(path)
14309 }
14310
14311 async fn shell_env(&self) -> HashMap<String, String> {
14312 let task = self.load_shell_env_task.clone();
14313 task.await.unwrap_or_default()
14314 }
14315
14316 async fn npm_package_installed_version(
14317 &self,
14318 package_name: &str,
14319 ) -> Result<Option<(PathBuf, Version)>> {
14320 let local_package_directory = self.worktree_root_path();
14321 let node_modules_directory = local_package_directory.join("node_modules");
14322
14323 if let Some(version) =
14324 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14325 {
14326 return Ok(Some((node_modules_directory, version)));
14327 }
14328 let Some(npm) = self.which("npm".as_ref()).await else {
14329 log::warn!(
14330 "Failed to find npm executable for {:?}",
14331 local_package_directory
14332 );
14333 return Ok(None);
14334 };
14335
14336 let env = self.shell_env().await;
14337 let output = util::command::new_command(&npm)
14338 .args(["root", "-g"])
14339 .envs(env)
14340 .current_dir(local_package_directory)
14341 .output()
14342 .await?;
14343 let global_node_modules =
14344 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14345
14346 if let Some(version) =
14347 read_package_installed_version(global_node_modules.clone(), package_name).await?
14348 {
14349 return Ok(Some((global_node_modules, version)));
14350 }
14351 return Ok(None);
14352 }
14353
14354 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14355 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14356 if self.fs.is_file(&worktree_abs_path).await {
14357 worktree_abs_path.pop();
14358 }
14359
14360 let env = self.shell_env().await;
14361
14362 let shell_path = env.get("PATH").cloned();
14363
14364 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14365 }
14366
14367 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14368 let mut working_dir = self.worktree_root_path().to_path_buf();
14369 if self.fs.is_file(&working_dir).await {
14370 working_dir.pop();
14371 }
14372 let output = util::command::new_command(&command.path)
14373 .args(command.arguments)
14374 .envs(command.env.clone().unwrap_or_default())
14375 .current_dir(working_dir)
14376 .output()
14377 .await?;
14378
14379 anyhow::ensure!(
14380 output.status.success(),
14381 "{}, stdout: {:?}, stderr: {:?}",
14382 output.status,
14383 String::from_utf8_lossy(&output.stdout),
14384 String::from_utf8_lossy(&output.stderr)
14385 );
14386 Ok(())
14387 }
14388
14389 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14390 self.language_registry
14391 .update_lsp_binary_status(server_name, status);
14392 }
14393
14394 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14395 self.language_registry
14396 .all_lsp_adapters()
14397 .into_iter()
14398 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14399 .collect()
14400 }
14401
14402 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14403 let dir = self.language_registry.language_server_download_dir(name)?;
14404
14405 if !dir.exists() {
14406 smol::fs::create_dir_all(&dir)
14407 .await
14408 .context("failed to create container directory")
14409 .log_err()?;
14410 }
14411
14412 Some(dir)
14413 }
14414
14415 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14416 let entry = self
14417 .worktree
14418 .entry_for_path(path)
14419 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14420 let abs_path = self.worktree.absolutize(&entry.path);
14421 self.fs.load(&abs_path).await
14422 }
14423}
14424
14425async fn populate_labels_for_symbols(
14426 symbols: Vec<CoreSymbol>,
14427 language_registry: &Arc<LanguageRegistry>,
14428 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14429 output: &mut Vec<Symbol>,
14430) {
14431 #[allow(clippy::mutable_key_type)]
14432 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14433
14434 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14435 for symbol in symbols {
14436 let Some(file_name) = symbol.path.file_name() else {
14437 continue;
14438 };
14439 let language = language_registry
14440 .load_language_for_file_path(Path::new(file_name))
14441 .await
14442 .ok()
14443 .or_else(|| {
14444 unknown_paths.insert(file_name.into());
14445 None
14446 });
14447 symbols_by_language
14448 .entry(language)
14449 .or_default()
14450 .push(symbol);
14451 }
14452
14453 for unknown_path in unknown_paths {
14454 log::info!("no language found for symbol in file {unknown_path:?}");
14455 }
14456
14457 let mut label_params = Vec::new();
14458 for (language, mut symbols) in symbols_by_language {
14459 label_params.clear();
14460 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14461 name: mem::take(&mut symbol.name),
14462 kind: symbol.kind,
14463 container_name: symbol.container_name.take(),
14464 }));
14465
14466 let mut labels = Vec::new();
14467 if let Some(language) = language {
14468 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14469 language_registry
14470 .lsp_adapters(&language.name())
14471 .first()
14472 .cloned()
14473 });
14474 if let Some(lsp_adapter) = lsp_adapter {
14475 labels = lsp_adapter
14476 .labels_for_symbols(&label_params, &language)
14477 .await
14478 .log_err()
14479 .unwrap_or_default();
14480 }
14481 }
14482
14483 for (
14484 (
14485 symbol,
14486 language::Symbol {
14487 name,
14488 container_name,
14489 ..
14490 },
14491 ),
14492 label,
14493 ) in symbols
14494 .into_iter()
14495 .zip(label_params.drain(..))
14496 .zip(labels.into_iter().chain(iter::repeat(None)))
14497 {
14498 output.push(Symbol {
14499 language_server_name: symbol.language_server_name,
14500 source_worktree_id: symbol.source_worktree_id,
14501 source_language_server_id: symbol.source_language_server_id,
14502 path: symbol.path,
14503 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14504 name,
14505 kind: symbol.kind,
14506 range: symbol.range,
14507 container_name,
14508 });
14509 }
14510 }
14511}
14512
14513pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14514 text.lines()
14515 .map(|line| line.trim())
14516 .filter(|line| !line.is_empty())
14517 .join(separator)
14518}
14519
14520fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14521 match server.capabilities().text_document_sync.as_ref()? {
14522 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14523 // Server wants didSave but didn't specify includeText.
14524 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14525 // Server doesn't want didSave at all.
14526 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14527 // Server provided SaveOptions.
14528 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14529 Some(save_options.include_text.unwrap_or(false))
14530 }
14531 },
14532 // We do not have any save info. Kind affects didChange only.
14533 lsp::TextDocumentSyncCapability::Kind(_) => None,
14534 }
14535}
14536
14537/// Completion items are displayed in a `UniformList`.
14538/// Usually, those items are single-line strings, but in LSP responses,
14539/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14540/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14541/// 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,
14542/// breaking the completions menu presentation.
14543///
14544/// 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.
14545pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14546 let mut new_text = String::with_capacity(label.text.len());
14547 let mut offset_map = vec![0; label.text.len() + 1];
14548 let mut last_char_was_space = false;
14549 let mut new_idx = 0;
14550 let chars = label.text.char_indices().fuse();
14551 let mut newlines_removed = false;
14552
14553 for (idx, c) in chars {
14554 offset_map[idx] = new_idx;
14555
14556 match c {
14557 '\n' if last_char_was_space => {
14558 newlines_removed = true;
14559 }
14560 '\t' | ' ' if last_char_was_space => {}
14561 '\n' if !last_char_was_space => {
14562 new_text.push(' ');
14563 new_idx += 1;
14564 last_char_was_space = true;
14565 newlines_removed = true;
14566 }
14567 ' ' | '\t' => {
14568 new_text.push(' ');
14569 new_idx += 1;
14570 last_char_was_space = true;
14571 }
14572 _ => {
14573 new_text.push(c);
14574 new_idx += c.len_utf8();
14575 last_char_was_space = false;
14576 }
14577 }
14578 }
14579 offset_map[label.text.len()] = new_idx;
14580
14581 // Only modify the label if newlines were removed.
14582 if !newlines_removed {
14583 return;
14584 }
14585
14586 let last_index = new_idx;
14587 let mut run_ranges_errors = Vec::new();
14588 label.runs.retain_mut(|(range, _)| {
14589 match offset_map.get(range.start) {
14590 Some(&start) => range.start = start,
14591 None => {
14592 run_ranges_errors.push(range.clone());
14593 return false;
14594 }
14595 }
14596
14597 match offset_map.get(range.end) {
14598 Some(&end) => range.end = end,
14599 None => {
14600 run_ranges_errors.push(range.clone());
14601 range.end = last_index;
14602 }
14603 }
14604 true
14605 });
14606 if !run_ranges_errors.is_empty() {
14607 log::error!(
14608 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14609 label.text
14610 );
14611 }
14612
14613 let mut wrong_filter_range = None;
14614 if label.filter_range == (0..label.text.len()) {
14615 label.filter_range = 0..new_text.len();
14616 } else {
14617 let mut original_filter_range = Some(label.filter_range.clone());
14618 match offset_map.get(label.filter_range.start) {
14619 Some(&start) => label.filter_range.start = start,
14620 None => {
14621 wrong_filter_range = original_filter_range.take();
14622 label.filter_range.start = last_index;
14623 }
14624 }
14625
14626 match offset_map.get(label.filter_range.end) {
14627 Some(&end) => label.filter_range.end = end,
14628 None => {
14629 wrong_filter_range = original_filter_range.take();
14630 label.filter_range.end = last_index;
14631 }
14632 }
14633 }
14634 if let Some(wrong_filter_range) = wrong_filter_range {
14635 log::error!(
14636 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14637 label.text
14638 );
14639 }
14640
14641 label.text = new_text;
14642}
14643
14644/// Apply edits to the buffer that will become part of the formatting transaction.
14645/// Fails if the buffer has been edited since the start of that transaction.
14646fn extend_formatting_transaction(
14647 buffer: &FormattableBuffer,
14648 formatting_transaction_id: text::TransactionId,
14649 cx: &mut AsyncApp,
14650 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14651) -> anyhow::Result<()> {
14652 buffer.handle.update(cx, |buffer, cx| {
14653 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14654 if last_transaction_id != Some(formatting_transaction_id) {
14655 anyhow::bail!("Buffer edited while formatting. Aborting")
14656 }
14657 buffer.start_transaction();
14658 operation(buffer, cx);
14659 if let Some(transaction_id) = buffer.end_transaction(cx) {
14660 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14661 }
14662 Ok(())
14663 })
14664}