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