1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 CodeLabelExt, Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff,
75 File as _, Language, LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate,
76 LspInstaller, ManifestDelegate, ManifestName, ModelineSettings, OffsetUtf16, Patch, PointUtf16,
77 TextBufferSnapshot, ToOffset, ToOffsetUtf16, ToPointUtf16, Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 },
81 modeline, point_to_lsp,
82 proto::{
83 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
84 serialize_anchor_range, serialize_version,
85 },
86 range_from_lsp, range_to_lsp,
87 row_chunk::RowChunk,
88};
89use lsp::{
90 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
91 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
92 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
93 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
94 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
95 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
96 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
97 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
98};
99use node_runtime::read_package_installed_version;
100use parking_lot::Mutex;
101use postage::{mpsc, sink::Sink, stream::Stream, watch};
102use rand::prelude::*;
103use rpc::{
104 AnyProtoClient, ErrorCode, ErrorExt as _,
105 proto::{LspRequestId, LspRequestMessage as _},
106};
107use semver::Version;
108use serde::Serialize;
109use serde_json::Value;
110use settings::{Settings, SettingsLocation, SettingsStore};
111use sha2::{Digest, Sha256};
112use snippet::Snippet;
113use std::{
114 any::TypeId,
115 borrow::Cow,
116 cell::RefCell,
117 cmp::{Ordering, Reverse},
118 collections::{VecDeque, hash_map},
119 convert::TryInto,
120 ffi::OsStr,
121 future::ready,
122 iter, mem,
123 ops::{ControlFlow, Range},
124 path::{self, Path, PathBuf},
125 pin::pin,
126 rc::Rc,
127 sync::{
128 Arc,
129 atomic::{self, AtomicUsize},
130 },
131 time::{Duration, Instant},
132 vec,
133};
134use sum_tree::Dimensions;
135use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
136
137use util::{
138 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
139 paths::{PathStyle, SanitizedPath, UrlExt},
140 post_inc,
141 redact::redact_command,
142 rel_path::RelPath,
143};
144
145pub use document_colors::DocumentColors;
146pub use folding_ranges::LspFoldingRange;
147pub use fs::*;
148pub use language::Location;
149pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
150#[cfg(any(test, feature = "test-support"))]
151pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
152#[cfg(any(test, feature = "test-support"))]
153pub use prettier::RANGE_FORMAT_SUFFIX as TEST_PRETTIER_RANGE_FORMAT_SUFFIX;
154pub use semantic_tokens::{
155 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
156};
157
158pub use worktree::{
159 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
160 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
161};
162
163const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
164pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
165const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
166const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
167static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
168
169#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
170pub enum ProgressToken {
171 Number(i32),
172 String(SharedString),
173}
174
175impl std::fmt::Display for ProgressToken {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 Self::Number(number) => write!(f, "{number}"),
179 Self::String(string) => write!(f, "{string}"),
180 }
181 }
182}
183
184impl ProgressToken {
185 fn from_lsp(value: lsp::NumberOrString) -> Self {
186 match value {
187 lsp::NumberOrString::Number(number) => Self::Number(number),
188 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
189 }
190 }
191
192 fn to_lsp(&self) -> lsp::NumberOrString {
193 match self {
194 Self::Number(number) => lsp::NumberOrString::Number(*number),
195 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
196 }
197 }
198
199 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
200 Some(match value.value? {
201 proto::progress_token::Value::Number(number) => Self::Number(number),
202 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
203 })
204 }
205
206 fn to_proto(&self) -> proto::ProgressToken {
207 proto::ProgressToken {
208 value: Some(match self {
209 Self::Number(number) => proto::progress_token::Value::Number(*number),
210 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
211 }),
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum FormatTrigger {
218 Save,
219 Manual,
220}
221
222pub enum LspFormatTarget {
223 Buffers,
224 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
229
230struct OpenLspBuffer(Entity<Buffer>);
231
232impl FormatTrigger {
233 fn from_proto(value: i32) -> FormatTrigger {
234 match value {
235 0 => FormatTrigger::Save,
236 1 => FormatTrigger::Manual,
237 _ => FormatTrigger::Save,
238 }
239 }
240}
241
242#[derive(Clone)]
243struct UnifiedLanguageServer {
244 id: LanguageServerId,
245 project_roots: HashSet<Arc<RelPath>>,
246}
247
248/// Settings that affect language server identity.
249///
250/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
251/// updated via `workspace/didChangeConfiguration` without restarting the server.
252#[derive(Clone, Debug, Hash, PartialEq, Eq)]
253struct LanguageServerSeedSettings {
254 binary: Option<BinarySettings>,
255 initialization_options: Option<serde_json::Value>,
256}
257
258#[derive(Clone, Debug, Hash, PartialEq, Eq)]
259struct LanguageServerSeed {
260 worktree_id: WorktreeId,
261 name: LanguageServerName,
262 toolchain: Option<Toolchain>,
263 settings: LanguageServerSeedSettings,
264}
265
266#[derive(Debug)]
267pub struct DocumentDiagnosticsUpdate<'a, D> {
268 pub diagnostics: D,
269 pub result_id: Option<SharedString>,
270 pub registration_id: Option<SharedString>,
271 pub server_id: LanguageServerId,
272 pub disk_based_sources: Cow<'a, [String]>,
273}
274
275pub struct DocumentDiagnostics {
276 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
277 document_abs_path: PathBuf,
278 version: Option<i32>,
279}
280
281#[derive(Default, Debug)]
282struct DynamicRegistrations {
283 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
284 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
285}
286
287pub struct LocalLspStore {
288 weak: WeakEntity<LspStore>,
289 pub worktree_store: Entity<WorktreeStore>,
290 toolchain_store: Entity<LocalToolchainStore>,
291 http_client: Arc<dyn HttpClient>,
292 environment: Entity<ProjectEnvironment>,
293 fs: Arc<dyn Fs>,
294 languages: Arc<LanguageRegistry>,
295 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
296 yarn: Entity<YarnPathStore>,
297 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
298 buffers_being_formatted: HashSet<BufferId>,
299 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
300 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
301 watched_manifest_filenames: HashSet<ManifestName>,
302 language_server_paths_watched_for_rename:
303 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
304 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
305 supplementary_language_servers:
306 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
307 prettier_store: Entity<PrettierStore>,
308 next_diagnostic_group_id: usize,
309 diagnostics: HashMap<
310 WorktreeId,
311 HashMap<
312 Arc<RelPath>,
313 Vec<(
314 LanguageServerId,
315 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
316 )>,
317 >,
318 >,
319 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
320 _subscription: gpui::Subscription,
321 lsp_tree: LanguageServerTree,
322 registered_buffers: HashMap<BufferId, usize>,
323 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
324 buffer_pull_diagnostics_result_ids: HashMap<
325 LanguageServerId,
326 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
327 >,
328 workspace_pull_diagnostics_result_ids: HashMap<
329 LanguageServerId,
330 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
331 >,
332 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
333
334 buffers_to_refresh_hash_set: HashSet<BufferId>,
335 buffers_to_refresh_queue: VecDeque<BufferId>,
336 _background_diagnostics_worker: Shared<Task<()>>,
337}
338
339impl LocalLspStore {
340 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
341 pub fn running_language_server_for_id(
342 &self,
343 id: LanguageServerId,
344 ) -> Option<&Arc<LanguageServer>> {
345 let language_server_state = self.language_servers.get(&id)?;
346
347 match language_server_state {
348 LanguageServerState::Running { server, .. } => Some(server),
349 LanguageServerState::Starting { .. } => None,
350 }
351 }
352
353 fn get_or_insert_language_server(
354 &mut self,
355 worktree_handle: &Entity<Worktree>,
356 delegate: Arc<LocalLspAdapterDelegate>,
357 disposition: &Arc<LaunchDisposition>,
358 language_name: &LanguageName,
359 cx: &mut App,
360 ) -> LanguageServerId {
361 let key = LanguageServerSeed {
362 worktree_id: worktree_handle.read(cx).id(),
363 name: disposition.server_name.clone(),
364 settings: LanguageServerSeedSettings {
365 binary: disposition.settings.binary.clone(),
366 initialization_options: disposition.settings.initialization_options.clone(),
367 },
368 toolchain: disposition.toolchain.clone(),
369 };
370 if let Some(state) = self.language_server_ids.get_mut(&key) {
371 state.project_roots.insert(disposition.path.path.clone());
372 state.id
373 } else {
374 let adapter = self
375 .languages
376 .lsp_adapters(language_name)
377 .into_iter()
378 .find(|adapter| adapter.name() == disposition.server_name)
379 .expect("To find LSP adapter");
380 let new_language_server_id = self.start_language_server(
381 worktree_handle,
382 delegate,
383 adapter,
384 disposition.settings.clone(),
385 key.clone(),
386 language_name.clone(),
387 cx,
388 );
389 if let Some(state) = self.language_server_ids.get_mut(&key) {
390 state.project_roots.insert(disposition.path.path.clone());
391 } else {
392 debug_assert!(
393 false,
394 "Expected `start_language_server` to ensure that `key` exists in a map"
395 );
396 }
397 new_language_server_id
398 }
399 }
400
401 fn start_language_server(
402 &mut self,
403 worktree_handle: &Entity<Worktree>,
404 delegate: Arc<LocalLspAdapterDelegate>,
405 adapter: Arc<CachedLspAdapter>,
406 settings: Arc<LspSettings>,
407 key: LanguageServerSeed,
408 language_name: LanguageName,
409 cx: &mut App,
410 ) -> LanguageServerId {
411 let worktree = worktree_handle.read(cx);
412
413 let worktree_id = worktree.id();
414 let worktree_abs_path = worktree.abs_path();
415 let toolchain = key.toolchain.clone();
416 let override_options = settings.initialization_options.clone();
417
418 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
419
420 let server_id = self.languages.next_language_server_id();
421 log::trace!(
422 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
423 adapter.name.0
424 );
425
426 let wait_until_worktree_trust =
427 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
428 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
429 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
430 });
431 if can_trust {
432 self.restricted_worktrees_tasks.remove(&worktree_id);
433 None
434 } else {
435 match self.restricted_worktrees_tasks.entry(worktree_id) {
436 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
437 hash_map::Entry::Vacant(v) => {
438 let (mut tx, rx) = watch::channel::<bool>();
439 let lsp_store = self.weak.clone();
440 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
441 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
442 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
443 tx.blocking_send(true).ok();
444 lsp_store
445 .update(cx, |lsp_store, _| {
446 if let Some(local_lsp_store) =
447 lsp_store.as_local_mut()
448 {
449 local_lsp_store
450 .restricted_worktrees_tasks
451 .remove(&worktree_id);
452 }
453 })
454 .ok();
455 }
456 }
457 });
458 v.insert((subscription, rx.clone()));
459 Some(rx)
460 }
461 }
462 }
463 });
464 let update_binary_status = wait_until_worktree_trust.is_none();
465
466 let binary = self.get_language_server_binary(
467 worktree_abs_path.clone(),
468 adapter.clone(),
469 settings,
470 toolchain.clone(),
471 delegate.clone(),
472 true,
473 wait_until_worktree_trust,
474 cx,
475 );
476 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
477
478 let pending_server = cx.spawn({
479 let adapter = adapter.clone();
480 let server_name = adapter.name.clone();
481 let stderr_capture = stderr_capture.clone();
482 #[cfg(any(test, feature = "test-support"))]
483 let lsp_store = self.weak.clone();
484 let pending_workspace_folders = pending_workspace_folders.clone();
485 async move |cx| {
486 let binary = binary.await?;
487 #[cfg(any(test, feature = "test-support"))]
488 if let Some(server) = lsp_store
489 .update(&mut cx.clone(), |this, cx| {
490 this.languages.create_fake_language_server(
491 server_id,
492 &server_name,
493 binary.clone(),
494 &mut cx.to_async(),
495 )
496 })
497 .ok()
498 .flatten()
499 {
500 return Ok(server);
501 }
502
503 let code_action_kinds = adapter.code_action_kinds();
504 lsp::LanguageServer::new(
505 stderr_capture,
506 server_id,
507 server_name,
508 binary,
509 &worktree_abs_path,
510 code_action_kinds,
511 Some(pending_workspace_folders),
512 cx,
513 )
514 }
515 });
516
517 let startup = {
518 let server_name = adapter.name.0.clone();
519 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
520 let key = key.clone();
521 let adapter = adapter.clone();
522 let lsp_store = self.weak.clone();
523 let pending_workspace_folders = pending_workspace_folders.clone();
524 let pull_diagnostics = ProjectSettings::get_global(cx)
525 .diagnostics
526 .lsp_pull_diagnostics
527 .enabled;
528 let settings_location = SettingsLocation {
529 worktree_id,
530 path: RelPath::empty(),
531 };
532 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
533 .language(Some(settings_location), Some(&language_name), cx)
534 .semantic_tokens
535 .use_tree_sitter();
536 cx.spawn(async move |cx| {
537 let result = async {
538 let language_server = pending_server.await?;
539
540 let workspace_config = Self::workspace_configuration_for_adapter(
541 adapter.adapter.clone(),
542 &delegate,
543 toolchain,
544 None,
545 cx,
546 )
547 .await?;
548
549 let mut initialization_options = Self::initialization_options_for_adapter(
550 adapter.adapter.clone(),
551 &delegate,
552 cx,
553 )
554 .await?;
555
556 match (&mut initialization_options, override_options) {
557 (Some(initialization_options), Some(override_options)) => {
558 merge_json_value_into(override_options, initialization_options);
559 }
560 (None, override_options) => initialization_options = override_options,
561 _ => {}
562 }
563
564 let initialization_params = cx.update(|cx| {
565 let mut params = language_server.default_initialize_params(
566 pull_diagnostics,
567 augments_syntax_tokens,
568 cx,
569 );
570 params.initialization_options = initialization_options;
571 adapter.adapter.prepare_initialize_params(params, cx)
572 })?;
573
574 Self::setup_lsp_messages(
575 lsp_store.clone(),
576 &language_server,
577 delegate.clone(),
578 adapter.clone(),
579 );
580
581 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
582 settings: workspace_config,
583 };
584 let language_server = cx
585 .update(|cx| {
586 let request_timeout = ProjectSettings::get_global(cx)
587 .global_lsp_settings
588 .get_request_timeout();
589
590 language_server.initialize(
591 initialization_params,
592 Arc::new(did_change_configuration_params.clone()),
593 request_timeout,
594 cx,
595 )
596 })
597 .await
598 .inspect_err(|_| {
599 if let Some(lsp_store) = lsp_store.upgrade() {
600 lsp_store.update(cx, |lsp_store, cx| {
601 lsp_store.cleanup_lsp_data(server_id);
602 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
603 });
604 }
605 })?;
606
607 language_server.notify::<lsp::notification::DidChangeConfiguration>(
608 did_change_configuration_params,
609 )?;
610
611 anyhow::Ok(language_server)
612 }
613 .await;
614
615 match result {
616 Ok(server) => {
617 lsp_store
618 .update(cx, |lsp_store, cx| {
619 lsp_store.insert_newly_running_language_server(
620 adapter,
621 server.clone(),
622 server_id,
623 key,
624 pending_workspace_folders,
625 cx,
626 );
627 })
628 .ok();
629 stderr_capture.lock().take();
630 Some(server)
631 }
632
633 Err(err) => {
634 let log = stderr_capture.lock().take().unwrap_or_default();
635 delegate.update_status(
636 adapter.name(),
637 BinaryStatus::Failed {
638 error: if log.is_empty() {
639 format!("{err:#}")
640 } else {
641 format!("{err:#}\n-- stderr --\n{log}")
642 },
643 },
644 );
645 log::error!(
646 "Failed to start language server {server_name:?}: {}",
647 redact_command(&format!("{err:?}"))
648 );
649 if !log.is_empty() {
650 log::error!("server stderr: {}", redact_command(&log));
651 }
652 None
653 }
654 }
655 })
656 };
657 let state = LanguageServerState::Starting {
658 startup,
659 pending_workspace_folders,
660 };
661
662 if update_binary_status {
663 self.languages
664 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
665 }
666
667 self.language_servers.insert(server_id, state);
668 self.language_server_ids
669 .entry(key)
670 .or_insert(UnifiedLanguageServer {
671 id: server_id,
672 project_roots: Default::default(),
673 });
674 server_id
675 }
676
677 fn get_language_server_binary(
678 &self,
679 worktree_abs_path: Arc<Path>,
680 adapter: Arc<CachedLspAdapter>,
681 settings: Arc<LspSettings>,
682 toolchain: Option<Toolchain>,
683 delegate: Arc<dyn LspAdapterDelegate>,
684 allow_binary_download: bool,
685 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
686 cx: &mut App,
687 ) -> Task<Result<LanguageServerBinary>> {
688 if let Some(settings) = &settings.binary
689 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
690 {
691 let settings = settings.clone();
692 let languages = self.languages.clone();
693 return cx.background_spawn(async move {
694 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
695 let already_trusted = *wait_until_worktree_trust.borrow();
696 if !already_trusted {
697 log::info!(
698 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
699 adapter.name(),
700 );
701 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
702 if worktree_trusted {
703 break;
704 }
705 }
706 log::info!(
707 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
708 adapter.name(),
709 );
710 }
711 languages
712 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
713 }
714 let mut env = delegate.shell_env().await;
715 env.extend(settings.env.unwrap_or_default());
716
717 Ok(LanguageServerBinary {
718 path: delegate.resolve_relative_path(path),
719 env: Some(env),
720 arguments: settings
721 .arguments
722 .unwrap_or_default()
723 .iter()
724 .map(Into::into)
725 .collect(),
726 })
727 });
728 }
729 let lsp_binary_options = LanguageServerBinaryOptions {
730 allow_path_lookup: !settings
731 .binary
732 .as_ref()
733 .and_then(|b| b.ignore_system_version)
734 .unwrap_or_default(),
735 allow_binary_download,
736 pre_release: settings
737 .fetch
738 .as_ref()
739 .and_then(|f| f.pre_release)
740 .unwrap_or(false),
741 };
742
743 cx.spawn(async move |cx| {
744 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
745 let already_trusted = *wait_until_worktree_trust.borrow();
746 if !already_trusted {
747 log::info!(
748 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
749 adapter.name(),
750 );
751 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
752 if worktree_trusted {
753 break;
754 }
755 }
756 log::info!(
757 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
758 adapter.name(),
759 );
760 }
761 }
762
763 let (existing_binary, maybe_download_binary) = adapter
764 .clone()
765 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
766 .await
767 .await;
768
769 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
770
771 let mut binary = match (existing_binary, maybe_download_binary) {
772 (binary, None) => binary?,
773 (Err(_), Some(downloader)) => downloader.await?,
774 (Ok(existing_binary), Some(downloader)) => {
775 let mut download_timeout = cx
776 .background_executor()
777 .timer(SERVER_DOWNLOAD_TIMEOUT)
778 .fuse();
779 let mut downloader = downloader.fuse();
780 futures::select! {
781 _ = download_timeout => {
782 // Return existing binary and kick the existing work to the background.
783 cx.spawn(async move |_| downloader.await).detach();
784 Ok(existing_binary)
785 },
786 downloaded_or_existing_binary = downloader => {
787 // If download fails, this results in the existing binary.
788 downloaded_or_existing_binary
789 }
790 }?
791 }
792 };
793 let mut shell_env = delegate.shell_env().await;
794
795 shell_env.extend(binary.env.unwrap_or_default());
796
797 if let Some(settings) = settings.binary.as_ref() {
798 if let Some(arguments) = &settings.arguments {
799 binary.arguments = arguments.iter().map(Into::into).collect();
800 }
801 if let Some(env) = &settings.env {
802 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
803 }
804 }
805
806 binary.env = Some(shell_env);
807 Ok(binary)
808 })
809 }
810
811 fn setup_lsp_messages(
812 lsp_store: WeakEntity<LspStore>,
813 language_server: &LanguageServer,
814 delegate: Arc<dyn LspAdapterDelegate>,
815 adapter: Arc<CachedLspAdapter>,
816 ) {
817 let name = language_server.name();
818 let server_id = language_server.server_id();
819 language_server
820 .on_notification::<lsp::notification::PublishDiagnostics, _>({
821 let adapter = adapter.clone();
822 let this = lsp_store.clone();
823 move |mut params, cx| {
824 let adapter = adapter.clone();
825 if let Some(this) = this.upgrade() {
826 this.update(cx, |this, cx| {
827 adapter.process_diagnostics(&mut params, server_id);
828
829 this.merge_lsp_diagnostics(
830 DiagnosticSourceKind::Pushed,
831 vec![DocumentDiagnosticsUpdate {
832 server_id,
833 diagnostics: params,
834 result_id: None,
835 disk_based_sources: Cow::Borrowed(
836 &adapter.disk_based_diagnostic_sources,
837 ),
838 registration_id: None,
839 }],
840 |_, diagnostic, _cx| match diagnostic.source_kind {
841 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
842 adapter.retain_old_diagnostic(diagnostic)
843 }
844 DiagnosticSourceKind::Pulled => true,
845 },
846 cx,
847 )
848 .log_err();
849 });
850 }
851 }
852 })
853 .detach();
854 language_server
855 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
856 let adapter = adapter.adapter.clone();
857 let delegate = delegate.clone();
858 let this = lsp_store.clone();
859 move |params, cx| {
860 let adapter = adapter.clone();
861 let delegate = delegate.clone();
862 let this = this.clone();
863 let mut cx = cx.clone();
864 async move {
865 let toolchain_for_id = this
866 .update(&mut cx, |this, _| {
867 this.as_local()?.language_server_ids.iter().find_map(
868 |(seed, value)| {
869 (value.id == server_id).then(|| seed.toolchain.clone())
870 },
871 )
872 })?
873 .context("Expected the LSP store to be in a local mode")?;
874
875 let mut scope_uri_to_workspace_config = BTreeMap::new();
876 for item in ¶ms.items {
877 let scope_uri = item.scope_uri.clone();
878 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
879 scope_uri_to_workspace_config.entry(scope_uri.clone())
880 else {
881 // We've already queried workspace configuration of this URI.
882 continue;
883 };
884 let workspace_config = Self::workspace_configuration_for_adapter(
885 adapter.clone(),
886 &delegate,
887 toolchain_for_id.clone(),
888 scope_uri,
889 &mut cx,
890 )
891 .await?;
892 new_scope_uri.insert(workspace_config);
893 }
894
895 Ok(params
896 .items
897 .into_iter()
898 .filter_map(|item| {
899 let workspace_config =
900 scope_uri_to_workspace_config.get(&item.scope_uri)?;
901 if let Some(section) = &item.section {
902 Some(
903 workspace_config
904 .get(section)
905 .cloned()
906 .unwrap_or(serde_json::Value::Null),
907 )
908 } else {
909 Some(workspace_config.clone())
910 }
911 })
912 .collect())
913 }
914 }
915 })
916 .detach();
917
918 language_server
919 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
920 let this = lsp_store.clone();
921 move |_, cx| {
922 let this = this.clone();
923 let cx = cx.clone();
924 async move {
925 let Some(server) =
926 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
927 else {
928 return Ok(None);
929 };
930 let root = server.workspace_folders();
931 Ok(Some(
932 root.into_iter()
933 .map(|uri| WorkspaceFolder {
934 uri,
935 name: Default::default(),
936 })
937 .collect(),
938 ))
939 }
940 }
941 })
942 .detach();
943 // Even though we don't have handling for these requests, respond to them to
944 // avoid stalling any language server like `gopls` which waits for a response
945 // to these requests when initializing.
946 language_server
947 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
948 let this = lsp_store.clone();
949 move |params, cx| {
950 let this = this.clone();
951 let mut cx = cx.clone();
952 async move {
953 this.update(&mut cx, |this, _| {
954 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
955 {
956 status
957 .progress_tokens
958 .insert(ProgressToken::from_lsp(params.token));
959 }
960 })?;
961
962 Ok(())
963 }
964 }
965 })
966 .detach();
967
968 language_server
969 .on_request::<lsp::request::RegisterCapability, _, _>({
970 let lsp_store = lsp_store.clone();
971 move |params, cx| {
972 let lsp_store = lsp_store.clone();
973 let mut cx = cx.clone();
974 async move {
975 lsp_store
976 .update(&mut cx, |lsp_store, cx| {
977 if lsp_store.as_local().is_some() {
978 match lsp_store
979 .register_server_capabilities(server_id, params, cx)
980 {
981 Ok(()) => {}
982 Err(e) => {
983 log::error!(
984 "Failed to register server capabilities: {e:#}"
985 );
986 }
987 };
988 }
989 })
990 .ok();
991 Ok(())
992 }
993 }
994 })
995 .detach();
996
997 language_server
998 .on_request::<lsp::request::UnregisterCapability, _, _>({
999 let lsp_store = lsp_store.clone();
1000 move |params, cx| {
1001 let lsp_store = lsp_store.clone();
1002 let mut cx = cx.clone();
1003 async move {
1004 lsp_store
1005 .update(&mut cx, |lsp_store, cx| {
1006 if lsp_store.as_local().is_some() {
1007 match lsp_store
1008 .unregister_server_capabilities(server_id, params, cx)
1009 {
1010 Ok(()) => {}
1011 Err(e) => {
1012 log::error!(
1013 "Failed to unregister server capabilities: {e:#}"
1014 );
1015 }
1016 }
1017 }
1018 })
1019 .ok();
1020 Ok(())
1021 }
1022 }
1023 })
1024 .detach();
1025
1026 language_server
1027 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1028 let this = lsp_store.clone();
1029 move |params, cx| {
1030 let mut cx = cx.clone();
1031 let this = this.clone();
1032 async move {
1033 LocalLspStore::on_lsp_workspace_edit(
1034 this.clone(),
1035 params,
1036 server_id,
1037 &mut cx,
1038 )
1039 .await
1040 }
1041 }
1042 })
1043 .detach();
1044
1045 language_server
1046 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1047 let lsp_store = lsp_store.clone();
1048 let request_id = Arc::new(AtomicUsize::new(0));
1049 move |(), cx| {
1050 let lsp_store = lsp_store.clone();
1051 let request_id = request_id.clone();
1052 let mut cx = cx.clone();
1053 async move {
1054 lsp_store
1055 .update(&mut cx, |lsp_store, cx| {
1056 let request_id =
1057 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1058 cx.emit(LspStoreEvent::RefreshInlayHints {
1059 server_id,
1060 request_id,
1061 });
1062 lsp_store
1063 .downstream_client
1064 .as_ref()
1065 .map(|(client, project_id)| {
1066 client.send(proto::RefreshInlayHints {
1067 project_id: *project_id,
1068 server_id: server_id.to_proto(),
1069 request_id: request_id.map(|id| id as u64),
1070 })
1071 })
1072 })?
1073 .transpose()?;
1074 Ok(())
1075 }
1076 }
1077 })
1078 .detach();
1079
1080 language_server
1081 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1082 let this = lsp_store.clone();
1083 move |(), cx| {
1084 let this = this.clone();
1085 let mut cx = cx.clone();
1086 async move {
1087 this.update(&mut cx, |this, cx| {
1088 cx.emit(LspStoreEvent::RefreshCodeLens);
1089 this.downstream_client.as_ref().map(|(client, project_id)| {
1090 client.send(proto::RefreshCodeLens {
1091 project_id: *project_id,
1092 })
1093 })
1094 })?
1095 .transpose()?;
1096 Ok(())
1097 }
1098 }
1099 })
1100 .detach();
1101
1102 language_server
1103 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1104 let lsp_store = lsp_store.clone();
1105 let request_id = Arc::new(AtomicUsize::new(0));
1106 move |(), cx| {
1107 let lsp_store = lsp_store.clone();
1108 let request_id = request_id.clone();
1109 let mut cx = cx.clone();
1110 async move {
1111 lsp_store
1112 .update(&mut cx, |lsp_store, cx| {
1113 let request_id =
1114 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1115 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1116 server_id,
1117 request_id,
1118 });
1119 lsp_store
1120 .downstream_client
1121 .as_ref()
1122 .map(|(client, project_id)| {
1123 client.send(proto::RefreshSemanticTokens {
1124 project_id: *project_id,
1125 server_id: server_id.to_proto(),
1126 request_id: request_id.map(|id| id as u64),
1127 })
1128 })
1129 })?
1130 .transpose()?;
1131 Ok(())
1132 }
1133 }
1134 })
1135 .detach();
1136
1137 language_server
1138 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1139 let this = lsp_store.clone();
1140 move |(), cx| {
1141 let this = this.clone();
1142 let mut cx = cx.clone();
1143 async move {
1144 this.update(&mut cx, |lsp_store, cx| {
1145 lsp_store.pull_workspace_diagnostics(server_id);
1146 lsp_store
1147 .downstream_client
1148 .as_ref()
1149 .map(|(client, project_id)| {
1150 client.send(proto::PullWorkspaceDiagnostics {
1151 project_id: *project_id,
1152 server_id: server_id.to_proto(),
1153 })
1154 })
1155 .transpose()?;
1156 anyhow::Ok(
1157 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1158 )
1159 })??
1160 .await;
1161 Ok(())
1162 }
1163 }
1164 })
1165 .detach();
1166
1167 language_server
1168 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1169 let this = lsp_store.clone();
1170 let name = name.to_string();
1171 let adapter = adapter.clone();
1172 move |params, cx| {
1173 let this = this.clone();
1174 let name = name.to_string();
1175 let adapter = adapter.clone();
1176 let mut cx = cx.clone();
1177 async move {
1178 let actions = params.actions.unwrap_or_default();
1179 let message = params.message.clone();
1180 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1181 let level = match params.typ {
1182 lsp::MessageType::ERROR => PromptLevel::Critical,
1183 lsp::MessageType::WARNING => PromptLevel::Warning,
1184 _ => PromptLevel::Info,
1185 };
1186 let request = LanguageServerPromptRequest::new(
1187 level,
1188 params.message,
1189 actions,
1190 name.clone(),
1191 tx,
1192 );
1193
1194 let did_update = this
1195 .update(&mut cx, |_, cx| {
1196 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1197 })
1198 .is_ok();
1199 if did_update {
1200 let response = rx.recv().await.ok();
1201 if let Some(ref selected_action) = response {
1202 let context = language::PromptResponseContext {
1203 message,
1204 selected_action: selected_action.clone(),
1205 };
1206 adapter.process_prompt_response(&context, &mut cx)
1207 }
1208
1209 Ok(response)
1210 } else {
1211 Ok(None)
1212 }
1213 }
1214 }
1215 })
1216 .detach();
1217 language_server
1218 .on_notification::<lsp::notification::ShowMessage, _>({
1219 let this = lsp_store.clone();
1220 let name = name.to_string();
1221 move |params, cx| {
1222 let this = this.clone();
1223 let name = name.to_string();
1224 let mut cx = cx.clone();
1225
1226 let (tx, _) = smol::channel::bounded(1);
1227 let level = match params.typ {
1228 lsp::MessageType::ERROR => PromptLevel::Critical,
1229 lsp::MessageType::WARNING => PromptLevel::Warning,
1230 _ => PromptLevel::Info,
1231 };
1232 let request =
1233 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1234
1235 let _ = this.update(&mut cx, |_, cx| {
1236 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1237 });
1238 }
1239 })
1240 .detach();
1241
1242 let disk_based_diagnostics_progress_token =
1243 adapter.disk_based_diagnostics_progress_token.clone();
1244
1245 language_server
1246 .on_notification::<lsp::notification::Progress, _>({
1247 let this = lsp_store.clone();
1248 move |params, cx| {
1249 if let Some(this) = this.upgrade() {
1250 this.update(cx, |this, cx| {
1251 this.on_lsp_progress(
1252 params,
1253 server_id,
1254 disk_based_diagnostics_progress_token.clone(),
1255 cx,
1256 );
1257 });
1258 }
1259 }
1260 })
1261 .detach();
1262
1263 language_server
1264 .on_notification::<lsp::notification::LogMessage, _>({
1265 let this = lsp_store.clone();
1266 move |params, cx| {
1267 if let Some(this) = this.upgrade() {
1268 this.update(cx, |_, cx| {
1269 cx.emit(LspStoreEvent::LanguageServerLog(
1270 server_id,
1271 LanguageServerLogType::Log(params.typ),
1272 params.message,
1273 ));
1274 });
1275 }
1276 }
1277 })
1278 .detach();
1279
1280 language_server
1281 .on_notification::<lsp::notification::LogTrace, _>({
1282 let this = lsp_store.clone();
1283 move |params, cx| {
1284 let mut cx = cx.clone();
1285 if let Some(this) = this.upgrade() {
1286 this.update(&mut cx, |_, cx| {
1287 cx.emit(LspStoreEvent::LanguageServerLog(
1288 server_id,
1289 LanguageServerLogType::Trace {
1290 verbose_info: params.verbose,
1291 },
1292 params.message,
1293 ));
1294 });
1295 }
1296 }
1297 })
1298 .detach();
1299
1300 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1301 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1302 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1303 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1304 }
1305
1306 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1307 let shutdown_futures = self
1308 .language_servers
1309 .drain()
1310 .map(|(_, server_state)| Self::shutdown_server(server_state))
1311 .collect::<Vec<_>>();
1312
1313 async move {
1314 join_all(shutdown_futures).await;
1315 }
1316 }
1317
1318 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1319 match server_state {
1320 LanguageServerState::Running { server, .. } => {
1321 if let Some(shutdown) = server.shutdown() {
1322 shutdown.await;
1323 }
1324 }
1325 LanguageServerState::Starting { startup, .. } => {
1326 if let Some(server) = startup.await
1327 && let Some(shutdown) = server.shutdown()
1328 {
1329 shutdown.await;
1330 }
1331 }
1332 }
1333 Ok(())
1334 }
1335
1336 fn language_servers_for_worktree(
1337 &self,
1338 worktree_id: WorktreeId,
1339 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1340 self.language_server_ids
1341 .iter()
1342 .filter_map(move |(seed, state)| {
1343 if seed.worktree_id != worktree_id {
1344 return None;
1345 }
1346
1347 if let Some(LanguageServerState::Running { server, .. }) =
1348 self.language_servers.get(&state.id)
1349 {
1350 Some(server)
1351 } else {
1352 None
1353 }
1354 })
1355 }
1356
1357 fn language_server_ids_for_project_path(
1358 &self,
1359 project_path: ProjectPath,
1360 language: &Language,
1361 cx: &mut App,
1362 ) -> Vec<LanguageServerId> {
1363 let Some(worktree) = self
1364 .worktree_store
1365 .read(cx)
1366 .worktree_for_id(project_path.worktree_id, cx)
1367 else {
1368 return Vec::new();
1369 };
1370 let delegate: Arc<dyn ManifestDelegate> =
1371 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1372
1373 self.lsp_tree
1374 .get(
1375 project_path,
1376 language.name(),
1377 language.manifest(),
1378 &delegate,
1379 cx,
1380 )
1381 .collect::<Vec<_>>()
1382 }
1383
1384 fn language_server_ids_for_buffer(
1385 &self,
1386 buffer: &Buffer,
1387 cx: &mut App,
1388 ) -> Vec<LanguageServerId> {
1389 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1390 let worktree_id = file.worktree_id(cx);
1391
1392 let path: Arc<RelPath> = file
1393 .path()
1394 .parent()
1395 .map(Arc::from)
1396 .unwrap_or_else(|| file.path().clone());
1397 let worktree_path = ProjectPath { worktree_id, path };
1398 self.language_server_ids_for_project_path(worktree_path, language, cx)
1399 } else {
1400 Vec::new()
1401 }
1402 }
1403
1404 fn language_servers_for_buffer<'a>(
1405 &'a self,
1406 buffer: &'a Buffer,
1407 cx: &'a mut App,
1408 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1409 self.language_server_ids_for_buffer(buffer, cx)
1410 .into_iter()
1411 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1412 LanguageServerState::Running {
1413 adapter, server, ..
1414 } => Some((adapter, server)),
1415 _ => None,
1416 })
1417 }
1418
1419 async fn execute_code_action_kind_locally(
1420 lsp_store: WeakEntity<LspStore>,
1421 mut buffers: Vec<Entity<Buffer>>,
1422 kind: CodeActionKind,
1423 push_to_history: bool,
1424 cx: &mut AsyncApp,
1425 ) -> anyhow::Result<ProjectTransaction> {
1426 // Do not allow multiple concurrent code actions requests for the
1427 // same buffer.
1428 lsp_store.update(cx, |this, cx| {
1429 let this = this.as_local_mut().unwrap();
1430 buffers.retain(|buffer| {
1431 this.buffers_being_formatted
1432 .insert(buffer.read(cx).remote_id())
1433 });
1434 })?;
1435 let _cleanup = defer({
1436 let this = lsp_store.clone();
1437 let mut cx = cx.clone();
1438 let buffers = &buffers;
1439 move || {
1440 this.update(&mut cx, |this, cx| {
1441 let this = this.as_local_mut().unwrap();
1442 for buffer in buffers {
1443 this.buffers_being_formatted
1444 .remove(&buffer.read(cx).remote_id());
1445 }
1446 })
1447 .ok();
1448 }
1449 });
1450 let mut project_transaction = ProjectTransaction::default();
1451
1452 for buffer in &buffers {
1453 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1454 buffer.update(cx, |buffer, cx| {
1455 lsp_store
1456 .as_local()
1457 .unwrap()
1458 .language_servers_for_buffer(buffer, cx)
1459 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1460 .collect::<Vec<_>>()
1461 })
1462 })?;
1463 for (_, language_server) in adapters_and_servers.iter() {
1464 let actions = Self::get_server_code_actions_from_action_kinds(
1465 &lsp_store,
1466 language_server.server_id(),
1467 vec![kind.clone()],
1468 buffer,
1469 cx,
1470 )
1471 .await?;
1472 Self::execute_code_actions_on_server(
1473 &lsp_store,
1474 language_server,
1475 actions,
1476 push_to_history,
1477 &mut project_transaction,
1478 cx,
1479 )
1480 .await?;
1481 }
1482 }
1483 Ok(project_transaction)
1484 }
1485
1486 async fn format_locally(
1487 lsp_store: WeakEntity<LspStore>,
1488 mut buffers: Vec<FormattableBuffer>,
1489 push_to_history: bool,
1490 trigger: FormatTrigger,
1491 logger: zlog::Logger,
1492 cx: &mut AsyncApp,
1493 ) -> anyhow::Result<ProjectTransaction> {
1494 // Do not allow multiple concurrent formatting requests for the
1495 // same buffer.
1496 lsp_store.update(cx, |this, cx| {
1497 let this = this.as_local_mut().unwrap();
1498 buffers.retain(|buffer| {
1499 this.buffers_being_formatted
1500 .insert(buffer.handle.read(cx).remote_id())
1501 });
1502 })?;
1503
1504 let _cleanup = defer({
1505 let this = lsp_store.clone();
1506 let mut cx = cx.clone();
1507 let buffers = &buffers;
1508 move || {
1509 this.update(&mut cx, |this, cx| {
1510 let this = this.as_local_mut().unwrap();
1511 for buffer in buffers {
1512 this.buffers_being_formatted
1513 .remove(&buffer.handle.read(cx).remote_id());
1514 }
1515 })
1516 .ok();
1517 }
1518 });
1519
1520 let mut project_transaction = ProjectTransaction::default();
1521
1522 for buffer in &buffers {
1523 zlog::debug!(
1524 logger =>
1525 "formatting buffer '{:?}'",
1526 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1527 );
1528 // Create an empty transaction to hold all of the formatting edits.
1529 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1530 // ensure no transactions created while formatting are
1531 // grouped with the previous transaction in the history
1532 // based on the transaction group interval
1533 buffer.finalize_last_transaction();
1534 buffer
1535 .start_transaction()
1536 .context("transaction already open")?;
1537 buffer.end_transaction(cx);
1538 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1539 buffer.finalize_last_transaction();
1540 anyhow::Ok(transaction_id)
1541 })?;
1542
1543 let result = Self::format_buffer_locally(
1544 lsp_store.clone(),
1545 buffer,
1546 formatting_transaction_id,
1547 trigger,
1548 logger,
1549 cx,
1550 )
1551 .await;
1552
1553 buffer.handle.update(cx, |buffer, cx| {
1554 let Some(formatting_transaction) =
1555 buffer.get_transaction(formatting_transaction_id).cloned()
1556 else {
1557 zlog::warn!(logger => "no formatting transaction");
1558 return;
1559 };
1560 if formatting_transaction.edit_ids.is_empty() {
1561 zlog::debug!(logger => "no changes made while formatting");
1562 buffer.forget_transaction(formatting_transaction_id);
1563 return;
1564 }
1565 if !push_to_history {
1566 zlog::trace!(logger => "forgetting format transaction");
1567 buffer.forget_transaction(formatting_transaction.id);
1568 }
1569 project_transaction
1570 .0
1571 .insert(cx.entity(), formatting_transaction);
1572 });
1573
1574 result?;
1575 }
1576
1577 Ok(project_transaction)
1578 }
1579
1580 async fn format_buffer_locally(
1581 lsp_store: WeakEntity<LspStore>,
1582 buffer: &FormattableBuffer,
1583 formatting_transaction_id: clock::Lamport,
1584 trigger: FormatTrigger,
1585 logger: zlog::Logger,
1586 cx: &mut AsyncApp,
1587 ) -> Result<()> {
1588 let (adapters_and_servers, settings, request_timeout) =
1589 lsp_store.update(cx, |lsp_store, cx| {
1590 buffer.handle.update(cx, |buffer, cx| {
1591 let adapters_and_servers = lsp_store
1592 .as_local()
1593 .unwrap()
1594 .language_servers_for_buffer(buffer, cx)
1595 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1596 .collect::<Vec<_>>();
1597 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1598 let request_timeout = ProjectSettings::get_global(cx)
1599 .global_lsp_settings
1600 .get_request_timeout();
1601 (adapters_and_servers, settings, request_timeout)
1602 })
1603 })?;
1604
1605 // handle whitespace formatting
1606 if settings.remove_trailing_whitespace_on_save {
1607 zlog::trace!(logger => "removing trailing whitespace");
1608 let diff = buffer
1609 .handle
1610 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1611 .await;
1612 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1613 buffer.apply_diff(diff, cx);
1614 })?;
1615 }
1616
1617 if settings.ensure_final_newline_on_save {
1618 zlog::trace!(logger => "ensuring final newline");
1619 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1620 buffer.ensure_final_newline(cx);
1621 })?;
1622 }
1623
1624 // Formatter for `code_actions_on_format` that runs before
1625 // the rest of the formatters
1626 let mut code_actions_on_format_formatters = None;
1627 let should_run_code_actions_on_format = !matches!(
1628 (trigger, &settings.format_on_save),
1629 (FormatTrigger::Save, &FormatOnSave::Off)
1630 );
1631 if should_run_code_actions_on_format {
1632 let have_code_actions_to_run_on_format = settings
1633 .code_actions_on_format
1634 .values()
1635 .any(|enabled| *enabled);
1636 if have_code_actions_to_run_on_format {
1637 zlog::trace!(logger => "going to run code actions on format");
1638 code_actions_on_format_formatters = Some(
1639 settings
1640 .code_actions_on_format
1641 .iter()
1642 .filter_map(|(action, enabled)| enabled.then_some(action))
1643 .cloned()
1644 .map(Formatter::CodeAction)
1645 .collect::<Vec<_>>(),
1646 );
1647 }
1648 }
1649
1650 let formatters = match (trigger, &settings.format_on_save) {
1651 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1652 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1653 settings.formatter.as_ref()
1654 }
1655 };
1656
1657 let formatters = code_actions_on_format_formatters
1658 .iter()
1659 .flatten()
1660 .chain(formatters);
1661
1662 for formatter in formatters {
1663 let formatter = if formatter == &Formatter::Auto {
1664 if settings.prettier.allowed {
1665 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1666 &Formatter::Prettier
1667 } else {
1668 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1669 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1670 }
1671 } else {
1672 formatter
1673 };
1674 if let Err(err) = Self::apply_formatter(
1675 formatter,
1676 &lsp_store,
1677 buffer,
1678 formatting_transaction_id,
1679 &adapters_and_servers,
1680 &settings,
1681 request_timeout,
1682 logger,
1683 cx,
1684 )
1685 .await
1686 {
1687 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1688 }
1689 }
1690
1691 Ok(())
1692 }
1693
1694 async fn apply_formatter(
1695 formatter: &Formatter,
1696 lsp_store: &WeakEntity<LspStore>,
1697 buffer: &FormattableBuffer,
1698 formatting_transaction_id: clock::Lamport,
1699 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1700 settings: &LanguageSettings,
1701 request_timeout: Duration,
1702 logger: zlog::Logger,
1703 cx: &mut AsyncApp,
1704 ) -> anyhow::Result<()> {
1705 match formatter {
1706 Formatter::None => {
1707 zlog::trace!(logger => "skipping formatter 'none'");
1708 return Ok(());
1709 }
1710 Formatter::Auto => {
1711 debug_panic!("Auto resolved above");
1712 return Ok(());
1713 }
1714 Formatter::Prettier => {
1715 let logger = zlog::scoped!(logger => "prettier");
1716 zlog::trace!(logger => "formatting");
1717 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1718
1719 // When selection ranges are provided (via FormatSelections), we pass the
1720 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1721 // After diffing, we filter the resulting edits to only keep those that
1722 // overlap with the original byte-level selection ranges.
1723 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1724 Some(ranges) if !ranges.is_empty() => {
1725 let (utf16_range, byte_ranges) =
1726 buffer.handle.read_with(cx, |buffer, _cx| {
1727 let snapshot = buffer.snapshot();
1728 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1729 let mut max_end_utf16 = OffsetUtf16(0);
1730 let mut byte_ranges = Vec::with_capacity(ranges.len());
1731 for range in ranges {
1732 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1733 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1734 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1735 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1736
1737 let start_byte = range.start.to_offset(&snapshot);
1738 let end_byte = range.end.to_offset(&snapshot);
1739 byte_ranges.push(start_byte..end_byte);
1740 }
1741 (min_start_utf16..max_end_utf16, byte_ranges)
1742 });
1743 (Some(utf16_range), Some(byte_ranges))
1744 }
1745 _ => (None, None),
1746 };
1747
1748 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1749 lsp_store.prettier_store().unwrap().downgrade()
1750 })?;
1751 let diff = prettier_store::format_with_prettier(
1752 &prettier,
1753 &buffer.handle,
1754 range_utf16,
1755 cx,
1756 )
1757 .await
1758 .transpose()?;
1759 let Some(mut diff) = diff else {
1760 zlog::trace!(logger => "No changes");
1761 return Ok(());
1762 };
1763
1764 if let Some(byte_ranges) = byte_ranges {
1765 diff.edits.retain(|(edit_range, _)| {
1766 byte_ranges.iter().any(|selection_range| {
1767 edit_range.start < selection_range.end
1768 && edit_range.end > selection_range.start
1769 })
1770 });
1771 if diff.edits.is_empty() {
1772 zlog::trace!(logger => "No changes within selection");
1773 return Ok(());
1774 }
1775 }
1776
1777 extend_formatting_transaction(
1778 buffer,
1779 formatting_transaction_id,
1780 cx,
1781 |buffer, cx| {
1782 buffer.apply_diff(diff, cx);
1783 },
1784 )?;
1785 }
1786 Formatter::External { command, arguments } => {
1787 let logger = zlog::scoped!(logger => "command");
1788
1789 if buffer.ranges.is_some() {
1790 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1791 return Ok(());
1792 }
1793
1794 zlog::trace!(logger => "formatting");
1795 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1796
1797 let diff =
1798 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1799 .await
1800 .with_context(|| {
1801 format!("Failed to format buffer via external command: {}", command)
1802 })?;
1803 let Some(diff) = diff else {
1804 zlog::trace!(logger => "No changes");
1805 return Ok(());
1806 };
1807
1808 extend_formatting_transaction(
1809 buffer,
1810 formatting_transaction_id,
1811 cx,
1812 |buffer, cx| {
1813 buffer.apply_diff(diff, cx);
1814 },
1815 )?;
1816 }
1817 Formatter::LanguageServer(specifier) => {
1818 let logger = zlog::scoped!(logger => "language-server");
1819 zlog::trace!(logger => "formatting");
1820 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1821
1822 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1823 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1824 return Ok(());
1825 };
1826
1827 let language_server = match specifier {
1828 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1829 adapters_and_servers.iter().find_map(|(adapter, server)| {
1830 if adapter.name.0.as_ref() == name {
1831 Some(server.clone())
1832 } else {
1833 None
1834 }
1835 })
1836 }
1837 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1838 .iter()
1839 .find(|(_, server)| Self::server_supports_formatting(server))
1840 .map(|(_, server)| server.clone()),
1841 };
1842
1843 let Some(language_server) = language_server else {
1844 log::debug!(
1845 "No language server found to format buffer '{:?}'. Skipping",
1846 buffer_path_abs.as_path().to_string_lossy()
1847 );
1848 return Ok(());
1849 };
1850
1851 zlog::trace!(
1852 logger =>
1853 "Formatting buffer '{:?}' using language server '{:?}'",
1854 buffer_path_abs.as_path().to_string_lossy(),
1855 language_server.name()
1856 );
1857
1858 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1859 zlog::trace!(logger => "formatting ranges");
1860 Self::format_ranges_via_lsp(
1861 &lsp_store,
1862 &buffer.handle,
1863 ranges,
1864 buffer_path_abs,
1865 &language_server,
1866 &settings,
1867 cx,
1868 )
1869 .await
1870 .context("Failed to format ranges via language server")?
1871 } else {
1872 zlog::trace!(logger => "formatting full");
1873 Self::format_via_lsp(
1874 &lsp_store,
1875 &buffer.handle,
1876 buffer_path_abs,
1877 &language_server,
1878 &settings,
1879 cx,
1880 )
1881 .await
1882 .context("failed to format via language server")?
1883 };
1884
1885 if edits.is_empty() {
1886 zlog::trace!(logger => "No changes");
1887 return Ok(());
1888 }
1889 extend_formatting_transaction(
1890 buffer,
1891 formatting_transaction_id,
1892 cx,
1893 |buffer, cx| {
1894 buffer.edit(edits, None, cx);
1895 },
1896 )?;
1897 }
1898 Formatter::CodeAction(code_action_name) => {
1899 let logger = zlog::scoped!(logger => "code-actions");
1900 zlog::trace!(logger => "formatting");
1901 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1902
1903 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1904 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1905 return Ok(());
1906 };
1907
1908 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1909 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1910
1911 let mut actions_and_servers = Vec::new();
1912
1913 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1914 let actions_result = Self::get_server_code_actions_from_action_kinds(
1915 &lsp_store,
1916 language_server.server_id(),
1917 vec![code_action_kind.clone()],
1918 &buffer.handle,
1919 cx,
1920 )
1921 .await
1922 .with_context(|| {
1923 format!(
1924 "Failed to resolve code action {:?} with language server {}",
1925 code_action_kind,
1926 language_server.name()
1927 )
1928 });
1929 let Ok(actions) = actions_result else {
1930 // note: it may be better to set result to the error and break formatters here
1931 // but for now we try to execute the actions that we can resolve and skip the rest
1932 zlog::error!(
1933 logger =>
1934 "Failed to resolve code action {:?} with language server {}",
1935 code_action_kind,
1936 language_server.name()
1937 );
1938 continue;
1939 };
1940 for action in actions {
1941 actions_and_servers.push((action, index));
1942 }
1943 }
1944
1945 if actions_and_servers.is_empty() {
1946 zlog::warn!(logger => "No code actions were resolved, continuing");
1947 return Ok(());
1948 }
1949
1950 'actions: for (mut action, server_index) in actions_and_servers {
1951 let server = &adapters_and_servers[server_index].1;
1952
1953 let describe_code_action = |action: &CodeAction| {
1954 format!(
1955 "code action '{}' with title \"{}\" on server {}",
1956 action
1957 .lsp_action
1958 .action_kind()
1959 .unwrap_or("unknown".into())
1960 .as_str(),
1961 action.lsp_action.title(),
1962 server.name(),
1963 )
1964 };
1965
1966 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1967
1968 if let Err(err) =
1969 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1970 {
1971 zlog::error!(
1972 logger =>
1973 "Failed to resolve {}. Error: {}",
1974 describe_code_action(&action),
1975 err
1976 );
1977 continue;
1978 }
1979
1980 if let Some(edit) = action.lsp_action.edit().cloned() {
1981 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1982 // but filters out and logs warnings for code actions that require unreasonably
1983 // difficult handling on our part, such as:
1984 // - applying edits that call commands
1985 // which can result in arbitrary workspace edits being sent from the server that
1986 // have no way of being tied back to the command that initiated them (i.e. we
1987 // can't know which edits are part of the format request, or if the server is done sending
1988 // actions in response to the command)
1989 // - actions that create/delete/modify/rename files other than the one we are formatting
1990 // as we then would need to handle such changes correctly in the local history as well
1991 // as the remote history through the ProjectTransaction
1992 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1993 // Supporting these actions is not impossible, but not supported as of yet.
1994 if edit.changes.is_none() && edit.document_changes.is_none() {
1995 zlog::trace!(
1996 logger =>
1997 "No changes for code action. Skipping {}",
1998 describe_code_action(&action),
1999 );
2000 continue;
2001 }
2002
2003 let mut operations = Vec::new();
2004 if let Some(document_changes) = edit.document_changes {
2005 match document_changes {
2006 lsp::DocumentChanges::Edits(edits) => operations.extend(
2007 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2008 ),
2009 lsp::DocumentChanges::Operations(ops) => operations = ops,
2010 }
2011 } else if let Some(changes) = edit.changes {
2012 operations.extend(changes.into_iter().map(|(uri, edits)| {
2013 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2014 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2015 uri,
2016 version: None,
2017 },
2018 edits: edits.into_iter().map(Edit::Plain).collect(),
2019 })
2020 }));
2021 }
2022
2023 let mut edits = Vec::with_capacity(operations.len());
2024
2025 if operations.is_empty() {
2026 zlog::trace!(
2027 logger =>
2028 "No changes for code action. Skipping {}",
2029 describe_code_action(&action),
2030 );
2031 continue;
2032 }
2033 for operation in operations {
2034 let op = match operation {
2035 lsp::DocumentChangeOperation::Edit(op) => op,
2036 lsp::DocumentChangeOperation::Op(_) => {
2037 zlog::warn!(
2038 logger =>
2039 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2040 describe_code_action(&action),
2041 );
2042 continue 'actions;
2043 }
2044 };
2045 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2046 zlog::warn!(
2047 logger =>
2048 "Failed to convert URI '{:?}' to file path. Skipping {}",
2049 &op.text_document.uri,
2050 describe_code_action(&action),
2051 );
2052 continue 'actions;
2053 };
2054 if &file_path != buffer_path_abs {
2055 zlog::warn!(
2056 logger =>
2057 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2058 file_path,
2059 buffer_path_abs,
2060 describe_code_action(&action),
2061 );
2062 continue 'actions;
2063 }
2064
2065 let mut lsp_edits = Vec::new();
2066 for edit in op.edits {
2067 match edit {
2068 Edit::Plain(edit) => {
2069 if !lsp_edits.contains(&edit) {
2070 lsp_edits.push(edit);
2071 }
2072 }
2073 Edit::Annotated(edit) => {
2074 if !lsp_edits.contains(&edit.text_edit) {
2075 lsp_edits.push(edit.text_edit);
2076 }
2077 }
2078 Edit::Snippet(_) => {
2079 zlog::warn!(
2080 logger =>
2081 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2082 describe_code_action(&action),
2083 );
2084 continue 'actions;
2085 }
2086 }
2087 }
2088 let edits_result = lsp_store
2089 .update(cx, |lsp_store, cx| {
2090 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2091 &buffer.handle,
2092 lsp_edits,
2093 server.server_id(),
2094 op.text_document.version,
2095 cx,
2096 )
2097 })?
2098 .await;
2099 let Ok(resolved_edits) = edits_result else {
2100 zlog::warn!(
2101 logger =>
2102 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2103 buffer_path_abs.as_path(),
2104 describe_code_action(&action),
2105 );
2106 continue 'actions;
2107 };
2108 edits.extend(resolved_edits);
2109 }
2110
2111 if edits.is_empty() {
2112 zlog::warn!(logger => "No edits resolved from LSP");
2113 continue;
2114 }
2115
2116 extend_formatting_transaction(
2117 buffer,
2118 formatting_transaction_id,
2119 cx,
2120 |buffer, cx| {
2121 zlog::info!(
2122 "Applying edits {edits:?}. Content: {:?}",
2123 buffer.text()
2124 );
2125 buffer.edit(edits, None, cx);
2126 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2127 },
2128 )?;
2129 }
2130
2131 let Some(command) = action.lsp_action.command() else {
2132 continue;
2133 };
2134
2135 zlog::warn!(
2136 logger =>
2137 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2138 &command.command,
2139 );
2140
2141 let server_capabilities = server.capabilities();
2142 let available_commands = server_capabilities
2143 .execute_command_provider
2144 .as_ref()
2145 .map(|options| options.commands.as_slice())
2146 .unwrap_or_default();
2147 if !available_commands.contains(&command.command) {
2148 zlog::warn!(
2149 logger =>
2150 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2151 command.command,
2152 server.name(),
2153 );
2154 continue;
2155 }
2156
2157 extend_formatting_transaction(
2158 buffer,
2159 formatting_transaction_id,
2160 cx,
2161 |_, _| {},
2162 )?;
2163 zlog::info!(logger => "Executing command {}", &command.command);
2164
2165 lsp_store.update(cx, |this, _| {
2166 this.as_local_mut()
2167 .unwrap()
2168 .last_workspace_edits_by_language_server
2169 .remove(&server.server_id());
2170 })?;
2171
2172 let execute_command_result = server
2173 .request::<lsp::request::ExecuteCommand>(
2174 lsp::ExecuteCommandParams {
2175 command: command.command.clone(),
2176 arguments: command.arguments.clone().unwrap_or_default(),
2177 ..Default::default()
2178 },
2179 request_timeout,
2180 )
2181 .await
2182 .into_response();
2183
2184 if execute_command_result.is_err() {
2185 zlog::error!(
2186 logger =>
2187 "Failed to execute command '{}' as part of {}",
2188 &command.command,
2189 describe_code_action(&action),
2190 );
2191 continue 'actions;
2192 }
2193
2194 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2195 this.as_local_mut()
2196 .unwrap()
2197 .last_workspace_edits_by_language_server
2198 .remove(&server.server_id())
2199 .unwrap_or_default()
2200 })?;
2201
2202 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2203 {
2204 zlog::trace!(
2205 logger =>
2206 "Successfully captured {} edits that resulted from command {}",
2207 transaction.edit_ids.len(),
2208 &command.command,
2209 );
2210 let transaction_id_project_transaction = transaction.id;
2211 buffer.handle.update(cx, |buffer, _| {
2212 // it may have been removed from history if push_to_history was
2213 // false in deserialize_workspace_edit. If so push it so we
2214 // can merge it with the format transaction
2215 // and pop the combined transaction off the history stack
2216 // later if push_to_history is false
2217 if buffer.get_transaction(transaction.id).is_none() {
2218 buffer.push_transaction(transaction, Instant::now());
2219 }
2220 buffer.merge_transactions(
2221 transaction_id_project_transaction,
2222 formatting_transaction_id,
2223 );
2224 });
2225 }
2226
2227 if project_transaction_command.0.is_empty() {
2228 continue;
2229 }
2230
2231 let mut extra_buffers = String::new();
2232 for buffer in project_transaction_command.0.keys() {
2233 buffer.read_with(cx, |b, cx| {
2234 let Some(path) = b.project_path(cx) else {
2235 return;
2236 };
2237
2238 if !extra_buffers.is_empty() {
2239 extra_buffers.push_str(", ");
2240 }
2241 extra_buffers.push_str(path.path.as_unix_str());
2242 });
2243 }
2244 zlog::warn!(
2245 logger =>
2246 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2247 &command.command,
2248 extra_buffers,
2249 );
2250 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2251 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2252 // add it so it's included, and merge it into the format transaction when its created later
2253 }
2254 }
2255 }
2256
2257 Ok(())
2258 }
2259
2260 pub async fn format_ranges_via_lsp(
2261 this: &WeakEntity<LspStore>,
2262 buffer_handle: &Entity<Buffer>,
2263 ranges: &[Range<Anchor>],
2264 abs_path: &Path,
2265 language_server: &Arc<LanguageServer>,
2266 settings: &LanguageSettings,
2267 cx: &mut AsyncApp,
2268 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2269 let capabilities = &language_server.capabilities();
2270 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2271 if range_formatting_provider == Some(&OneOf::Left(false)) {
2272 anyhow::bail!(
2273 "{} language server does not support range formatting",
2274 language_server.name()
2275 );
2276 }
2277
2278 let uri = file_path_to_lsp_url(abs_path)?;
2279 let text_document = lsp::TextDocumentIdentifier::new(uri);
2280
2281 let request_timeout = cx.update(|app| {
2282 ProjectSettings::get_global(app)
2283 .global_lsp_settings
2284 .get_request_timeout()
2285 });
2286 let lsp_edits = {
2287 let mut lsp_ranges = Vec::new();
2288 this.update(cx, |_this, cx| {
2289 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2290 // not have been sent to the language server. This seems like a fairly systemic
2291 // issue, though, the resolution probably is not specific to formatting.
2292 //
2293 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2294 // LSP.
2295 let snapshot = buffer_handle.read(cx).snapshot();
2296 for range in ranges {
2297 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2298 }
2299 anyhow::Ok(())
2300 })??;
2301
2302 let mut edits = None;
2303 for range in lsp_ranges {
2304 if let Some(mut edit) = language_server
2305 .request::<lsp::request::RangeFormatting>(
2306 lsp::DocumentRangeFormattingParams {
2307 text_document: text_document.clone(),
2308 range,
2309 options: lsp_command::lsp_formatting_options(settings),
2310 work_done_progress_params: Default::default(),
2311 },
2312 request_timeout,
2313 )
2314 .await
2315 .into_response()?
2316 {
2317 edits.get_or_insert_with(Vec::new).append(&mut edit);
2318 }
2319 }
2320 edits
2321 };
2322
2323 if let Some(lsp_edits) = lsp_edits {
2324 this.update(cx, |this, cx| {
2325 this.as_local_mut().unwrap().edits_from_lsp(
2326 buffer_handle,
2327 lsp_edits,
2328 language_server.server_id(),
2329 None,
2330 cx,
2331 )
2332 })?
2333 .await
2334 } else {
2335 Ok(Vec::with_capacity(0))
2336 }
2337 }
2338
2339 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2340 let capabilities = server.capabilities();
2341 let formatting = capabilities.document_formatting_provider.as_ref();
2342 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2343 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2344 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2345 }
2346
2347 async fn format_via_lsp(
2348 this: &WeakEntity<LspStore>,
2349 buffer: &Entity<Buffer>,
2350 abs_path: &Path,
2351 language_server: &Arc<LanguageServer>,
2352 settings: &LanguageSettings,
2353 cx: &mut AsyncApp,
2354 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2355 let logger = zlog::scoped!("lsp_format");
2356 zlog::debug!(logger => "Formatting via LSP");
2357
2358 let uri = file_path_to_lsp_url(abs_path)?;
2359 let text_document = lsp::TextDocumentIdentifier::new(uri);
2360 let capabilities = &language_server.capabilities();
2361
2362 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2363 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2364
2365 let request_timeout = cx.update(|app| {
2366 ProjectSettings::get_global(app)
2367 .global_lsp_settings
2368 .get_request_timeout()
2369 });
2370
2371 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2372 let _timer = zlog::time!(logger => "format-full");
2373 language_server
2374 .request::<lsp::request::Formatting>(
2375 lsp::DocumentFormattingParams {
2376 text_document,
2377 options: lsp_command::lsp_formatting_options(settings),
2378 work_done_progress_params: Default::default(),
2379 },
2380 request_timeout,
2381 )
2382 .await
2383 .into_response()?
2384 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2385 let _timer = zlog::time!(logger => "format-range");
2386 let buffer_start = lsp::Position::new(0, 0);
2387 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2388 language_server
2389 .request::<lsp::request::RangeFormatting>(
2390 lsp::DocumentRangeFormattingParams {
2391 text_document: text_document.clone(),
2392 range: lsp::Range::new(buffer_start, buffer_end),
2393 options: lsp_command::lsp_formatting_options(settings),
2394 work_done_progress_params: Default::default(),
2395 },
2396 request_timeout,
2397 )
2398 .await
2399 .into_response()?
2400 } else {
2401 None
2402 };
2403
2404 if let Some(lsp_edits) = lsp_edits {
2405 this.update(cx, |this, cx| {
2406 this.as_local_mut().unwrap().edits_from_lsp(
2407 buffer,
2408 lsp_edits,
2409 language_server.server_id(),
2410 None,
2411 cx,
2412 )
2413 })?
2414 .await
2415 } else {
2416 Ok(Vec::with_capacity(0))
2417 }
2418 }
2419
2420 async fn format_via_external_command(
2421 buffer: &FormattableBuffer,
2422 command: &str,
2423 arguments: Option<&[String]>,
2424 cx: &mut AsyncApp,
2425 ) -> Result<Option<Diff>> {
2426 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2427 let file = File::from_dyn(buffer.file())?;
2428 let worktree = file.worktree.read(cx);
2429 let mut worktree_path = worktree.abs_path().to_path_buf();
2430 if worktree.root_entry()?.is_file() {
2431 worktree_path.pop();
2432 }
2433 Some(worktree_path)
2434 });
2435
2436 use util::command::Stdio;
2437 let mut child = util::command::new_command(command);
2438
2439 if let Some(buffer_env) = buffer.env.as_ref() {
2440 child.envs(buffer_env);
2441 }
2442
2443 if let Some(working_dir_path) = working_dir_path {
2444 child.current_dir(working_dir_path);
2445 }
2446
2447 if let Some(arguments) = arguments {
2448 child.args(arguments.iter().map(|arg| {
2449 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2450 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2451 } else {
2452 arg.replace("{buffer_path}", "Untitled")
2453 }
2454 }));
2455 }
2456
2457 let mut child = child
2458 .stdin(Stdio::piped())
2459 .stdout(Stdio::piped())
2460 .stderr(Stdio::piped())
2461 .spawn()?;
2462
2463 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2464 let text = buffer
2465 .handle
2466 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2467 for chunk in text.chunks() {
2468 stdin.write_all(chunk.as_bytes()).await?;
2469 }
2470 stdin.flush().await?;
2471
2472 let output = child.output().await?;
2473 anyhow::ensure!(
2474 output.status.success(),
2475 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2476 output.status.code(),
2477 String::from_utf8_lossy(&output.stdout),
2478 String::from_utf8_lossy(&output.stderr),
2479 );
2480
2481 let stdout = String::from_utf8(output.stdout)?;
2482 Ok(Some(
2483 buffer
2484 .handle
2485 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2486 .await,
2487 ))
2488 }
2489
2490 async fn try_resolve_code_action(
2491 lang_server: &LanguageServer,
2492 action: &mut CodeAction,
2493 request_timeout: Duration,
2494 ) -> anyhow::Result<()> {
2495 match &mut action.lsp_action {
2496 LspAction::Action(lsp_action) => {
2497 if !action.resolved
2498 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2499 && lsp_action.data.is_some()
2500 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2501 {
2502 **lsp_action = lang_server
2503 .request::<lsp::request::CodeActionResolveRequest>(
2504 *lsp_action.clone(),
2505 request_timeout,
2506 )
2507 .await
2508 .into_response()?;
2509 }
2510 }
2511 LspAction::CodeLens(lens) => {
2512 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2513 *lens = lang_server
2514 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2515 .await
2516 .into_response()?;
2517 }
2518 }
2519 LspAction::Command(_) => {}
2520 }
2521
2522 action.resolved = true;
2523 anyhow::Ok(())
2524 }
2525
2526 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2527 let buffer = buffer_handle.read(cx);
2528
2529 let file = buffer.file().cloned();
2530
2531 let Some(file) = File::from_dyn(file.as_ref()) else {
2532 return;
2533 };
2534 if !file.is_local() {
2535 return;
2536 }
2537 let path = ProjectPath::from_file(file, cx);
2538 let worktree_id = file.worktree_id(cx);
2539 let language = buffer.language().cloned();
2540
2541 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2542 for (server_id, diagnostics) in
2543 diagnostics.get(file.path()).cloned().unwrap_or_default()
2544 {
2545 self.update_buffer_diagnostics(
2546 buffer_handle,
2547 server_id,
2548 None,
2549 None,
2550 None,
2551 Vec::new(),
2552 diagnostics,
2553 cx,
2554 )
2555 .log_err();
2556 }
2557 }
2558 let Some(language) = language else {
2559 return;
2560 };
2561 let Some(snapshot) = self
2562 .worktree_store
2563 .read(cx)
2564 .worktree_for_id(worktree_id, cx)
2565 .map(|worktree| worktree.read(cx).snapshot())
2566 else {
2567 return;
2568 };
2569 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2570
2571 for server_id in
2572 self.lsp_tree
2573 .get(path, language.name(), language.manifest(), &delegate, cx)
2574 {
2575 let server = self
2576 .language_servers
2577 .get(&server_id)
2578 .and_then(|server_state| {
2579 if let LanguageServerState::Running { server, .. } = server_state {
2580 Some(server.clone())
2581 } else {
2582 None
2583 }
2584 });
2585 let server = match server {
2586 Some(server) => server,
2587 None => continue,
2588 };
2589
2590 buffer_handle.update(cx, |buffer, cx| {
2591 buffer.set_completion_triggers(
2592 server.server_id(),
2593 server
2594 .capabilities()
2595 .completion_provider
2596 .as_ref()
2597 .and_then(|provider| {
2598 provider
2599 .trigger_characters
2600 .as_ref()
2601 .map(|characters| characters.iter().cloned().collect())
2602 })
2603 .unwrap_or_default(),
2604 cx,
2605 );
2606 });
2607 }
2608 }
2609
2610 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2611 buffer.update(cx, |buffer, cx| {
2612 let Some(language) = buffer.language() else {
2613 return;
2614 };
2615 let path = ProjectPath {
2616 worktree_id: old_file.worktree_id(cx),
2617 path: old_file.path.clone(),
2618 };
2619 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2620 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2621 buffer.set_completion_triggers(server_id, Default::default(), cx);
2622 }
2623 });
2624 }
2625
2626 fn update_buffer_diagnostics(
2627 &mut self,
2628 buffer: &Entity<Buffer>,
2629 server_id: LanguageServerId,
2630 registration_id: Option<Option<SharedString>>,
2631 result_id: Option<SharedString>,
2632 version: Option<i32>,
2633 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2634 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2635 cx: &mut Context<LspStore>,
2636 ) -> Result<()> {
2637 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2638 Ordering::Equal
2639 .then_with(|| b.is_primary.cmp(&a.is_primary))
2640 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2641 .then_with(|| a.severity.cmp(&b.severity))
2642 .then_with(|| a.message.cmp(&b.message))
2643 }
2644
2645 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2646 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2647 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2648
2649 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2650 Ordering::Equal
2651 .then_with(|| a.range.start.cmp(&b.range.start))
2652 .then_with(|| b.range.end.cmp(&a.range.end))
2653 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2654 });
2655
2656 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2657
2658 let edits_since_save = std::cell::LazyCell::new(|| {
2659 let saved_version = buffer.read(cx).saved_version();
2660 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2661 });
2662
2663 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2664
2665 for (new_diagnostic, entry) in diagnostics {
2666 let start;
2667 let end;
2668 if new_diagnostic && entry.diagnostic.is_disk_based {
2669 // Some diagnostics are based on files on disk instead of buffers'
2670 // current contents. Adjust these diagnostics' ranges to reflect
2671 // any unsaved edits.
2672 // Do not alter the reused ones though, as their coordinates were stored as anchors
2673 // and were properly adjusted on reuse.
2674 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2675 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2676 } else {
2677 start = entry.range.start;
2678 end = entry.range.end;
2679 }
2680
2681 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2682 ..snapshot.clip_point_utf16(end, Bias::Right);
2683
2684 // Expand empty ranges by one codepoint
2685 if range.start == range.end {
2686 // This will be go to the next boundary when being clipped
2687 range.end.column += 1;
2688 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2689 if range.start == range.end && range.end.column > 0 {
2690 range.start.column -= 1;
2691 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2692 }
2693 }
2694
2695 sanitized_diagnostics.push(DiagnosticEntry {
2696 range,
2697 diagnostic: entry.diagnostic,
2698 });
2699 }
2700 drop(edits_since_save);
2701
2702 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2703 buffer.update(cx, |buffer, cx| {
2704 if let Some(registration_id) = registration_id {
2705 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2706 self.buffer_pull_diagnostics_result_ids
2707 .entry(server_id)
2708 .or_default()
2709 .entry(registration_id)
2710 .or_default()
2711 .insert(abs_path, result_id);
2712 }
2713 }
2714
2715 buffer.update_diagnostics(server_id, set, cx)
2716 });
2717
2718 Ok(())
2719 }
2720
2721 fn register_language_server_for_invisible_worktree(
2722 &mut self,
2723 worktree: &Entity<Worktree>,
2724 language_server_id: LanguageServerId,
2725 cx: &mut App,
2726 ) {
2727 let worktree = worktree.read(cx);
2728 let worktree_id = worktree.id();
2729 debug_assert!(!worktree.is_visible());
2730 let Some(mut origin_seed) = self
2731 .language_server_ids
2732 .iter()
2733 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2734 else {
2735 return;
2736 };
2737 origin_seed.worktree_id = worktree_id;
2738 self.language_server_ids
2739 .entry(origin_seed)
2740 .or_insert_with(|| UnifiedLanguageServer {
2741 id: language_server_id,
2742 project_roots: Default::default(),
2743 });
2744 }
2745
2746 fn register_buffer_with_language_servers(
2747 &mut self,
2748 buffer_handle: &Entity<Buffer>,
2749 only_register_servers: HashSet<LanguageServerSelector>,
2750 cx: &mut Context<LspStore>,
2751 ) {
2752 let buffer = buffer_handle.read(cx);
2753 let buffer_id = buffer.remote_id();
2754
2755 let Some(file) = File::from_dyn(buffer.file()) else {
2756 return;
2757 };
2758 if !file.is_local() {
2759 return;
2760 }
2761
2762 let abs_path = file.abs_path(cx);
2763 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2764 return;
2765 };
2766 let initial_snapshot = buffer.text_snapshot();
2767 let worktree_id = file.worktree_id(cx);
2768
2769 let Some(language) = buffer.language().cloned() else {
2770 return;
2771 };
2772 let path: Arc<RelPath> = file
2773 .path()
2774 .parent()
2775 .map(Arc::from)
2776 .unwrap_or_else(|| file.path().clone());
2777 let Some(worktree) = self
2778 .worktree_store
2779 .read(cx)
2780 .worktree_for_id(worktree_id, cx)
2781 else {
2782 return;
2783 };
2784 let language_name = language.name();
2785 let (reused, delegate, servers) = self
2786 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2787 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2788 .unwrap_or_else(|| {
2789 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2790 let delegate: Arc<dyn ManifestDelegate> =
2791 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2792
2793 let servers = self
2794 .lsp_tree
2795 .walk(
2796 ProjectPath { worktree_id, path },
2797 language.name(),
2798 language.manifest(),
2799 &delegate,
2800 cx,
2801 )
2802 .collect::<Vec<_>>();
2803 (false, lsp_delegate, servers)
2804 });
2805 let servers_and_adapters = servers
2806 .into_iter()
2807 .filter_map(|server_node| {
2808 if reused && server_node.server_id().is_none() {
2809 return None;
2810 }
2811 if !only_register_servers.is_empty() {
2812 if let Some(server_id) = server_node.server_id()
2813 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2814 {
2815 return None;
2816 }
2817 if let Some(name) = server_node.name()
2818 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2819 {
2820 return None;
2821 }
2822 }
2823
2824 let server_id = server_node.server_id_or_init(|disposition| {
2825 let path = &disposition.path;
2826
2827 {
2828 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2829
2830 let server_id = self.get_or_insert_language_server(
2831 &worktree,
2832 delegate.clone(),
2833 disposition,
2834 &language_name,
2835 cx,
2836 );
2837
2838 if let Some(state) = self.language_servers.get(&server_id)
2839 && let Ok(uri) = uri
2840 {
2841 state.add_workspace_folder(uri);
2842 };
2843 server_id
2844 }
2845 })?;
2846 let server_state = self.language_servers.get(&server_id)?;
2847 if let LanguageServerState::Running {
2848 server, adapter, ..
2849 } = server_state
2850 {
2851 Some((server.clone(), adapter.clone()))
2852 } else {
2853 None
2854 }
2855 })
2856 .collect::<Vec<_>>();
2857 for (server, adapter) in servers_and_adapters {
2858 buffer_handle.update(cx, |buffer, cx| {
2859 buffer.set_completion_triggers(
2860 server.server_id(),
2861 server
2862 .capabilities()
2863 .completion_provider
2864 .as_ref()
2865 .and_then(|provider| {
2866 provider
2867 .trigger_characters
2868 .as_ref()
2869 .map(|characters| characters.iter().cloned().collect())
2870 })
2871 .unwrap_or_default(),
2872 cx,
2873 );
2874 });
2875
2876 let snapshot = LspBufferSnapshot {
2877 version: 0,
2878 snapshot: initial_snapshot.clone(),
2879 };
2880
2881 let mut registered = false;
2882 self.buffer_snapshots
2883 .entry(buffer_id)
2884 .or_default()
2885 .entry(server.server_id())
2886 .or_insert_with(|| {
2887 registered = true;
2888 server.register_buffer(
2889 uri.clone(),
2890 adapter.language_id(&language.name()),
2891 0,
2892 initial_snapshot.text(),
2893 );
2894
2895 vec![snapshot]
2896 });
2897
2898 self.buffers_opened_in_servers
2899 .entry(buffer_id)
2900 .or_default()
2901 .insert(server.server_id());
2902 if registered {
2903 cx.emit(LspStoreEvent::LanguageServerUpdate {
2904 language_server_id: server.server_id(),
2905 name: None,
2906 message: proto::update_language_server::Variant::RegisteredForBuffer(
2907 proto::RegisteredForBuffer {
2908 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2909 buffer_id: buffer_id.to_proto(),
2910 },
2911 ),
2912 });
2913 }
2914 }
2915 }
2916
2917 fn reuse_existing_language_server<'lang_name>(
2918 &self,
2919 server_tree: &LanguageServerTree,
2920 worktree: &Entity<Worktree>,
2921 language_name: &'lang_name LanguageName,
2922 cx: &mut App,
2923 ) -> Option<(
2924 Arc<LocalLspAdapterDelegate>,
2925 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2926 )> {
2927 if worktree.read(cx).is_visible() {
2928 return None;
2929 }
2930
2931 let worktree_store = self.worktree_store.read(cx);
2932 let servers = server_tree
2933 .instances
2934 .iter()
2935 .filter(|(worktree_id, _)| {
2936 worktree_store
2937 .worktree_for_id(**worktree_id, cx)
2938 .is_some_and(|worktree| worktree.read(cx).is_visible())
2939 })
2940 .flat_map(|(worktree_id, servers)| {
2941 servers
2942 .roots
2943 .iter()
2944 .flat_map(|(_, language_servers)| language_servers)
2945 .map(move |(_, (server_node, server_languages))| {
2946 (worktree_id, server_node, server_languages)
2947 })
2948 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2949 .map(|(worktree_id, server_node, _)| {
2950 (
2951 *worktree_id,
2952 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2953 )
2954 })
2955 })
2956 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2957 acc.entry(worktree_id)
2958 .or_insert_with(Vec::new)
2959 .push(server_node);
2960 acc
2961 })
2962 .into_values()
2963 .max_by_key(|servers| servers.len())?;
2964
2965 let worktree_id = worktree.read(cx).id();
2966 let apply = move |tree: &mut LanguageServerTree| {
2967 for server_node in &servers {
2968 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2969 }
2970 servers
2971 };
2972
2973 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2974 Some((delegate, apply))
2975 }
2976
2977 pub(crate) fn unregister_old_buffer_from_language_servers(
2978 &mut self,
2979 buffer: &Entity<Buffer>,
2980 old_file: &File,
2981 cx: &mut App,
2982 ) {
2983 let old_path = match old_file.as_local() {
2984 Some(local) => local.abs_path(cx),
2985 None => return,
2986 };
2987
2988 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2989 debug_panic!("{old_path:?} is not parseable as an URI");
2990 return;
2991 };
2992 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2993 }
2994
2995 pub(crate) fn unregister_buffer_from_language_servers(
2996 &mut self,
2997 buffer: &Entity<Buffer>,
2998 file_url: &lsp::Uri,
2999 cx: &mut App,
3000 ) {
3001 buffer.update(cx, |buffer, cx| {
3002 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3003
3004 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3005 if snapshots
3006 .as_mut()
3007 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3008 {
3009 language_server.unregister_buffer(file_url.clone());
3010 }
3011 }
3012 });
3013 }
3014
3015 fn buffer_snapshot_for_lsp_version(
3016 &mut self,
3017 buffer: &Entity<Buffer>,
3018 server_id: LanguageServerId,
3019 version: Option<i32>,
3020 cx: &App,
3021 ) -> Result<TextBufferSnapshot> {
3022 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3023
3024 if let Some(version) = version {
3025 let buffer_id = buffer.read(cx).remote_id();
3026 let snapshots = if let Some(snapshots) = self
3027 .buffer_snapshots
3028 .get_mut(&buffer_id)
3029 .and_then(|m| m.get_mut(&server_id))
3030 {
3031 snapshots
3032 } else if version == 0 {
3033 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3034 // We detect this case and treat it as if the version was `None`.
3035 return Ok(buffer.read(cx).text_snapshot());
3036 } else {
3037 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3038 };
3039
3040 let found_snapshot = snapshots
3041 .binary_search_by_key(&version, |e| e.version)
3042 .map(|ix| snapshots[ix].snapshot.clone())
3043 .map_err(|_| {
3044 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3045 })?;
3046
3047 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3048 Ok(found_snapshot)
3049 } else {
3050 Ok((buffer.read(cx)).text_snapshot())
3051 }
3052 }
3053
3054 async fn get_server_code_actions_from_action_kinds(
3055 lsp_store: &WeakEntity<LspStore>,
3056 language_server_id: LanguageServerId,
3057 code_action_kinds: Vec<lsp::CodeActionKind>,
3058 buffer: &Entity<Buffer>,
3059 cx: &mut AsyncApp,
3060 ) -> Result<Vec<CodeAction>> {
3061 let actions = lsp_store
3062 .update(cx, move |this, cx| {
3063 let request = GetCodeActions {
3064 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3065 kinds: Some(code_action_kinds),
3066 };
3067 let server = LanguageServerToQuery::Other(language_server_id);
3068 this.request_lsp(buffer.clone(), server, request, cx)
3069 })?
3070 .await?;
3071 Ok(actions)
3072 }
3073
3074 pub async fn execute_code_actions_on_server(
3075 lsp_store: &WeakEntity<LspStore>,
3076 language_server: &Arc<LanguageServer>,
3077 actions: Vec<CodeAction>,
3078 push_to_history: bool,
3079 project_transaction: &mut ProjectTransaction,
3080 cx: &mut AsyncApp,
3081 ) -> anyhow::Result<()> {
3082 let request_timeout = cx.update(|app| {
3083 ProjectSettings::get_global(app)
3084 .global_lsp_settings
3085 .get_request_timeout()
3086 });
3087
3088 for mut action in actions {
3089 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3090 .await
3091 .context("resolving a formatting code action")?;
3092
3093 if let Some(edit) = action.lsp_action.edit() {
3094 if edit.changes.is_none() && edit.document_changes.is_none() {
3095 continue;
3096 }
3097
3098 let new = Self::deserialize_workspace_edit(
3099 lsp_store.upgrade().context("project dropped")?,
3100 edit.clone(),
3101 push_to_history,
3102 language_server.clone(),
3103 cx,
3104 )
3105 .await?;
3106 project_transaction.0.extend(new.0);
3107 }
3108
3109 let Some(command) = action.lsp_action.command() else {
3110 continue;
3111 };
3112
3113 let server_capabilities = language_server.capabilities();
3114 let available_commands = server_capabilities
3115 .execute_command_provider
3116 .as_ref()
3117 .map(|options| options.commands.as_slice())
3118 .unwrap_or_default();
3119 if !available_commands.contains(&command.command) {
3120 log::warn!(
3121 "Cannot execute a command {} not listed in the language server capabilities",
3122 command.command
3123 );
3124 continue;
3125 }
3126
3127 lsp_store.update(cx, |lsp_store, _| {
3128 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3129 mode.last_workspace_edits_by_language_server
3130 .remove(&language_server.server_id());
3131 }
3132 })?;
3133
3134 language_server
3135 .request::<lsp::request::ExecuteCommand>(
3136 lsp::ExecuteCommandParams {
3137 command: command.command.clone(),
3138 arguments: command.arguments.clone().unwrap_or_default(),
3139 ..Default::default()
3140 },
3141 request_timeout,
3142 )
3143 .await
3144 .into_response()
3145 .context("execute command")?;
3146
3147 lsp_store.update(cx, |this, _| {
3148 if let LspStoreMode::Local(mode) = &mut this.mode {
3149 project_transaction.0.extend(
3150 mode.last_workspace_edits_by_language_server
3151 .remove(&language_server.server_id())
3152 .unwrap_or_default()
3153 .0,
3154 )
3155 }
3156 })?;
3157 }
3158 Ok(())
3159 }
3160
3161 pub async fn deserialize_text_edits(
3162 this: Entity<LspStore>,
3163 buffer_to_edit: Entity<Buffer>,
3164 edits: Vec<lsp::TextEdit>,
3165 push_to_history: bool,
3166 _: Arc<CachedLspAdapter>,
3167 language_server: Arc<LanguageServer>,
3168 cx: &mut AsyncApp,
3169 ) -> Result<Option<Transaction>> {
3170 let edits = this
3171 .update(cx, |this, cx| {
3172 this.as_local_mut().unwrap().edits_from_lsp(
3173 &buffer_to_edit,
3174 edits,
3175 language_server.server_id(),
3176 None,
3177 cx,
3178 )
3179 })
3180 .await?;
3181
3182 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3183 buffer.finalize_last_transaction();
3184 buffer.start_transaction();
3185 for (range, text) in edits {
3186 buffer.edit([(range, text)], None, cx);
3187 }
3188
3189 if buffer.end_transaction(cx).is_some() {
3190 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3191 if !push_to_history {
3192 buffer.forget_transaction(transaction.id);
3193 }
3194 Some(transaction)
3195 } else {
3196 None
3197 }
3198 });
3199
3200 Ok(transaction)
3201 }
3202
3203 #[allow(clippy::type_complexity)]
3204 pub fn edits_from_lsp(
3205 &mut self,
3206 buffer: &Entity<Buffer>,
3207 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3208 server_id: LanguageServerId,
3209 version: Option<i32>,
3210 cx: &mut Context<LspStore>,
3211 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3212 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3213 cx.background_spawn(async move {
3214 let snapshot = snapshot?;
3215 let mut lsp_edits = lsp_edits
3216 .into_iter()
3217 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3218 .collect::<Vec<_>>();
3219
3220 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3221
3222 let mut lsp_edits = lsp_edits.into_iter().peekable();
3223 let mut edits = Vec::new();
3224 while let Some((range, mut new_text)) = lsp_edits.next() {
3225 // Clip invalid ranges provided by the language server.
3226 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3227 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3228
3229 // Combine any LSP edits that are adjacent.
3230 //
3231 // Also, combine LSP edits that are separated from each other by only
3232 // a newline. This is important because for some code actions,
3233 // Rust-analyzer rewrites the entire buffer via a series of edits that
3234 // are separated by unchanged newline characters.
3235 //
3236 // In order for the diffing logic below to work properly, any edits that
3237 // cancel each other out must be combined into one.
3238 while let Some((next_range, next_text)) = lsp_edits.peek() {
3239 if next_range.start.0 > range.end {
3240 if next_range.start.0.row > range.end.row + 1
3241 || next_range.start.0.column > 0
3242 || snapshot.clip_point_utf16(
3243 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3244 Bias::Left,
3245 ) > range.end
3246 {
3247 break;
3248 }
3249 new_text.push('\n');
3250 }
3251 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3252 new_text.push_str(next_text);
3253 lsp_edits.next();
3254 }
3255
3256 // For multiline edits, perform a diff of the old and new text so that
3257 // we can identify the changes more precisely, preserving the locations
3258 // of any anchors positioned in the unchanged regions.
3259 if range.end.row > range.start.row {
3260 let offset = range.start.to_offset(&snapshot);
3261 let old_text = snapshot.text_for_range(range).collect::<String>();
3262 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3263 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3264 (
3265 snapshot.anchor_after(offset + range.start)
3266 ..snapshot.anchor_before(offset + range.end),
3267 replacement,
3268 )
3269 }));
3270 } else if range.end == range.start {
3271 let anchor = snapshot.anchor_after(range.start);
3272 edits.push((anchor..anchor, new_text.into()));
3273 } else {
3274 let edit_start = snapshot.anchor_after(range.start);
3275 let edit_end = snapshot.anchor_before(range.end);
3276 edits.push((edit_start..edit_end, new_text.into()));
3277 }
3278 }
3279
3280 Ok(edits)
3281 })
3282 }
3283
3284 pub(crate) async fn deserialize_workspace_edit(
3285 this: Entity<LspStore>,
3286 edit: lsp::WorkspaceEdit,
3287 push_to_history: bool,
3288 language_server: Arc<LanguageServer>,
3289 cx: &mut AsyncApp,
3290 ) -> Result<ProjectTransaction> {
3291 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3292
3293 let mut operations = Vec::new();
3294 if let Some(document_changes) = edit.document_changes {
3295 match document_changes {
3296 lsp::DocumentChanges::Edits(edits) => {
3297 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3298 }
3299 lsp::DocumentChanges::Operations(ops) => operations = ops,
3300 }
3301 } else if let Some(changes) = edit.changes {
3302 operations.extend(changes.into_iter().map(|(uri, edits)| {
3303 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3304 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3305 uri,
3306 version: None,
3307 },
3308 edits: edits.into_iter().map(Edit::Plain).collect(),
3309 })
3310 }));
3311 }
3312
3313 let mut project_transaction = ProjectTransaction::default();
3314 for operation in operations {
3315 match operation {
3316 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3317 let abs_path = op
3318 .uri
3319 .to_file_path()
3320 .map_err(|()| anyhow!("can't convert URI to path"))?;
3321
3322 if let Some(parent_path) = abs_path.parent() {
3323 fs.create_dir(parent_path).await?;
3324 }
3325 if abs_path.ends_with("/") {
3326 fs.create_dir(&abs_path).await?;
3327 } else {
3328 fs.create_file(
3329 &abs_path,
3330 op.options
3331 .map(|options| fs::CreateOptions {
3332 overwrite: options.overwrite.unwrap_or(false),
3333 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3334 })
3335 .unwrap_or_default(),
3336 )
3337 .await?;
3338 }
3339 }
3340
3341 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3342 let source_abs_path = op
3343 .old_uri
3344 .to_file_path()
3345 .map_err(|()| anyhow!("can't convert URI to path"))?;
3346 let target_abs_path = op
3347 .new_uri
3348 .to_file_path()
3349 .map_err(|()| anyhow!("can't convert URI to path"))?;
3350
3351 let options = fs::RenameOptions {
3352 overwrite: op
3353 .options
3354 .as_ref()
3355 .and_then(|options| options.overwrite)
3356 .unwrap_or(false),
3357 ignore_if_exists: op
3358 .options
3359 .as_ref()
3360 .and_then(|options| options.ignore_if_exists)
3361 .unwrap_or(false),
3362 create_parents: true,
3363 };
3364
3365 fs.rename(&source_abs_path, &target_abs_path, options)
3366 .await?;
3367 }
3368
3369 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3370 let abs_path = op
3371 .uri
3372 .to_file_path()
3373 .map_err(|()| anyhow!("can't convert URI to path"))?;
3374 let options = op
3375 .options
3376 .map(|options| fs::RemoveOptions {
3377 recursive: options.recursive.unwrap_or(false),
3378 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3379 })
3380 .unwrap_or_default();
3381 if abs_path.ends_with("/") {
3382 fs.remove_dir(&abs_path, options).await?;
3383 } else {
3384 fs.remove_file(&abs_path, options).await?;
3385 }
3386 }
3387
3388 lsp::DocumentChangeOperation::Edit(op) => {
3389 let buffer_to_edit = this
3390 .update(cx, |this, cx| {
3391 this.open_local_buffer_via_lsp(
3392 op.text_document.uri.clone(),
3393 language_server.server_id(),
3394 cx,
3395 )
3396 })
3397 .await?;
3398
3399 let edits = this
3400 .update(cx, |this, cx| {
3401 let path = buffer_to_edit.read(cx).project_path(cx);
3402 let active_entry = this.active_entry;
3403 let is_active_entry = path.is_some_and(|project_path| {
3404 this.worktree_store
3405 .read(cx)
3406 .entry_for_path(&project_path, cx)
3407 .is_some_and(|entry| Some(entry.id) == active_entry)
3408 });
3409 let local = this.as_local_mut().unwrap();
3410
3411 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3412 for edit in op.edits {
3413 match edit {
3414 Edit::Plain(edit) => {
3415 if !edits.contains(&edit) {
3416 edits.push(edit)
3417 }
3418 }
3419 Edit::Annotated(edit) => {
3420 if !edits.contains(&edit.text_edit) {
3421 edits.push(edit.text_edit)
3422 }
3423 }
3424 Edit::Snippet(edit) => {
3425 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3426 else {
3427 continue;
3428 };
3429
3430 if is_active_entry {
3431 snippet_edits.push((edit.range, snippet));
3432 } else {
3433 // Since this buffer is not focused, apply a normal edit.
3434 let new_edit = TextEdit {
3435 range: edit.range,
3436 new_text: snippet.text,
3437 };
3438 if !edits.contains(&new_edit) {
3439 edits.push(new_edit);
3440 }
3441 }
3442 }
3443 }
3444 }
3445 if !snippet_edits.is_empty() {
3446 let buffer_id = buffer_to_edit.read(cx).remote_id();
3447 let version = if let Some(buffer_version) = op.text_document.version
3448 {
3449 local
3450 .buffer_snapshot_for_lsp_version(
3451 &buffer_to_edit,
3452 language_server.server_id(),
3453 Some(buffer_version),
3454 cx,
3455 )
3456 .ok()
3457 .map(|snapshot| snapshot.version)
3458 } else {
3459 Some(buffer_to_edit.read(cx).saved_version().clone())
3460 };
3461
3462 let most_recent_edit =
3463 version.and_then(|version| version.most_recent());
3464 // Check if the edit that triggered that edit has been made by this participant.
3465
3466 if let Some(most_recent_edit) = most_recent_edit {
3467 cx.emit(LspStoreEvent::SnippetEdit {
3468 buffer_id,
3469 edits: snippet_edits,
3470 most_recent_edit,
3471 });
3472 }
3473 }
3474
3475 local.edits_from_lsp(
3476 &buffer_to_edit,
3477 edits,
3478 language_server.server_id(),
3479 op.text_document.version,
3480 cx,
3481 )
3482 })
3483 .await?;
3484
3485 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3486 buffer.finalize_last_transaction();
3487 buffer.start_transaction();
3488 for (range, text) in edits {
3489 buffer.edit([(range, text)], None, cx);
3490 }
3491
3492 buffer.end_transaction(cx).and_then(|transaction_id| {
3493 if push_to_history {
3494 buffer.finalize_last_transaction();
3495 buffer.get_transaction(transaction_id).cloned()
3496 } else {
3497 buffer.forget_transaction(transaction_id)
3498 }
3499 })
3500 });
3501 if let Some(transaction) = transaction {
3502 project_transaction.0.insert(buffer_to_edit, transaction);
3503 }
3504 }
3505 }
3506 }
3507
3508 Ok(project_transaction)
3509 }
3510
3511 async fn on_lsp_workspace_edit(
3512 this: WeakEntity<LspStore>,
3513 params: lsp::ApplyWorkspaceEditParams,
3514 server_id: LanguageServerId,
3515 cx: &mut AsyncApp,
3516 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3517 let this = this.upgrade().context("project project closed")?;
3518 let language_server = this
3519 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3520 .context("language server not found")?;
3521 let transaction = Self::deserialize_workspace_edit(
3522 this.clone(),
3523 params.edit,
3524 true,
3525 language_server.clone(),
3526 cx,
3527 )
3528 .await
3529 .log_err();
3530 this.update(cx, |this, cx| {
3531 if let Some(transaction) = transaction {
3532 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3533
3534 this.as_local_mut()
3535 .unwrap()
3536 .last_workspace_edits_by_language_server
3537 .insert(server_id, transaction);
3538 }
3539 });
3540 Ok(lsp::ApplyWorkspaceEditResponse {
3541 applied: true,
3542 failed_change: None,
3543 failure_reason: None,
3544 })
3545 }
3546
3547 fn remove_worktree(
3548 &mut self,
3549 id_to_remove: WorktreeId,
3550 cx: &mut Context<LspStore>,
3551 ) -> Vec<LanguageServerId> {
3552 self.restricted_worktrees_tasks.remove(&id_to_remove);
3553 self.diagnostics.remove(&id_to_remove);
3554 self.prettier_store.update(cx, |prettier_store, cx| {
3555 prettier_store.remove_worktree(id_to_remove, cx);
3556 });
3557
3558 let mut servers_to_remove = BTreeSet::default();
3559 let mut servers_to_preserve = HashSet::default();
3560 for (seed, state) in &self.language_server_ids {
3561 if seed.worktree_id == id_to_remove {
3562 servers_to_remove.insert(state.id);
3563 } else {
3564 servers_to_preserve.insert(state.id);
3565 }
3566 }
3567 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3568 self.language_server_ids
3569 .retain(|_, state| !servers_to_remove.contains(&state.id));
3570 for server_id_to_remove in &servers_to_remove {
3571 self.language_server_watched_paths
3572 .remove(server_id_to_remove);
3573 self.language_server_paths_watched_for_rename
3574 .remove(server_id_to_remove);
3575 self.last_workspace_edits_by_language_server
3576 .remove(server_id_to_remove);
3577 self.language_servers.remove(server_id_to_remove);
3578 self.buffer_pull_diagnostics_result_ids
3579 .remove(server_id_to_remove);
3580 self.workspace_pull_diagnostics_result_ids
3581 .remove(server_id_to_remove);
3582 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3583 buffer_servers.remove(server_id_to_remove);
3584 }
3585 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3586 }
3587 servers_to_remove.into_iter().collect()
3588 }
3589
3590 fn rebuild_watched_paths_inner<'a>(
3591 &'a self,
3592 language_server_id: LanguageServerId,
3593 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3594 cx: &mut Context<LspStore>,
3595 ) -> LanguageServerWatchedPathsBuilder {
3596 let worktrees = self
3597 .worktree_store
3598 .read(cx)
3599 .worktrees()
3600 .filter_map(|worktree| {
3601 self.language_servers_for_worktree(worktree.read(cx).id())
3602 .find(|server| server.server_id() == language_server_id)
3603 .map(|_| worktree)
3604 })
3605 .collect::<Vec<_>>();
3606
3607 let mut worktree_globs = HashMap::default();
3608 let mut abs_globs = HashMap::default();
3609 log::trace!(
3610 "Processing new watcher paths for language server with id {}",
3611 language_server_id
3612 );
3613
3614 for watcher in watchers {
3615 if let Some((worktree, literal_prefix, pattern)) =
3616 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3617 {
3618 worktree.update(cx, |worktree, _| {
3619 if let Some((tree, glob)) =
3620 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3621 {
3622 tree.add_path_prefix_to_scan(literal_prefix);
3623 worktree_globs
3624 .entry(tree.id())
3625 .or_insert_with(GlobSetBuilder::new)
3626 .add(glob);
3627 }
3628 });
3629 } else {
3630 let (path, pattern) = match &watcher.glob_pattern {
3631 lsp::GlobPattern::String(s) => {
3632 let watcher_path = SanitizedPath::new(s);
3633 let path = glob_literal_prefix(watcher_path.as_path());
3634 let pattern = watcher_path
3635 .as_path()
3636 .strip_prefix(&path)
3637 .map(|p| p.to_string_lossy().into_owned())
3638 .unwrap_or_else(|e| {
3639 debug_panic!(
3640 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3641 s,
3642 path.display(),
3643 e
3644 );
3645 watcher_path.as_path().to_string_lossy().into_owned()
3646 });
3647 (path, pattern)
3648 }
3649 lsp::GlobPattern::Relative(rp) => {
3650 let Ok(mut base_uri) = match &rp.base_uri {
3651 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3652 lsp::OneOf::Right(base_uri) => base_uri,
3653 }
3654 .to_file_path() else {
3655 continue;
3656 };
3657
3658 let path = glob_literal_prefix(Path::new(&rp.pattern));
3659 let pattern = Path::new(&rp.pattern)
3660 .strip_prefix(&path)
3661 .map(|p| p.to_string_lossy().into_owned())
3662 .unwrap_or_else(|e| {
3663 debug_panic!(
3664 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3665 rp.pattern,
3666 path.display(),
3667 e
3668 );
3669 rp.pattern.clone()
3670 });
3671 base_uri.push(path);
3672 (base_uri, pattern)
3673 }
3674 };
3675
3676 if let Some(glob) = Glob::new(&pattern).log_err() {
3677 if !path
3678 .components()
3679 .any(|c| matches!(c, path::Component::Normal(_)))
3680 {
3681 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3682 // rather than adding a new watcher for `/`.
3683 for worktree in &worktrees {
3684 worktree_globs
3685 .entry(worktree.read(cx).id())
3686 .or_insert_with(GlobSetBuilder::new)
3687 .add(glob.clone());
3688 }
3689 } else {
3690 abs_globs
3691 .entry(path.into())
3692 .or_insert_with(GlobSetBuilder::new)
3693 .add(glob);
3694 }
3695 }
3696 }
3697 }
3698
3699 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3700 for (worktree_id, builder) in worktree_globs {
3701 if let Ok(globset) = builder.build() {
3702 watch_builder.watch_worktree(worktree_id, globset);
3703 }
3704 }
3705 for (abs_path, builder) in abs_globs {
3706 if let Ok(globset) = builder.build() {
3707 watch_builder.watch_abs_path(abs_path, globset);
3708 }
3709 }
3710 watch_builder
3711 }
3712
3713 fn worktree_and_path_for_file_watcher(
3714 worktrees: &[Entity<Worktree>],
3715 watcher: &FileSystemWatcher,
3716 cx: &App,
3717 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3718 worktrees.iter().find_map(|worktree| {
3719 let tree = worktree.read(cx);
3720 let worktree_root_path = tree.abs_path();
3721 let path_style = tree.path_style();
3722 match &watcher.glob_pattern {
3723 lsp::GlobPattern::String(s) => {
3724 let watcher_path = SanitizedPath::new(s);
3725 let relative = watcher_path
3726 .as_path()
3727 .strip_prefix(&worktree_root_path)
3728 .ok()?;
3729 let literal_prefix = glob_literal_prefix(relative);
3730 Some((
3731 worktree.clone(),
3732 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3733 relative.to_string_lossy().into_owned(),
3734 ))
3735 }
3736 lsp::GlobPattern::Relative(rp) => {
3737 let base_uri = match &rp.base_uri {
3738 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3739 lsp::OneOf::Right(base_uri) => base_uri,
3740 }
3741 .to_file_path()
3742 .ok()?;
3743 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3744 let mut literal_prefix = relative.to_owned();
3745 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3746 Some((
3747 worktree.clone(),
3748 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3749 rp.pattern.clone(),
3750 ))
3751 }
3752 }
3753 })
3754 }
3755
3756 fn rebuild_watched_paths(
3757 &mut self,
3758 language_server_id: LanguageServerId,
3759 cx: &mut Context<LspStore>,
3760 ) {
3761 let Some(registrations) = self
3762 .language_server_dynamic_registrations
3763 .get(&language_server_id)
3764 else {
3765 return;
3766 };
3767
3768 let watch_builder = self.rebuild_watched_paths_inner(
3769 language_server_id,
3770 registrations.did_change_watched_files.values().flatten(),
3771 cx,
3772 );
3773 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3774 self.language_server_watched_paths
3775 .insert(language_server_id, watcher);
3776
3777 cx.notify();
3778 }
3779
3780 fn on_lsp_did_change_watched_files(
3781 &mut self,
3782 language_server_id: LanguageServerId,
3783 registration_id: &str,
3784 params: DidChangeWatchedFilesRegistrationOptions,
3785 cx: &mut Context<LspStore>,
3786 ) {
3787 let registrations = self
3788 .language_server_dynamic_registrations
3789 .entry(language_server_id)
3790 .or_default();
3791
3792 registrations
3793 .did_change_watched_files
3794 .insert(registration_id.to_string(), params.watchers);
3795
3796 self.rebuild_watched_paths(language_server_id, cx);
3797 }
3798
3799 fn on_lsp_unregister_did_change_watched_files(
3800 &mut self,
3801 language_server_id: LanguageServerId,
3802 registration_id: &str,
3803 cx: &mut Context<LspStore>,
3804 ) {
3805 let registrations = self
3806 .language_server_dynamic_registrations
3807 .entry(language_server_id)
3808 .or_default();
3809
3810 if registrations
3811 .did_change_watched_files
3812 .remove(registration_id)
3813 .is_some()
3814 {
3815 log::info!(
3816 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3817 language_server_id,
3818 registration_id
3819 );
3820 } else {
3821 log::warn!(
3822 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3823 language_server_id,
3824 registration_id
3825 );
3826 }
3827
3828 self.rebuild_watched_paths(language_server_id, cx);
3829 }
3830
3831 async fn initialization_options_for_adapter(
3832 adapter: Arc<dyn LspAdapter>,
3833 delegate: &Arc<dyn LspAdapterDelegate>,
3834 cx: &mut AsyncApp,
3835 ) -> Result<Option<serde_json::Value>> {
3836 let Some(mut initialization_config) =
3837 adapter.clone().initialization_options(delegate, cx).await?
3838 else {
3839 return Ok(None);
3840 };
3841
3842 for other_adapter in delegate.registered_lsp_adapters() {
3843 if other_adapter.name() == adapter.name() {
3844 continue;
3845 }
3846 if let Ok(Some(target_config)) = other_adapter
3847 .clone()
3848 .additional_initialization_options(adapter.name(), delegate)
3849 .await
3850 {
3851 merge_json_value_into(target_config.clone(), &mut initialization_config);
3852 }
3853 }
3854
3855 Ok(Some(initialization_config))
3856 }
3857
3858 async fn workspace_configuration_for_adapter(
3859 adapter: Arc<dyn LspAdapter>,
3860 delegate: &Arc<dyn LspAdapterDelegate>,
3861 toolchain: Option<Toolchain>,
3862 requested_uri: Option<Uri>,
3863 cx: &mut AsyncApp,
3864 ) -> Result<serde_json::Value> {
3865 let mut workspace_config = adapter
3866 .clone()
3867 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3868 .await?;
3869
3870 for other_adapter in delegate.registered_lsp_adapters() {
3871 if other_adapter.name() == adapter.name() {
3872 continue;
3873 }
3874 if let Ok(Some(target_config)) = other_adapter
3875 .clone()
3876 .additional_workspace_configuration(adapter.name(), delegate, cx)
3877 .await
3878 {
3879 merge_json_value_into(target_config.clone(), &mut workspace_config);
3880 }
3881 }
3882
3883 Ok(workspace_config)
3884 }
3885
3886 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3887 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3888 Some(server.clone())
3889 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3890 Some(Arc::clone(server))
3891 } else {
3892 None
3893 }
3894 }
3895}
3896
3897fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3898 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3899 cx.emit(LspStoreEvent::LanguageServerUpdate {
3900 language_server_id: server.server_id(),
3901 name: Some(server.name()),
3902 message: proto::update_language_server::Variant::MetadataUpdated(
3903 proto::ServerMetadataUpdated {
3904 capabilities: Some(capabilities),
3905 binary: Some(proto::LanguageServerBinaryInfo {
3906 path: server.binary().path.to_string_lossy().into_owned(),
3907 arguments: server
3908 .binary()
3909 .arguments
3910 .iter()
3911 .map(|arg| arg.to_string_lossy().into_owned())
3912 .collect(),
3913 }),
3914 configuration: serde_json::to_string(server.configuration()).ok(),
3915 workspace_folders: server
3916 .workspace_folders()
3917 .iter()
3918 .map(|uri| uri.to_string())
3919 .collect(),
3920 },
3921 ),
3922 });
3923 }
3924}
3925
3926#[derive(Debug)]
3927pub struct FormattableBuffer {
3928 handle: Entity<Buffer>,
3929 abs_path: Option<PathBuf>,
3930 env: Option<HashMap<String, String>>,
3931 ranges: Option<Vec<Range<Anchor>>>,
3932}
3933
3934pub struct RemoteLspStore {
3935 upstream_client: Option<AnyProtoClient>,
3936 upstream_project_id: u64,
3937}
3938
3939pub(crate) enum LspStoreMode {
3940 Local(LocalLspStore), // ssh host and collab host
3941 Remote(RemoteLspStore), // collab guest
3942}
3943
3944impl LspStoreMode {
3945 fn is_local(&self) -> bool {
3946 matches!(self, LspStoreMode::Local(_))
3947 }
3948}
3949
3950pub struct LspStore {
3951 mode: LspStoreMode,
3952 last_formatting_failure: Option<String>,
3953 downstream_client: Option<(AnyProtoClient, u64)>,
3954 nonce: u128,
3955 buffer_store: Entity<BufferStore>,
3956 worktree_store: Entity<WorktreeStore>,
3957 pub languages: Arc<LanguageRegistry>,
3958 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3959 active_entry: Option<ProjectEntryId>,
3960 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3961 _maintain_buffer_languages: Task<()>,
3962 diagnostic_summaries:
3963 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3964 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3965 semantic_token_config: SemanticTokenConfig,
3966 lsp_data: HashMap<BufferId, BufferLspData>,
3967 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3968 next_hint_id: Arc<AtomicUsize>,
3969}
3970
3971#[derive(Debug)]
3972pub struct BufferLspData {
3973 buffer_version: Global,
3974 document_colors: Option<DocumentColorData>,
3975 code_lens: Option<CodeLensData>,
3976 semantic_tokens: Option<SemanticTokensData>,
3977 folding_ranges: Option<FoldingRangeData>,
3978 document_symbols: Option<DocumentSymbolsData>,
3979 inlay_hints: BufferInlayHints,
3980 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3981 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3982}
3983
3984#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3985struct LspKey {
3986 request_type: TypeId,
3987 server_queried: Option<LanguageServerId>,
3988}
3989
3990impl BufferLspData {
3991 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3992 Self {
3993 buffer_version: buffer.read(cx).version(),
3994 document_colors: None,
3995 code_lens: None,
3996 semantic_tokens: None,
3997 folding_ranges: None,
3998 document_symbols: None,
3999 inlay_hints: BufferInlayHints::new(buffer, cx),
4000 lsp_requests: HashMap::default(),
4001 chunk_lsp_requests: HashMap::default(),
4002 }
4003 }
4004
4005 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4006 if let Some(document_colors) = &mut self.document_colors {
4007 document_colors.remove_server_data(for_server);
4008 }
4009
4010 if let Some(code_lens) = &mut self.code_lens {
4011 code_lens.remove_server_data(for_server);
4012 }
4013
4014 self.inlay_hints.remove_server_data(for_server);
4015
4016 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4017 semantic_tokens.remove_server_data(for_server);
4018 }
4019
4020 if let Some(folding_ranges) = &mut self.folding_ranges {
4021 folding_ranges.ranges.remove(&for_server);
4022 }
4023
4024 if let Some(document_symbols) = &mut self.document_symbols {
4025 document_symbols.remove_server_data(for_server);
4026 }
4027 }
4028
4029 #[cfg(any(test, feature = "test-support"))]
4030 pub fn inlay_hints(&self) -> &BufferInlayHints {
4031 &self.inlay_hints
4032 }
4033}
4034
4035#[derive(Debug)]
4036pub enum LspStoreEvent {
4037 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4038 LanguageServerRemoved(LanguageServerId),
4039 LanguageServerUpdate {
4040 language_server_id: LanguageServerId,
4041 name: Option<LanguageServerName>,
4042 message: proto::update_language_server::Variant,
4043 },
4044 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4045 LanguageServerPrompt(LanguageServerPromptRequest),
4046 LanguageDetected {
4047 buffer: Entity<Buffer>,
4048 new_language: Option<Arc<Language>>,
4049 },
4050 Notification(String),
4051 RefreshInlayHints {
4052 server_id: LanguageServerId,
4053 request_id: Option<usize>,
4054 },
4055 RefreshSemanticTokens {
4056 server_id: LanguageServerId,
4057 request_id: Option<usize>,
4058 },
4059 RefreshCodeLens,
4060 DiagnosticsUpdated {
4061 server_id: LanguageServerId,
4062 paths: Vec<ProjectPath>,
4063 },
4064 DiskBasedDiagnosticsStarted {
4065 language_server_id: LanguageServerId,
4066 },
4067 DiskBasedDiagnosticsFinished {
4068 language_server_id: LanguageServerId,
4069 },
4070 SnippetEdit {
4071 buffer_id: BufferId,
4072 edits: Vec<(lsp::Range, Snippet)>,
4073 most_recent_edit: clock::Lamport,
4074 },
4075 WorkspaceEditApplied(ProjectTransaction),
4076}
4077
4078#[derive(Clone, Debug, Serialize)]
4079pub struct LanguageServerStatus {
4080 pub name: LanguageServerName,
4081 pub server_version: Option<SharedString>,
4082 pub server_readable_version: Option<SharedString>,
4083 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4084 pub has_pending_diagnostic_updates: bool,
4085 pub progress_tokens: HashSet<ProgressToken>,
4086 pub worktree: Option<WorktreeId>,
4087 pub binary: Option<LanguageServerBinary>,
4088 pub configuration: Option<Value>,
4089 pub workspace_folders: BTreeSet<Uri>,
4090 pub process_id: Option<u32>,
4091}
4092
4093#[derive(Clone, Debug)]
4094struct CoreSymbol {
4095 pub language_server_name: LanguageServerName,
4096 pub source_worktree_id: WorktreeId,
4097 pub source_language_server_id: LanguageServerId,
4098 pub path: SymbolLocation,
4099 pub name: String,
4100 pub kind: lsp::SymbolKind,
4101 pub range: Range<Unclipped<PointUtf16>>,
4102 pub container_name: Option<String>,
4103}
4104
4105#[derive(Clone, Debug, PartialEq, Eq)]
4106pub enum SymbolLocation {
4107 InProject(ProjectPath),
4108 OutsideProject {
4109 abs_path: Arc<Path>,
4110 signature: [u8; 32],
4111 },
4112}
4113
4114impl SymbolLocation {
4115 fn file_name(&self) -> Option<&str> {
4116 match self {
4117 Self::InProject(path) => path.path.file_name(),
4118 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4119 }
4120 }
4121}
4122
4123impl LspStore {
4124 pub fn init(client: &AnyProtoClient) {
4125 client.add_entity_request_handler(Self::handle_lsp_query);
4126 client.add_entity_message_handler(Self::handle_lsp_query_response);
4127 client.add_entity_request_handler(Self::handle_restart_language_servers);
4128 client.add_entity_request_handler(Self::handle_stop_language_servers);
4129 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4130 client.add_entity_message_handler(Self::handle_start_language_server);
4131 client.add_entity_message_handler(Self::handle_update_language_server);
4132 client.add_entity_message_handler(Self::handle_language_server_log);
4133 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4134 client.add_entity_request_handler(Self::handle_format_buffers);
4135 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4136 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4137 client.add_entity_request_handler(Self::handle_apply_code_action);
4138 client.add_entity_request_handler(Self::handle_get_project_symbols);
4139 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4140 client.add_entity_request_handler(Self::handle_get_color_presentation);
4141 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4142 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4143 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4144 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4145 client.add_entity_request_handler(Self::handle_on_type_formatting);
4146 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4147 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4148 client.add_entity_request_handler(Self::handle_rename_project_entry);
4149 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4150 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4151 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4152 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4153 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4154 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4155 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4156
4157 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4158 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4159 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4160 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4161 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4162 client.add_entity_request_handler(
4163 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4164 );
4165 client.add_entity_request_handler(
4166 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4167 );
4168 client.add_entity_request_handler(
4169 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4170 );
4171 }
4172
4173 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4174 match &self.mode {
4175 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4176 _ => None,
4177 }
4178 }
4179
4180 pub fn as_local(&self) -> Option<&LocalLspStore> {
4181 match &self.mode {
4182 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4183 _ => None,
4184 }
4185 }
4186
4187 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4188 match &mut self.mode {
4189 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4190 _ => None,
4191 }
4192 }
4193
4194 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4195 match &self.mode {
4196 LspStoreMode::Remote(RemoteLspStore {
4197 upstream_client: Some(upstream_client),
4198 upstream_project_id,
4199 ..
4200 }) => Some((upstream_client.clone(), *upstream_project_id)),
4201
4202 LspStoreMode::Remote(RemoteLspStore {
4203 upstream_client: None,
4204 ..
4205 }) => None,
4206 LspStoreMode::Local(_) => None,
4207 }
4208 }
4209
4210 pub fn new_local(
4211 buffer_store: Entity<BufferStore>,
4212 worktree_store: Entity<WorktreeStore>,
4213 prettier_store: Entity<PrettierStore>,
4214 toolchain_store: Entity<LocalToolchainStore>,
4215 environment: Entity<ProjectEnvironment>,
4216 manifest_tree: Entity<ManifestTree>,
4217 languages: Arc<LanguageRegistry>,
4218 http_client: Arc<dyn HttpClient>,
4219 fs: Arc<dyn Fs>,
4220 cx: &mut Context<Self>,
4221 ) -> Self {
4222 let yarn = YarnPathStore::new(fs.clone(), cx);
4223 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4224 .detach();
4225 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4226 .detach();
4227 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4228 .detach();
4229 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4230 .detach();
4231 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4232 .detach();
4233 subscribe_to_binary_statuses(&languages, cx).detach();
4234
4235 let _maintain_workspace_config = {
4236 let (sender, receiver) = watch::channel();
4237 (Self::maintain_workspace_config(receiver, cx), sender)
4238 };
4239
4240 Self {
4241 mode: LspStoreMode::Local(LocalLspStore {
4242 weak: cx.weak_entity(),
4243 worktree_store: worktree_store.clone(),
4244
4245 supplementary_language_servers: Default::default(),
4246 languages: languages.clone(),
4247 language_server_ids: Default::default(),
4248 language_servers: Default::default(),
4249 last_workspace_edits_by_language_server: Default::default(),
4250 language_server_watched_paths: Default::default(),
4251 language_server_paths_watched_for_rename: Default::default(),
4252 language_server_dynamic_registrations: Default::default(),
4253 buffers_being_formatted: Default::default(),
4254 buffers_to_refresh_hash_set: HashSet::default(),
4255 buffers_to_refresh_queue: VecDeque::new(),
4256 _background_diagnostics_worker: Task::ready(()).shared(),
4257 buffer_snapshots: Default::default(),
4258 prettier_store,
4259 environment,
4260 http_client,
4261 fs,
4262 yarn,
4263 next_diagnostic_group_id: Default::default(),
4264 diagnostics: Default::default(),
4265 _subscription: cx.on_app_quit(|this, _| {
4266 this.as_local_mut()
4267 .unwrap()
4268 .shutdown_language_servers_on_quit()
4269 }),
4270 lsp_tree: LanguageServerTree::new(
4271 manifest_tree,
4272 languages.clone(),
4273 toolchain_store.clone(),
4274 ),
4275 toolchain_store,
4276 registered_buffers: HashMap::default(),
4277 buffers_opened_in_servers: HashMap::default(),
4278 buffer_pull_diagnostics_result_ids: HashMap::default(),
4279 workspace_pull_diagnostics_result_ids: HashMap::default(),
4280 restricted_worktrees_tasks: HashMap::default(),
4281 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4282 .manifest_file_names(),
4283 }),
4284 last_formatting_failure: None,
4285 downstream_client: None,
4286 buffer_store,
4287 worktree_store,
4288 languages: languages.clone(),
4289 language_server_statuses: Default::default(),
4290 nonce: StdRng::from_os_rng().random(),
4291 diagnostic_summaries: HashMap::default(),
4292 lsp_server_capabilities: HashMap::default(),
4293 semantic_token_config: SemanticTokenConfig::new(cx),
4294 lsp_data: HashMap::default(),
4295 buffer_reload_tasks: HashMap::default(),
4296 next_hint_id: Arc::default(),
4297 active_entry: None,
4298 _maintain_workspace_config,
4299 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4300 }
4301 }
4302
4303 fn send_lsp_proto_request<R: LspCommand>(
4304 &self,
4305 buffer: Entity<Buffer>,
4306 client: AnyProtoClient,
4307 upstream_project_id: u64,
4308 request: R,
4309 cx: &mut Context<LspStore>,
4310 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4311 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4312 return Task::ready(Ok(R::Response::default()));
4313 }
4314 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4315 cx.spawn(async move |this, cx| {
4316 let response = client.request(message).await?;
4317 let this = this.upgrade().context("project dropped")?;
4318 request
4319 .response_from_proto(response, this, buffer, cx.clone())
4320 .await
4321 })
4322 }
4323
4324 pub(super) fn new_remote(
4325 buffer_store: Entity<BufferStore>,
4326 worktree_store: Entity<WorktreeStore>,
4327 languages: Arc<LanguageRegistry>,
4328 upstream_client: AnyProtoClient,
4329 project_id: u64,
4330 cx: &mut Context<Self>,
4331 ) -> Self {
4332 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4333 .detach();
4334 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4335 .detach();
4336 subscribe_to_binary_statuses(&languages, cx).detach();
4337 let _maintain_workspace_config = {
4338 let (sender, receiver) = watch::channel();
4339 (Self::maintain_workspace_config(receiver, cx), sender)
4340 };
4341 Self {
4342 mode: LspStoreMode::Remote(RemoteLspStore {
4343 upstream_client: Some(upstream_client),
4344 upstream_project_id: project_id,
4345 }),
4346 downstream_client: None,
4347 last_formatting_failure: None,
4348 buffer_store,
4349 worktree_store,
4350 languages: languages.clone(),
4351 language_server_statuses: Default::default(),
4352 nonce: StdRng::from_os_rng().random(),
4353 diagnostic_summaries: HashMap::default(),
4354 lsp_server_capabilities: HashMap::default(),
4355 semantic_token_config: SemanticTokenConfig::new(cx),
4356 next_hint_id: Arc::default(),
4357 lsp_data: HashMap::default(),
4358 buffer_reload_tasks: HashMap::default(),
4359 active_entry: None,
4360
4361 _maintain_workspace_config,
4362 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4363 }
4364 }
4365
4366 fn on_buffer_store_event(
4367 &mut self,
4368 _: Entity<BufferStore>,
4369 event: &BufferStoreEvent,
4370 cx: &mut Context<Self>,
4371 ) {
4372 match event {
4373 BufferStoreEvent::BufferAdded(buffer) => {
4374 self.on_buffer_added(buffer, cx).log_err();
4375 }
4376 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4377 let buffer_id = buffer.read(cx).remote_id();
4378 if let Some(local) = self.as_local_mut()
4379 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4380 {
4381 local.reset_buffer(buffer, old_file, cx);
4382
4383 if local.registered_buffers.contains_key(&buffer_id) {
4384 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4385 }
4386 }
4387
4388 self.detect_language_for_buffer(buffer, cx);
4389 if let Some(local) = self.as_local_mut() {
4390 local.initialize_buffer(buffer, cx);
4391 if local.registered_buffers.contains_key(&buffer_id) {
4392 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4393 }
4394 }
4395 }
4396 _ => {}
4397 }
4398 }
4399
4400 fn on_worktree_store_event(
4401 &mut self,
4402 _: Entity<WorktreeStore>,
4403 event: &WorktreeStoreEvent,
4404 cx: &mut Context<Self>,
4405 ) {
4406 match event {
4407 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4408 if !worktree.read(cx).is_local() {
4409 return;
4410 }
4411 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4412 worktree::Event::UpdatedEntries(changes) => {
4413 this.update_local_worktree_language_servers(&worktree, changes, cx);
4414 }
4415 worktree::Event::UpdatedGitRepositories(_)
4416 | worktree::Event::DeletedEntry(_) => {}
4417 })
4418 .detach()
4419 }
4420 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4421 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4422 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4423 }
4424 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4425 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4426 }
4427 WorktreeStoreEvent::WorktreeReleased(..)
4428 | WorktreeStoreEvent::WorktreeOrderChanged
4429 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4430 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4431 }
4432 }
4433
4434 fn on_prettier_store_event(
4435 &mut self,
4436 _: Entity<PrettierStore>,
4437 event: &PrettierStoreEvent,
4438 cx: &mut Context<Self>,
4439 ) {
4440 match event {
4441 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4442 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4443 }
4444 PrettierStoreEvent::LanguageServerAdded {
4445 new_server_id,
4446 name,
4447 prettier_server,
4448 } => {
4449 self.register_supplementary_language_server(
4450 *new_server_id,
4451 name.clone(),
4452 prettier_server.clone(),
4453 cx,
4454 );
4455 }
4456 }
4457 }
4458
4459 fn on_toolchain_store_event(
4460 &mut self,
4461 _: Entity<LocalToolchainStore>,
4462 event: &ToolchainStoreEvent,
4463 _: &mut Context<Self>,
4464 ) {
4465 if let ToolchainStoreEvent::ToolchainActivated = event {
4466 self.request_workspace_config_refresh()
4467 }
4468 }
4469
4470 fn request_workspace_config_refresh(&mut self) {
4471 *self._maintain_workspace_config.1.borrow_mut() = ();
4472 }
4473
4474 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4475 self.as_local().map(|local| local.prettier_store.clone())
4476 }
4477
4478 fn on_buffer_event(
4479 &mut self,
4480 buffer: Entity<Buffer>,
4481 event: &language::BufferEvent,
4482 cx: &mut Context<Self>,
4483 ) {
4484 match event {
4485 language::BufferEvent::Edited { .. } => {
4486 self.on_buffer_edited(buffer, cx);
4487 }
4488
4489 language::BufferEvent::Saved => {
4490 self.on_buffer_saved(buffer, cx);
4491 }
4492
4493 language::BufferEvent::Reloaded => {
4494 self.on_buffer_reloaded(buffer, cx);
4495 }
4496
4497 _ => {}
4498 }
4499 }
4500
4501 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4502 buffer
4503 .read(cx)
4504 .set_language_registry(self.languages.clone());
4505
4506 cx.subscribe(buffer, |this, buffer, event, cx| {
4507 this.on_buffer_event(buffer, event, cx);
4508 })
4509 .detach();
4510
4511 self.parse_modeline(buffer, cx);
4512 self.detect_language_for_buffer(buffer, cx);
4513 if let Some(local) = self.as_local_mut() {
4514 local.initialize_buffer(buffer, cx);
4515 }
4516
4517 Ok(())
4518 }
4519
4520 pub fn refresh_background_diagnostics_for_buffers(
4521 &mut self,
4522 buffers: HashSet<BufferId>,
4523 cx: &mut Context<Self>,
4524 ) -> Shared<Task<()>> {
4525 let Some(local) = self.as_local_mut() else {
4526 return Task::ready(()).shared();
4527 };
4528 for buffer in buffers {
4529 if local.buffers_to_refresh_hash_set.insert(buffer) {
4530 local.buffers_to_refresh_queue.push_back(buffer);
4531 if local.buffers_to_refresh_queue.len() == 1 {
4532 local._background_diagnostics_worker =
4533 Self::background_diagnostics_worker(cx).shared();
4534 }
4535 }
4536 }
4537
4538 local._background_diagnostics_worker.clone()
4539 }
4540
4541 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4542 let buffer_store = self.buffer_store.clone();
4543 let local = self.as_local_mut()?;
4544 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4545 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4546 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4547 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4548 }
4549 }
4550 None
4551 }
4552
4553 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4554 cx.spawn(async move |this, cx| {
4555 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4556 task.await.log_err();
4557 }
4558 })
4559 }
4560
4561 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4562 if self.parse_modeline(&buffer, cx) {
4563 self.detect_language_for_buffer(&buffer, cx);
4564 }
4565
4566 let buffer_id = buffer.read(cx).remote_id();
4567 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4568 self.buffer_reload_tasks.insert(buffer_id, task);
4569 }
4570
4571 pub(crate) fn register_buffer_with_language_servers(
4572 &mut self,
4573 buffer: &Entity<Buffer>,
4574 only_register_servers: HashSet<LanguageServerSelector>,
4575 ignore_refcounts: bool,
4576 cx: &mut Context<Self>,
4577 ) -> OpenLspBufferHandle {
4578 let buffer_id = buffer.read(cx).remote_id();
4579 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4580 if let Some(local) = self.as_local_mut() {
4581 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4582 if !ignore_refcounts {
4583 *refcount += 1;
4584 }
4585
4586 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4587 // 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
4588 // 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
4589 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4590 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4591 return handle;
4592 };
4593 if !file.is_local() {
4594 return handle;
4595 }
4596
4597 if ignore_refcounts || *refcount == 1 {
4598 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4599 }
4600 if !ignore_refcounts {
4601 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4602 let refcount = {
4603 let local = lsp_store.as_local_mut().unwrap();
4604 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4605 debug_panic!("bad refcounting");
4606 return;
4607 };
4608
4609 *refcount -= 1;
4610 *refcount
4611 };
4612 if refcount == 0 {
4613 lsp_store.lsp_data.remove(&buffer_id);
4614 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4615 let local = lsp_store.as_local_mut().unwrap();
4616 local.registered_buffers.remove(&buffer_id);
4617
4618 local.buffers_opened_in_servers.remove(&buffer_id);
4619 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4620 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4621
4622 let buffer_abs_path = file.abs_path(cx);
4623 for (_, buffer_pull_diagnostics_result_ids) in
4624 &mut local.buffer_pull_diagnostics_result_ids
4625 {
4626 buffer_pull_diagnostics_result_ids.retain(
4627 |_, buffer_result_ids| {
4628 buffer_result_ids.remove(&buffer_abs_path);
4629 !buffer_result_ids.is_empty()
4630 },
4631 );
4632 }
4633
4634 let diagnostic_updates = local
4635 .language_servers
4636 .keys()
4637 .cloned()
4638 .map(|server_id| DocumentDiagnosticsUpdate {
4639 diagnostics: DocumentDiagnostics {
4640 document_abs_path: buffer_abs_path.clone(),
4641 version: None,
4642 diagnostics: Vec::new(),
4643 },
4644 result_id: None,
4645 registration_id: None,
4646 server_id,
4647 disk_based_sources: Cow::Borrowed(&[]),
4648 })
4649 .collect::<Vec<_>>();
4650
4651 lsp_store
4652 .merge_diagnostic_entries(
4653 diagnostic_updates,
4654 |_, diagnostic, _| {
4655 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4656 },
4657 cx,
4658 )
4659 .context("Clearing diagnostics for the closed buffer")
4660 .log_err();
4661 }
4662 }
4663 })
4664 .detach();
4665 }
4666 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4667 let buffer_id = buffer.read(cx).remote_id().to_proto();
4668 cx.background_spawn(async move {
4669 upstream_client
4670 .request(proto::RegisterBufferWithLanguageServers {
4671 project_id: upstream_project_id,
4672 buffer_id,
4673 only_servers: only_register_servers
4674 .into_iter()
4675 .map(|selector| {
4676 let selector = match selector {
4677 LanguageServerSelector::Id(language_server_id) => {
4678 proto::language_server_selector::Selector::ServerId(
4679 language_server_id.to_proto(),
4680 )
4681 }
4682 LanguageServerSelector::Name(language_server_name) => {
4683 proto::language_server_selector::Selector::Name(
4684 language_server_name.to_string(),
4685 )
4686 }
4687 };
4688 proto::LanguageServerSelector {
4689 selector: Some(selector),
4690 }
4691 })
4692 .collect(),
4693 })
4694 .await
4695 })
4696 .detach();
4697 } else {
4698 // Our remote connection got closed
4699 }
4700 handle
4701 }
4702
4703 fn maintain_buffer_languages(
4704 languages: Arc<LanguageRegistry>,
4705 cx: &mut Context<Self>,
4706 ) -> Task<()> {
4707 let mut subscription = languages.subscribe();
4708 let mut prev_reload_count = languages.reload_count();
4709 cx.spawn(async move |this, cx| {
4710 while let Some(()) = subscription.next().await {
4711 if let Some(this) = this.upgrade() {
4712 // If the language registry has been reloaded, then remove and
4713 // re-assign the languages on all open buffers.
4714 let reload_count = languages.reload_count();
4715 if reload_count > prev_reload_count {
4716 prev_reload_count = reload_count;
4717 this.update(cx, |this, cx| {
4718 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4719 for buffer in buffer_store.buffers() {
4720 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4721 {
4722 buffer.update(cx, |buffer, cx| {
4723 buffer.set_language_async(None, cx)
4724 });
4725 if let Some(local) = this.as_local_mut() {
4726 local.reset_buffer(&buffer, &f, cx);
4727
4728 if local
4729 .registered_buffers
4730 .contains_key(&buffer.read(cx).remote_id())
4731 && let Some(file_url) =
4732 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4733 {
4734 local.unregister_buffer_from_language_servers(
4735 &buffer, &file_url, cx,
4736 );
4737 }
4738 }
4739 }
4740 }
4741 });
4742 });
4743 }
4744
4745 this.update(cx, |this, cx| {
4746 let mut plain_text_buffers = Vec::new();
4747 let mut buffers_with_unknown_injections = Vec::new();
4748 for handle in this.buffer_store.read(cx).buffers() {
4749 let buffer = handle.read(cx);
4750 if buffer.language().is_none()
4751 || buffer.language() == Some(&*language::PLAIN_TEXT)
4752 {
4753 plain_text_buffers.push(handle);
4754 } else if buffer.contains_unknown_injections() {
4755 buffers_with_unknown_injections.push(handle);
4756 }
4757 }
4758
4759 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4760 // and reused later in the invisible worktrees.
4761 plain_text_buffers.sort_by_key(|buffer| {
4762 Reverse(
4763 File::from_dyn(buffer.read(cx).file())
4764 .map(|file| file.worktree.read(cx).is_visible()),
4765 )
4766 });
4767
4768 for buffer in plain_text_buffers {
4769 this.detect_language_for_buffer(&buffer, cx);
4770 if let Some(local) = this.as_local_mut() {
4771 local.initialize_buffer(&buffer, cx);
4772 if local
4773 .registered_buffers
4774 .contains_key(&buffer.read(cx).remote_id())
4775 {
4776 local.register_buffer_with_language_servers(
4777 &buffer,
4778 HashSet::default(),
4779 cx,
4780 );
4781 }
4782 }
4783 }
4784
4785 for buffer in buffers_with_unknown_injections {
4786 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4787 }
4788 });
4789 }
4790 }
4791 })
4792 }
4793
4794 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4795 let buffer = buffer_handle.read(cx);
4796 let content = buffer.as_rope();
4797
4798 let modeline_settings = {
4799 let settings_store = cx.global::<SettingsStore>();
4800 let modeline_lines = settings_store
4801 .raw_user_settings()
4802 .and_then(|s| s.content.modeline_lines)
4803 .or(settings_store.raw_default_settings().modeline_lines)
4804 .unwrap_or(5);
4805
4806 const MAX_MODELINE_BYTES: usize = 1024;
4807
4808 let first_bytes =
4809 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4810 let mut first_lines = Vec::new();
4811 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4812 for _ in 0..modeline_lines {
4813 if let Some(line) = lines.next() {
4814 first_lines.push(line.to_string());
4815 } else {
4816 break;
4817 }
4818 }
4819 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4820
4821 let last_start =
4822 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4823 let mut last_lines = Vec::new();
4824 let mut lines = content
4825 .reversed_chunks_in_range(last_start..content.len())
4826 .lines();
4827 for _ in 0..modeline_lines {
4828 if let Some(line) = lines.next() {
4829 last_lines.push(line.to_string());
4830 } else {
4831 break;
4832 }
4833 }
4834 let last_lines_ref: Vec<_> =
4835 last_lines.iter().rev().map(|line| line.as_str()).collect();
4836 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4837 };
4838
4839 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4840
4841 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4842 }
4843
4844 fn detect_language_for_buffer(
4845 &mut self,
4846 buffer_handle: &Entity<Buffer>,
4847 cx: &mut Context<Self>,
4848 ) -> Option<language::AvailableLanguage> {
4849 // If the buffer has a language, set it and start the language server if we haven't already.
4850 let buffer = buffer_handle.read(cx);
4851 let file = buffer.file()?;
4852 let content = buffer.as_rope();
4853 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4854
4855 let available_language = if let Some(ModelineSettings {
4856 mode: Some(mode_name),
4857 ..
4858 }) = modeline_settings
4859 {
4860 self.languages
4861 .available_language_for_modeline_name(mode_name)
4862 } else {
4863 self.languages.language_for_file(file, Some(content), cx)
4864 };
4865 if let Some(available_language) = &available_language {
4866 if let Some(Ok(Ok(new_language))) = self
4867 .languages
4868 .load_language(available_language)
4869 .now_or_never()
4870 {
4871 self.set_language_for_buffer(buffer_handle, new_language, cx);
4872 }
4873 } else {
4874 cx.emit(LspStoreEvent::LanguageDetected {
4875 buffer: buffer_handle.clone(),
4876 new_language: None,
4877 });
4878 }
4879
4880 available_language
4881 }
4882
4883 pub(crate) fn set_language_for_buffer(
4884 &mut self,
4885 buffer_entity: &Entity<Buffer>,
4886 new_language: Arc<Language>,
4887 cx: &mut Context<Self>,
4888 ) {
4889 let buffer = buffer_entity.read(cx);
4890 let buffer_file = buffer.file().cloned();
4891 let buffer_id = buffer.remote_id();
4892 if let Some(local_store) = self.as_local_mut()
4893 && local_store.registered_buffers.contains_key(&buffer_id)
4894 && let Some(abs_path) =
4895 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4896 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4897 {
4898 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4899 }
4900 buffer_entity.update(cx, |buffer, cx| {
4901 if buffer
4902 .language()
4903 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4904 {
4905 buffer.set_language_async(Some(new_language.clone()), cx);
4906 }
4907 });
4908
4909 let settings = LanguageSettings::resolve(
4910 Some(&buffer_entity.read(cx)),
4911 Some(&new_language.name()),
4912 cx,
4913 )
4914 .into_owned();
4915 let buffer_file = File::from_dyn(buffer_file.as_ref());
4916
4917 let worktree_id = if let Some(file) = buffer_file {
4918 let worktree = file.worktree.clone();
4919
4920 if let Some(local) = self.as_local_mut()
4921 && local.registered_buffers.contains_key(&buffer_id)
4922 {
4923 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4924 }
4925 Some(worktree.read(cx).id())
4926 } else {
4927 None
4928 };
4929
4930 if settings.prettier.allowed
4931 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4932 {
4933 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4934 if let Some(prettier_store) = prettier_store {
4935 prettier_store.update(cx, |prettier_store, cx| {
4936 prettier_store.install_default_prettier(
4937 worktree_id,
4938 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4939 cx,
4940 )
4941 })
4942 }
4943 }
4944
4945 cx.emit(LspStoreEvent::LanguageDetected {
4946 buffer: buffer_entity.clone(),
4947 new_language: Some(new_language),
4948 })
4949 }
4950
4951 pub fn buffer_store(&self) -> Entity<BufferStore> {
4952 self.buffer_store.clone()
4953 }
4954
4955 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4956 self.active_entry = active_entry;
4957 }
4958
4959 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4960 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4961 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4962 {
4963 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4964 summaries
4965 .iter()
4966 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4967 });
4968 if let Some(summary) = summaries.next() {
4969 client
4970 .send(proto::UpdateDiagnosticSummary {
4971 project_id: downstream_project_id,
4972 worktree_id: worktree.id().to_proto(),
4973 summary: Some(summary),
4974 more_summaries: summaries.collect(),
4975 })
4976 .log_err();
4977 }
4978 }
4979 }
4980
4981 fn is_capable_for_proto_request<R>(
4982 &self,
4983 buffer: &Entity<Buffer>,
4984 request: &R,
4985 cx: &App,
4986 ) -> bool
4987 where
4988 R: LspCommand,
4989 {
4990 self.check_if_capable_for_proto_request(
4991 buffer,
4992 |capabilities| {
4993 request.check_capabilities(AdapterServerCapabilities {
4994 server_capabilities: capabilities.clone(),
4995 code_action_kinds: None,
4996 })
4997 },
4998 cx,
4999 )
5000 }
5001
5002 fn check_if_capable_for_proto_request<F>(
5003 &self,
5004 buffer: &Entity<Buffer>,
5005 check: F,
5006 cx: &App,
5007 ) -> bool
5008 where
5009 F: FnMut(&lsp::ServerCapabilities) -> bool,
5010 {
5011 let Some(language) = buffer.read(cx).language().cloned() else {
5012 return false;
5013 };
5014 let registered_language_servers = self
5015 .languages
5016 .lsp_adapters(&language.name())
5017 .into_iter()
5018 .map(|lsp_adapter| lsp_adapter.name())
5019 .collect::<HashSet<_>>();
5020 self.language_server_statuses
5021 .iter()
5022 .filter_map(|(server_id, server_status)| {
5023 // Include servers that are either registered for this language OR
5024 // available to be loaded (for SSH remote mode where adapters like
5025 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5026 // but only loaded on the server side)
5027 let is_relevant = registered_language_servers.contains(&server_status.name)
5028 || self.languages.is_lsp_adapter_available(&server_status.name);
5029 is_relevant.then_some(server_id)
5030 })
5031 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
5032 .any(check)
5033 }
5034
5035 fn all_capable_for_proto_request<F>(
5036 &self,
5037 buffer: &Entity<Buffer>,
5038 mut check: F,
5039 cx: &App,
5040 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5041 where
5042 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5043 {
5044 let Some(language) = buffer.read(cx).language().cloned() else {
5045 return Vec::default();
5046 };
5047 let registered_language_servers = self
5048 .languages
5049 .lsp_adapters(&language.name())
5050 .into_iter()
5051 .map(|lsp_adapter| lsp_adapter.name())
5052 .collect::<HashSet<_>>();
5053 self.language_server_statuses
5054 .iter()
5055 .filter_map(|(server_id, server_status)| {
5056 // Include servers that are either registered for this language OR
5057 // available to be loaded (for SSH remote mode where adapters like
5058 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5059 // but only loaded on the server side)
5060 let is_relevant = registered_language_servers.contains(&server_status.name)
5061 || self.languages.is_lsp_adapter_available(&server_status.name);
5062 is_relevant.then_some((server_id, &server_status.name))
5063 })
5064 .filter_map(|(server_id, server_name)| {
5065 self.lsp_server_capabilities
5066 .get(server_id)
5067 .map(|c| (server_id, server_name, c))
5068 })
5069 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5070 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5071 .collect()
5072 }
5073
5074 pub fn request_lsp<R>(
5075 &mut self,
5076 buffer: Entity<Buffer>,
5077 server: LanguageServerToQuery,
5078 request: R,
5079 cx: &mut Context<Self>,
5080 ) -> Task<Result<R::Response>>
5081 where
5082 R: LspCommand,
5083 <R::LspRequest as lsp::request::Request>::Result: Send,
5084 <R::LspRequest as lsp::request::Request>::Params: Send,
5085 {
5086 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5087 return self.send_lsp_proto_request(
5088 buffer,
5089 upstream_client,
5090 upstream_project_id,
5091 request,
5092 cx,
5093 );
5094 }
5095
5096 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5097 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5098 local
5099 .language_servers_for_buffer(buffer, cx)
5100 .find(|(_, server)| {
5101 request.check_capabilities(server.adapter_server_capabilities())
5102 })
5103 .map(|(_, server)| server.clone())
5104 }),
5105 LanguageServerToQuery::Other(id) => self
5106 .language_server_for_local_buffer(buffer, id, cx)
5107 .and_then(|(_, server)| {
5108 request
5109 .check_capabilities(server.adapter_server_capabilities())
5110 .then(|| Arc::clone(server))
5111 }),
5112 }) else {
5113 return Task::ready(Ok(Default::default()));
5114 };
5115
5116 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5117
5118 let Some(file) = file else {
5119 return Task::ready(Ok(Default::default()));
5120 };
5121
5122 let lsp_params = match request.to_lsp_params_or_response(
5123 &file.abs_path(cx),
5124 buffer.read(cx),
5125 &language_server,
5126 cx,
5127 ) {
5128 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5129 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5130 Err(err) => {
5131 let message = format!(
5132 "{} via {} failed: {}",
5133 request.display_name(),
5134 language_server.name(),
5135 err
5136 );
5137 // rust-analyzer likes to error with this when its still loading up
5138 if !message.ends_with("content modified") {
5139 log::warn!("{message}");
5140 }
5141 return Task::ready(Err(anyhow!(message)));
5142 }
5143 };
5144
5145 let status = request.status();
5146 let request_timeout = ProjectSettings::get_global(cx)
5147 .global_lsp_settings
5148 .get_request_timeout();
5149
5150 cx.spawn(async move |this, cx| {
5151 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5152
5153 let id = lsp_request.id();
5154 let _cleanup = if status.is_some() {
5155 cx.update(|cx| {
5156 this.update(cx, |this, cx| {
5157 this.on_lsp_work_start(
5158 language_server.server_id(),
5159 ProgressToken::Number(id),
5160 LanguageServerProgress {
5161 is_disk_based_diagnostics_progress: false,
5162 is_cancellable: false,
5163 title: None,
5164 message: status.clone(),
5165 percentage: None,
5166 last_update_at: cx.background_executor().now(),
5167 },
5168 cx,
5169 );
5170 })
5171 })
5172 .log_err();
5173
5174 Some(defer(|| {
5175 cx.update(|cx| {
5176 this.update(cx, |this, cx| {
5177 this.on_lsp_work_end(
5178 language_server.server_id(),
5179 ProgressToken::Number(id),
5180 cx,
5181 );
5182 })
5183 })
5184 .log_err();
5185 }))
5186 } else {
5187 None
5188 };
5189
5190 let result = lsp_request.await.into_response();
5191
5192 let response = result.map_err(|err| {
5193 let message = format!(
5194 "{} via {} failed: {}",
5195 request.display_name(),
5196 language_server.name(),
5197 err
5198 );
5199 // rust-analyzer likes to error with this when its still loading up
5200 if !message.ends_with("content modified") {
5201 log::warn!("{message}");
5202 }
5203 anyhow::anyhow!(message)
5204 })?;
5205
5206 request
5207 .response_from_lsp(
5208 response,
5209 this.upgrade().context("no app context")?,
5210 buffer,
5211 language_server.server_id(),
5212 cx.clone(),
5213 )
5214 .await
5215 })
5216 }
5217
5218 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5219 let mut language_formatters_to_check = Vec::new();
5220 for buffer in self.buffer_store.read(cx).buffers() {
5221 let buffer = buffer.read(cx);
5222 let settings = LanguageSettings::for_buffer(buffer, cx);
5223 if buffer.language().is_some() {
5224 let buffer_file = File::from_dyn(buffer.file());
5225 language_formatters_to_check.push((
5226 buffer_file.map(|f| f.worktree_id(cx)),
5227 settings.into_owned(),
5228 ));
5229 }
5230 }
5231
5232 self.request_workspace_config_refresh();
5233
5234 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5235 prettier_store.update(cx, |prettier_store, cx| {
5236 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5237 })
5238 }
5239
5240 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5241 .global_lsp_settings
5242 .semantic_token_rules
5243 .clone();
5244 self.semantic_token_config
5245 .update_rules(new_semantic_token_rules);
5246 // Always clear cached stylizers so that changes to language-specific
5247 // semantic token rules (e.g. from extension install/uninstall) are
5248 // picked up. Stylizers are recreated lazily, so this is cheap.
5249 self.semantic_token_config.clear_stylizers();
5250
5251 let new_global_semantic_tokens_mode =
5252 all_language_settings(None, cx).defaults.semantic_tokens;
5253 if self
5254 .semantic_token_config
5255 .update_global_mode(new_global_semantic_tokens_mode)
5256 {
5257 self.restart_all_language_servers(cx);
5258 }
5259
5260 cx.notify();
5261 }
5262
5263 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5264 let buffer_store = self.buffer_store.clone();
5265 let Some(local) = self.as_local_mut() else {
5266 return;
5267 };
5268 let mut adapters = BTreeMap::default();
5269 let get_adapter = {
5270 let languages = local.languages.clone();
5271 let environment = local.environment.clone();
5272 let weak = local.weak.clone();
5273 let worktree_store = local.worktree_store.clone();
5274 let http_client = local.http_client.clone();
5275 let fs = local.fs.clone();
5276 move |worktree_id, cx: &mut App| {
5277 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5278 Some(LocalLspAdapterDelegate::new(
5279 languages.clone(),
5280 &environment,
5281 weak.clone(),
5282 &worktree,
5283 http_client.clone(),
5284 fs.clone(),
5285 cx,
5286 ))
5287 }
5288 };
5289
5290 let mut messages_to_report = Vec::new();
5291 let (new_tree, to_stop) = {
5292 let mut rebase = local.lsp_tree.rebase();
5293 let buffers = buffer_store
5294 .read(cx)
5295 .buffers()
5296 .filter_map(|buffer| {
5297 let raw_buffer = buffer.read(cx);
5298 if !local
5299 .registered_buffers
5300 .contains_key(&raw_buffer.remote_id())
5301 {
5302 return None;
5303 }
5304 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5305 let language = raw_buffer.language().cloned()?;
5306 Some((file, language, raw_buffer.remote_id()))
5307 })
5308 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5309 for (file, language, buffer_id) in buffers {
5310 let worktree_id = file.worktree_id(cx);
5311 let Some(worktree) = local
5312 .worktree_store
5313 .read(cx)
5314 .worktree_for_id(worktree_id, cx)
5315 else {
5316 continue;
5317 };
5318
5319 if let Some((_, apply)) = local.reuse_existing_language_server(
5320 rebase.server_tree(),
5321 &worktree,
5322 &language.name(),
5323 cx,
5324 ) {
5325 (apply)(rebase.server_tree());
5326 } else if let Some(lsp_delegate) = adapters
5327 .entry(worktree_id)
5328 .or_insert_with(|| get_adapter(worktree_id, cx))
5329 .clone()
5330 {
5331 let delegate =
5332 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5333 let path = file
5334 .path()
5335 .parent()
5336 .map(Arc::from)
5337 .unwrap_or_else(|| file.path().clone());
5338 let worktree_path = ProjectPath { worktree_id, path };
5339 let abs_path = file.abs_path(cx);
5340 let nodes = rebase
5341 .walk(
5342 worktree_path,
5343 language.name(),
5344 language.manifest(),
5345 delegate.clone(),
5346 cx,
5347 )
5348 .collect::<Vec<_>>();
5349 for node in nodes {
5350 let server_id = node.server_id_or_init(|disposition| {
5351 let path = &disposition.path;
5352 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5353 let key = LanguageServerSeed {
5354 worktree_id,
5355 name: disposition.server_name.clone(),
5356 settings: LanguageServerSeedSettings {
5357 binary: disposition.settings.binary.clone(),
5358 initialization_options: disposition
5359 .settings
5360 .initialization_options
5361 .clone(),
5362 },
5363 toolchain: local.toolchain_store.read(cx).active_toolchain(
5364 path.worktree_id,
5365 &path.path,
5366 language.name(),
5367 ),
5368 };
5369 local.language_server_ids.remove(&key);
5370
5371 let server_id = local.get_or_insert_language_server(
5372 &worktree,
5373 lsp_delegate.clone(),
5374 disposition,
5375 &language.name(),
5376 cx,
5377 );
5378 if let Some(state) = local.language_servers.get(&server_id)
5379 && let Ok(uri) = uri
5380 {
5381 state.add_workspace_folder(uri);
5382 };
5383 server_id
5384 });
5385
5386 if let Some(language_server_id) = server_id {
5387 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5388 language_server_id,
5389 name: node.name(),
5390 message:
5391 proto::update_language_server::Variant::RegisteredForBuffer(
5392 proto::RegisteredForBuffer {
5393 buffer_abs_path: abs_path
5394 .to_string_lossy()
5395 .into_owned(),
5396 buffer_id: buffer_id.to_proto(),
5397 },
5398 ),
5399 });
5400 }
5401 }
5402 } else {
5403 continue;
5404 }
5405 }
5406 rebase.finish()
5407 };
5408 for message in messages_to_report {
5409 cx.emit(message);
5410 }
5411 local.lsp_tree = new_tree;
5412 for (id, _) in to_stop {
5413 self.stop_local_language_server(id, cx).detach();
5414 }
5415 }
5416
5417 pub fn apply_code_action(
5418 &self,
5419 buffer_handle: Entity<Buffer>,
5420 mut action: CodeAction,
5421 push_to_history: bool,
5422 cx: &mut Context<Self>,
5423 ) -> Task<Result<ProjectTransaction>> {
5424 if let Some((upstream_client, project_id)) = self.upstream_client() {
5425 let request = proto::ApplyCodeAction {
5426 project_id,
5427 buffer_id: buffer_handle.read(cx).remote_id().into(),
5428 action: Some(Self::serialize_code_action(&action)),
5429 };
5430 let buffer_store = self.buffer_store();
5431 cx.spawn(async move |_, cx| {
5432 let response = upstream_client
5433 .request(request)
5434 .await?
5435 .transaction
5436 .context("missing transaction")?;
5437
5438 buffer_store
5439 .update(cx, |buffer_store, cx| {
5440 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5441 })
5442 .await
5443 })
5444 } else if self.mode.is_local() {
5445 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5446 let request_timeout = ProjectSettings::get_global(cx)
5447 .global_lsp_settings
5448 .get_request_timeout();
5449 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5450 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5451 }) else {
5452 return Task::ready(Ok(ProjectTransaction::default()));
5453 };
5454
5455 cx.spawn(async move |this, cx| {
5456 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5457 .await
5458 .context("resolving a code action")?;
5459 if let Some(edit) = action.lsp_action.edit()
5460 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5461 return LocalLspStore::deserialize_workspace_edit(
5462 this.upgrade().context("no app present")?,
5463 edit.clone(),
5464 push_to_history,
5465
5466 lang_server.clone(),
5467 cx,
5468 )
5469 .await;
5470 }
5471
5472 let Some(command) = action.lsp_action.command() else {
5473 return Ok(ProjectTransaction::default())
5474 };
5475
5476 let server_capabilities = lang_server.capabilities();
5477 let available_commands = server_capabilities
5478 .execute_command_provider
5479 .as_ref()
5480 .map(|options| options.commands.as_slice())
5481 .unwrap_or_default();
5482
5483 if !available_commands.contains(&command.command) {
5484 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5485 return Ok(ProjectTransaction::default())
5486 }
5487
5488 let request_timeout = cx.update(|app|
5489 ProjectSettings::get_global(app)
5490 .global_lsp_settings
5491 .get_request_timeout()
5492 );
5493
5494 this.update(cx, |this, _| {
5495 this.as_local_mut()
5496 .unwrap()
5497 .last_workspace_edits_by_language_server
5498 .remove(&lang_server.server_id());
5499 })?;
5500
5501 let _result = lang_server
5502 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5503 command: command.command.clone(),
5504 arguments: command.arguments.clone().unwrap_or_default(),
5505 ..lsp::ExecuteCommandParams::default()
5506 }, request_timeout)
5507 .await.into_response()
5508 .context("execute command")?;
5509
5510 return this.update(cx, |this, _| {
5511 this.as_local_mut()
5512 .unwrap()
5513 .last_workspace_edits_by_language_server
5514 .remove(&lang_server.server_id())
5515 .unwrap_or_default()
5516 });
5517 })
5518 } else {
5519 Task::ready(Err(anyhow!("no upstream client and not local")))
5520 }
5521 }
5522
5523 pub fn apply_code_action_kind(
5524 &mut self,
5525 buffers: HashSet<Entity<Buffer>>,
5526 kind: CodeActionKind,
5527 push_to_history: bool,
5528 cx: &mut Context<Self>,
5529 ) -> Task<anyhow::Result<ProjectTransaction>> {
5530 if self.as_local().is_some() {
5531 cx.spawn(async move |lsp_store, cx| {
5532 let buffers = buffers.into_iter().collect::<Vec<_>>();
5533 let result = LocalLspStore::execute_code_action_kind_locally(
5534 lsp_store.clone(),
5535 buffers,
5536 kind,
5537 push_to_history,
5538 cx,
5539 )
5540 .await;
5541 lsp_store.update(cx, |lsp_store, _| {
5542 lsp_store.update_last_formatting_failure(&result);
5543 })?;
5544 result
5545 })
5546 } else if let Some((client, project_id)) = self.upstream_client() {
5547 let buffer_store = self.buffer_store();
5548 cx.spawn(async move |lsp_store, cx| {
5549 let result = client
5550 .request(proto::ApplyCodeActionKind {
5551 project_id,
5552 kind: kind.as_str().to_owned(),
5553 buffer_ids: buffers
5554 .iter()
5555 .map(|buffer| {
5556 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5557 })
5558 .collect(),
5559 })
5560 .await
5561 .and_then(|result| result.transaction.context("missing transaction"));
5562 lsp_store.update(cx, |lsp_store, _| {
5563 lsp_store.update_last_formatting_failure(&result);
5564 })?;
5565
5566 let transaction_response = result?;
5567 buffer_store
5568 .update(cx, |buffer_store, cx| {
5569 buffer_store.deserialize_project_transaction(
5570 transaction_response,
5571 push_to_history,
5572 cx,
5573 )
5574 })
5575 .await
5576 })
5577 } else {
5578 Task::ready(Ok(ProjectTransaction::default()))
5579 }
5580 }
5581
5582 pub fn resolved_hint(
5583 &mut self,
5584 buffer_id: BufferId,
5585 id: InlayId,
5586 cx: &mut Context<Self>,
5587 ) -> Option<ResolvedHint> {
5588 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5589
5590 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5591 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5592 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5593 let (server_id, resolve_data) = match &hint.resolve_state {
5594 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5595 ResolveState::Resolving => {
5596 return Some(ResolvedHint::Resolving(
5597 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5598 ));
5599 }
5600 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5601 };
5602
5603 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5604 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5605 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5606 id,
5607 cx.spawn(async move |lsp_store, cx| {
5608 let resolved_hint = resolve_task.await;
5609 lsp_store
5610 .update(cx, |lsp_store, _| {
5611 if let Some(old_inlay_hint) = lsp_store
5612 .lsp_data
5613 .get_mut(&buffer_id)
5614 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5615 {
5616 match resolved_hint {
5617 Ok(resolved_hint) => {
5618 *old_inlay_hint = resolved_hint;
5619 }
5620 Err(e) => {
5621 old_inlay_hint.resolve_state =
5622 ResolveState::CanResolve(server_id, resolve_data);
5623 log::error!("Inlay hint resolve failed: {e:#}");
5624 }
5625 }
5626 }
5627 })
5628 .ok();
5629 })
5630 .shared(),
5631 );
5632 debug_assert!(
5633 previous_task.is_none(),
5634 "Did not change hint's resolve state after spawning its resolve"
5635 );
5636 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5637 None
5638 }
5639
5640 pub(crate) fn linked_edits(
5641 &mut self,
5642 buffer: &Entity<Buffer>,
5643 position: Anchor,
5644 cx: &mut Context<Self>,
5645 ) -> Task<Result<Vec<Range<Anchor>>>> {
5646 let snapshot = buffer.read(cx).snapshot();
5647 let scope = snapshot.language_scope_at(position);
5648 let Some(server_id) = self
5649 .as_local()
5650 .and_then(|local| {
5651 buffer.update(cx, |buffer, cx| {
5652 local
5653 .language_servers_for_buffer(buffer, cx)
5654 .filter(|(_, server)| {
5655 LinkedEditingRange::check_server_capabilities(server.capabilities())
5656 })
5657 .filter(|(adapter, _)| {
5658 scope
5659 .as_ref()
5660 .map(|scope| scope.language_allowed(&adapter.name))
5661 .unwrap_or(true)
5662 })
5663 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5664 .next()
5665 })
5666 })
5667 .or_else(|| {
5668 self.upstream_client()
5669 .is_some()
5670 .then_some(LanguageServerToQuery::FirstCapable)
5671 })
5672 .filter(|_| {
5673 maybe!({
5674 buffer.read(cx).language_at(position)?;
5675 Some(
5676 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5677 .linked_edits,
5678 )
5679 }) == Some(true)
5680 })
5681 else {
5682 return Task::ready(Ok(Vec::new()));
5683 };
5684
5685 self.request_lsp(
5686 buffer.clone(),
5687 server_id,
5688 LinkedEditingRange { position },
5689 cx,
5690 )
5691 }
5692
5693 fn apply_on_type_formatting(
5694 &mut self,
5695 buffer: Entity<Buffer>,
5696 position: Anchor,
5697 trigger: String,
5698 cx: &mut Context<Self>,
5699 ) -> Task<Result<Option<Transaction>>> {
5700 if let Some((client, project_id)) = self.upstream_client() {
5701 if !self.check_if_capable_for_proto_request(
5702 &buffer,
5703 |capabilities| {
5704 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5705 },
5706 cx,
5707 ) {
5708 return Task::ready(Ok(None));
5709 }
5710 let request = proto::OnTypeFormatting {
5711 project_id,
5712 buffer_id: buffer.read(cx).remote_id().into(),
5713 position: Some(serialize_anchor(&position)),
5714 trigger,
5715 version: serialize_version(&buffer.read(cx).version()),
5716 };
5717 cx.background_spawn(async move {
5718 client
5719 .request(request)
5720 .await?
5721 .transaction
5722 .map(language::proto::deserialize_transaction)
5723 .transpose()
5724 })
5725 } else if let Some(local) = self.as_local_mut() {
5726 let buffer_id = buffer.read(cx).remote_id();
5727 local.buffers_being_formatted.insert(buffer_id);
5728 cx.spawn(async move |this, cx| {
5729 let _cleanup = defer({
5730 let this = this.clone();
5731 let mut cx = cx.clone();
5732 move || {
5733 this.update(&mut cx, |this, _| {
5734 if let Some(local) = this.as_local_mut() {
5735 local.buffers_being_formatted.remove(&buffer_id);
5736 }
5737 })
5738 .ok();
5739 }
5740 });
5741
5742 buffer
5743 .update(cx, |buffer, _| {
5744 buffer.wait_for_edits(Some(position.timestamp()))
5745 })
5746 .await?;
5747 this.update(cx, |this, cx| {
5748 let position = position.to_point_utf16(buffer.read(cx));
5749 this.on_type_format(buffer, position, trigger, false, cx)
5750 })?
5751 .await
5752 })
5753 } else {
5754 Task::ready(Err(anyhow!("No upstream client or local language server")))
5755 }
5756 }
5757
5758 pub fn on_type_format<T: ToPointUtf16>(
5759 &mut self,
5760 buffer: Entity<Buffer>,
5761 position: T,
5762 trigger: String,
5763 push_to_history: bool,
5764 cx: &mut Context<Self>,
5765 ) -> Task<Result<Option<Transaction>>> {
5766 let position = position.to_point_utf16(buffer.read(cx));
5767 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5768 }
5769
5770 fn on_type_format_impl(
5771 &mut self,
5772 buffer: Entity<Buffer>,
5773 position: PointUtf16,
5774 trigger: String,
5775 push_to_history: bool,
5776 cx: &mut Context<Self>,
5777 ) -> Task<Result<Option<Transaction>>> {
5778 let options = buffer.update(cx, |buffer, cx| {
5779 lsp_command::lsp_formatting_options(
5780 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5781 )
5782 });
5783
5784 cx.spawn(async move |this, cx| {
5785 if let Some(waiter) =
5786 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5787 {
5788 waiter.await?;
5789 }
5790 cx.update(|cx| {
5791 this.update(cx, |this, cx| {
5792 this.request_lsp(
5793 buffer.clone(),
5794 LanguageServerToQuery::FirstCapable,
5795 OnTypeFormatting {
5796 position,
5797 trigger,
5798 options,
5799 push_to_history,
5800 },
5801 cx,
5802 )
5803 })
5804 })?
5805 .await
5806 })
5807 }
5808
5809 pub fn definitions(
5810 &mut self,
5811 buffer: &Entity<Buffer>,
5812 position: PointUtf16,
5813 cx: &mut Context<Self>,
5814 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5815 if let Some((upstream_client, project_id)) = self.upstream_client() {
5816 let request = GetDefinitions { position };
5817 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5818 return Task::ready(Ok(None));
5819 }
5820
5821 let request_timeout = ProjectSettings::get_global(cx)
5822 .global_lsp_settings
5823 .get_request_timeout();
5824
5825 let request_task = upstream_client.request_lsp(
5826 project_id,
5827 None,
5828 request_timeout,
5829 cx.background_executor().clone(),
5830 request.to_proto(project_id, buffer.read(cx)),
5831 );
5832 let buffer = buffer.clone();
5833 cx.spawn(async move |weak_lsp_store, cx| {
5834 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5835 return Ok(None);
5836 };
5837 let Some(responses) = request_task.await? else {
5838 return Ok(None);
5839 };
5840 let actions = join_all(responses.payload.into_iter().map(|response| {
5841 GetDefinitions { position }.response_from_proto(
5842 response.response,
5843 lsp_store.clone(),
5844 buffer.clone(),
5845 cx.clone(),
5846 )
5847 }))
5848 .await;
5849
5850 Ok(Some(
5851 actions
5852 .into_iter()
5853 .collect::<Result<Vec<Vec<_>>>>()?
5854 .into_iter()
5855 .flatten()
5856 .dedup()
5857 .collect(),
5858 ))
5859 })
5860 } else {
5861 let definitions_task = self.request_multiple_lsp_locally(
5862 buffer,
5863 Some(position),
5864 GetDefinitions { position },
5865 cx,
5866 );
5867 cx.background_spawn(async move {
5868 Ok(Some(
5869 definitions_task
5870 .await
5871 .into_iter()
5872 .flat_map(|(_, definitions)| definitions)
5873 .dedup()
5874 .collect(),
5875 ))
5876 })
5877 }
5878 }
5879
5880 pub fn declarations(
5881 &mut self,
5882 buffer: &Entity<Buffer>,
5883 position: PointUtf16,
5884 cx: &mut Context<Self>,
5885 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5886 if let Some((upstream_client, project_id)) = self.upstream_client() {
5887 let request = GetDeclarations { position };
5888 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5889 return Task::ready(Ok(None));
5890 }
5891 let request_timeout = ProjectSettings::get_global(cx)
5892 .global_lsp_settings
5893 .get_request_timeout();
5894 let request_task = upstream_client.request_lsp(
5895 project_id,
5896 None,
5897 request_timeout,
5898 cx.background_executor().clone(),
5899 request.to_proto(project_id, buffer.read(cx)),
5900 );
5901 let buffer = buffer.clone();
5902 cx.spawn(async move |weak_lsp_store, cx| {
5903 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5904 return Ok(None);
5905 };
5906 let Some(responses) = request_task.await? else {
5907 return Ok(None);
5908 };
5909 let actions = join_all(responses.payload.into_iter().map(|response| {
5910 GetDeclarations { position }.response_from_proto(
5911 response.response,
5912 lsp_store.clone(),
5913 buffer.clone(),
5914 cx.clone(),
5915 )
5916 }))
5917 .await;
5918
5919 Ok(Some(
5920 actions
5921 .into_iter()
5922 .collect::<Result<Vec<Vec<_>>>>()?
5923 .into_iter()
5924 .flatten()
5925 .dedup()
5926 .collect(),
5927 ))
5928 })
5929 } else {
5930 let declarations_task = self.request_multiple_lsp_locally(
5931 buffer,
5932 Some(position),
5933 GetDeclarations { position },
5934 cx,
5935 );
5936 cx.background_spawn(async move {
5937 Ok(Some(
5938 declarations_task
5939 .await
5940 .into_iter()
5941 .flat_map(|(_, declarations)| declarations)
5942 .dedup()
5943 .collect(),
5944 ))
5945 })
5946 }
5947 }
5948
5949 pub fn type_definitions(
5950 &mut self,
5951 buffer: &Entity<Buffer>,
5952 position: PointUtf16,
5953 cx: &mut Context<Self>,
5954 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5955 if let Some((upstream_client, project_id)) = self.upstream_client() {
5956 let request = GetTypeDefinitions { position };
5957 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5958 return Task::ready(Ok(None));
5959 }
5960 let request_timeout = ProjectSettings::get_global(cx)
5961 .global_lsp_settings
5962 .get_request_timeout();
5963 let request_task = upstream_client.request_lsp(
5964 project_id,
5965 None,
5966 request_timeout,
5967 cx.background_executor().clone(),
5968 request.to_proto(project_id, buffer.read(cx)),
5969 );
5970 let buffer = buffer.clone();
5971 cx.spawn(async move |weak_lsp_store, cx| {
5972 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5973 return Ok(None);
5974 };
5975 let Some(responses) = request_task.await? else {
5976 return Ok(None);
5977 };
5978 let actions = join_all(responses.payload.into_iter().map(|response| {
5979 GetTypeDefinitions { position }.response_from_proto(
5980 response.response,
5981 lsp_store.clone(),
5982 buffer.clone(),
5983 cx.clone(),
5984 )
5985 }))
5986 .await;
5987
5988 Ok(Some(
5989 actions
5990 .into_iter()
5991 .collect::<Result<Vec<Vec<_>>>>()?
5992 .into_iter()
5993 .flatten()
5994 .dedup()
5995 .collect(),
5996 ))
5997 })
5998 } else {
5999 let type_definitions_task = self.request_multiple_lsp_locally(
6000 buffer,
6001 Some(position),
6002 GetTypeDefinitions { position },
6003 cx,
6004 );
6005 cx.background_spawn(async move {
6006 Ok(Some(
6007 type_definitions_task
6008 .await
6009 .into_iter()
6010 .flat_map(|(_, type_definitions)| type_definitions)
6011 .dedup()
6012 .collect(),
6013 ))
6014 })
6015 }
6016 }
6017
6018 pub fn implementations(
6019 &mut self,
6020 buffer: &Entity<Buffer>,
6021 position: PointUtf16,
6022 cx: &mut Context<Self>,
6023 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6024 if let Some((upstream_client, project_id)) = self.upstream_client() {
6025 let request = GetImplementations { position };
6026 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6027 return Task::ready(Ok(None));
6028 }
6029
6030 let request_timeout = ProjectSettings::get_global(cx)
6031 .global_lsp_settings
6032 .get_request_timeout();
6033 let request_task = upstream_client.request_lsp(
6034 project_id,
6035 None,
6036 request_timeout,
6037 cx.background_executor().clone(),
6038 request.to_proto(project_id, buffer.read(cx)),
6039 );
6040 let buffer = buffer.clone();
6041 cx.spawn(async move |weak_lsp_store, cx| {
6042 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6043 return Ok(None);
6044 };
6045 let Some(responses) = request_task.await? else {
6046 return Ok(None);
6047 };
6048 let actions = join_all(responses.payload.into_iter().map(|response| {
6049 GetImplementations { position }.response_from_proto(
6050 response.response,
6051 lsp_store.clone(),
6052 buffer.clone(),
6053 cx.clone(),
6054 )
6055 }))
6056 .await;
6057
6058 Ok(Some(
6059 actions
6060 .into_iter()
6061 .collect::<Result<Vec<Vec<_>>>>()?
6062 .into_iter()
6063 .flatten()
6064 .dedup()
6065 .collect(),
6066 ))
6067 })
6068 } else {
6069 let implementations_task = self.request_multiple_lsp_locally(
6070 buffer,
6071 Some(position),
6072 GetImplementations { position },
6073 cx,
6074 );
6075 cx.background_spawn(async move {
6076 Ok(Some(
6077 implementations_task
6078 .await
6079 .into_iter()
6080 .flat_map(|(_, implementations)| implementations)
6081 .dedup()
6082 .collect(),
6083 ))
6084 })
6085 }
6086 }
6087
6088 pub fn references(
6089 &mut self,
6090 buffer: &Entity<Buffer>,
6091 position: PointUtf16,
6092 cx: &mut Context<Self>,
6093 ) -> Task<Result<Option<Vec<Location>>>> {
6094 if let Some((upstream_client, project_id)) = self.upstream_client() {
6095 let request = GetReferences { position };
6096 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6097 return Task::ready(Ok(None));
6098 }
6099
6100 let request_timeout = ProjectSettings::get_global(cx)
6101 .global_lsp_settings
6102 .get_request_timeout();
6103 let request_task = upstream_client.request_lsp(
6104 project_id,
6105 None,
6106 request_timeout,
6107 cx.background_executor().clone(),
6108 request.to_proto(project_id, buffer.read(cx)),
6109 );
6110 let buffer = buffer.clone();
6111 cx.spawn(async move |weak_lsp_store, cx| {
6112 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6113 return Ok(None);
6114 };
6115 let Some(responses) = request_task.await? else {
6116 return Ok(None);
6117 };
6118
6119 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6120 GetReferences { position }.response_from_proto(
6121 lsp_response.response,
6122 lsp_store.clone(),
6123 buffer.clone(),
6124 cx.clone(),
6125 )
6126 }))
6127 .await
6128 .into_iter()
6129 .collect::<Result<Vec<Vec<_>>>>()?
6130 .into_iter()
6131 .flatten()
6132 .dedup()
6133 .collect();
6134 Ok(Some(locations))
6135 })
6136 } else {
6137 let references_task = self.request_multiple_lsp_locally(
6138 buffer,
6139 Some(position),
6140 GetReferences { position },
6141 cx,
6142 );
6143 cx.background_spawn(async move {
6144 Ok(Some(
6145 references_task
6146 .await
6147 .into_iter()
6148 .flat_map(|(_, references)| references)
6149 .dedup()
6150 .collect(),
6151 ))
6152 })
6153 }
6154 }
6155
6156 pub fn code_actions(
6157 &mut self,
6158 buffer: &Entity<Buffer>,
6159 range: Range<Anchor>,
6160 kinds: Option<Vec<CodeActionKind>>,
6161 cx: &mut Context<Self>,
6162 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6163 if let Some((upstream_client, project_id)) = self.upstream_client() {
6164 let request = GetCodeActions {
6165 range: range.clone(),
6166 kinds: kinds.clone(),
6167 };
6168 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6169 return Task::ready(Ok(None));
6170 }
6171 let request_timeout = ProjectSettings::get_global(cx)
6172 .global_lsp_settings
6173 .get_request_timeout();
6174 let request_task = upstream_client.request_lsp(
6175 project_id,
6176 None,
6177 request_timeout,
6178 cx.background_executor().clone(),
6179 request.to_proto(project_id, buffer.read(cx)),
6180 );
6181 let buffer = buffer.clone();
6182 cx.spawn(async move |weak_lsp_store, cx| {
6183 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6184 return Ok(None);
6185 };
6186 let Some(responses) = request_task.await? else {
6187 return Ok(None);
6188 };
6189 let actions = join_all(responses.payload.into_iter().map(|response| {
6190 GetCodeActions {
6191 range: range.clone(),
6192 kinds: kinds.clone(),
6193 }
6194 .response_from_proto(
6195 response.response,
6196 lsp_store.clone(),
6197 buffer.clone(),
6198 cx.clone(),
6199 )
6200 }))
6201 .await;
6202
6203 Ok(Some(
6204 actions
6205 .into_iter()
6206 .collect::<Result<Vec<Vec<_>>>>()?
6207 .into_iter()
6208 .flatten()
6209 .collect(),
6210 ))
6211 })
6212 } else {
6213 let all_actions_task = self.request_multiple_lsp_locally(
6214 buffer,
6215 Some(range.start),
6216 GetCodeActions { range, kinds },
6217 cx,
6218 );
6219 cx.background_spawn(async move {
6220 Ok(Some(
6221 all_actions_task
6222 .await
6223 .into_iter()
6224 .flat_map(|(_, actions)| actions)
6225 .collect(),
6226 ))
6227 })
6228 }
6229 }
6230
6231 #[inline(never)]
6232 pub fn completions(
6233 &self,
6234 buffer: &Entity<Buffer>,
6235 position: PointUtf16,
6236 context: CompletionContext,
6237 cx: &mut Context<Self>,
6238 ) -> Task<Result<Vec<CompletionResponse>>> {
6239 let language_registry = self.languages.clone();
6240
6241 if let Some((upstream_client, project_id)) = self.upstream_client() {
6242 let snapshot = buffer.read(cx).snapshot();
6243 let offset = position.to_offset(&snapshot);
6244 let scope = snapshot.language_scope_at(offset);
6245 let capable_lsps = self.all_capable_for_proto_request(
6246 buffer,
6247 |server_name, capabilities| {
6248 capabilities.completion_provider.is_some()
6249 && scope
6250 .as_ref()
6251 .map(|scope| scope.language_allowed(server_name))
6252 .unwrap_or(true)
6253 },
6254 cx,
6255 );
6256 if capable_lsps.is_empty() {
6257 return Task::ready(Ok(Vec::new()));
6258 }
6259
6260 let language = buffer.read(cx).language().cloned();
6261
6262 let buffer = buffer.clone();
6263
6264 cx.spawn(async move |this, cx| {
6265 let requests = join_all(
6266 capable_lsps
6267 .into_iter()
6268 .map(|(id, server_name)| {
6269 let request = GetCompletions {
6270 position,
6271 context: context.clone(),
6272 server_id: Some(id),
6273 };
6274 let buffer = buffer.clone();
6275 let language = language.clone();
6276 let lsp_adapter = language.as_ref().and_then(|language| {
6277 let adapters = language_registry.lsp_adapters(&language.name());
6278 adapters
6279 .iter()
6280 .find(|adapter| adapter.name() == server_name)
6281 .or_else(|| adapters.first())
6282 .cloned()
6283 });
6284 let upstream_client = upstream_client.clone();
6285 let response = this
6286 .update(cx, |this, cx| {
6287 this.send_lsp_proto_request(
6288 buffer,
6289 upstream_client,
6290 project_id,
6291 request,
6292 cx,
6293 )
6294 })
6295 .log_err();
6296 async move {
6297 let response = response?.await.log_err()?;
6298
6299 let completions = populate_labels_for_completions(
6300 response.completions,
6301 language,
6302 lsp_adapter,
6303 )
6304 .await;
6305
6306 Some(CompletionResponse {
6307 completions,
6308 display_options: CompletionDisplayOptions::default(),
6309 is_incomplete: response.is_incomplete,
6310 })
6311 }
6312 })
6313 .collect::<Vec<_>>(),
6314 );
6315 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6316 })
6317 } else if let Some(local) = self.as_local() {
6318 let snapshot = buffer.read(cx).snapshot();
6319 let offset = position.to_offset(&snapshot);
6320 let scope = snapshot.language_scope_at(offset);
6321 let language = snapshot.language().cloned();
6322 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6323 .completions
6324 .clone();
6325 if !completion_settings.lsp {
6326 return Task::ready(Ok(Vec::new()));
6327 }
6328
6329 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6330 local
6331 .language_servers_for_buffer(buffer, cx)
6332 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6333 .filter(|(adapter, _)| {
6334 scope
6335 .as_ref()
6336 .map(|scope| scope.language_allowed(&adapter.name))
6337 .unwrap_or(true)
6338 })
6339 .map(|(_, server)| server.server_id())
6340 .collect()
6341 });
6342
6343 let buffer = buffer.clone();
6344 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6345 let lsp_timeout = if lsp_timeout > 0 {
6346 Some(Duration::from_millis(lsp_timeout))
6347 } else {
6348 None
6349 };
6350 cx.spawn(async move |this, cx| {
6351 let mut tasks = Vec::with_capacity(server_ids.len());
6352 this.update(cx, |lsp_store, cx| {
6353 for server_id in server_ids {
6354 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6355 let lsp_timeout = lsp_timeout
6356 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6357 let mut timeout = cx.background_spawn(async move {
6358 match lsp_timeout {
6359 Some(lsp_timeout) => {
6360 lsp_timeout.await;
6361 true
6362 },
6363 None => false,
6364 }
6365 }).fuse();
6366 let mut lsp_request = lsp_store.request_lsp(
6367 buffer.clone(),
6368 LanguageServerToQuery::Other(server_id),
6369 GetCompletions {
6370 position,
6371 context: context.clone(),
6372 server_id: Some(server_id),
6373 },
6374 cx,
6375 ).fuse();
6376 let new_task = cx.background_spawn(async move {
6377 select_biased! {
6378 response = lsp_request => anyhow::Ok(Some(response?)),
6379 timeout_happened = timeout => {
6380 if timeout_happened {
6381 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6382 Ok(None)
6383 } else {
6384 let completions = lsp_request.await?;
6385 Ok(Some(completions))
6386 }
6387 },
6388 }
6389 });
6390 tasks.push((lsp_adapter, new_task));
6391 }
6392 })?;
6393
6394 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6395 let completion_response = task.await.ok()??;
6396 let completions = populate_labels_for_completions(
6397 completion_response.completions,
6398 language.clone(),
6399 lsp_adapter,
6400 )
6401 .await;
6402 Some(CompletionResponse {
6403 completions,
6404 display_options: CompletionDisplayOptions::default(),
6405 is_incomplete: completion_response.is_incomplete,
6406 })
6407 });
6408
6409 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6410
6411 Ok(responses.into_iter().flatten().collect())
6412 })
6413 } else {
6414 Task::ready(Err(anyhow!("No upstream client or local language server")))
6415 }
6416 }
6417
6418 pub fn resolve_completions(
6419 &self,
6420 buffer: Entity<Buffer>,
6421 completion_indices: Vec<usize>,
6422 completions: Rc<RefCell<Box<[Completion]>>>,
6423 cx: &mut Context<Self>,
6424 ) -> Task<Result<bool>> {
6425 let client = self.upstream_client();
6426 let buffer_id = buffer.read(cx).remote_id();
6427 let buffer_snapshot = buffer.read(cx).snapshot();
6428
6429 if !self.check_if_capable_for_proto_request(
6430 &buffer,
6431 GetCompletions::can_resolve_completions,
6432 cx,
6433 ) {
6434 return Task::ready(Ok(false));
6435 }
6436 cx.spawn(async move |lsp_store, cx| {
6437 let request_timeout = cx.update(|app| {
6438 ProjectSettings::get_global(app)
6439 .global_lsp_settings
6440 .get_request_timeout()
6441 });
6442
6443 let mut did_resolve = false;
6444 if let Some((client, project_id)) = client {
6445 for completion_index in completion_indices {
6446 let server_id = {
6447 let completion = &completions.borrow()[completion_index];
6448 completion.source.server_id()
6449 };
6450 if let Some(server_id) = server_id {
6451 if Self::resolve_completion_remote(
6452 project_id,
6453 server_id,
6454 buffer_id,
6455 completions.clone(),
6456 completion_index,
6457 client.clone(),
6458 )
6459 .await
6460 .log_err()
6461 .is_some()
6462 {
6463 did_resolve = true;
6464 }
6465 } else {
6466 resolve_word_completion(
6467 &buffer_snapshot,
6468 &mut completions.borrow_mut()[completion_index],
6469 );
6470 }
6471 }
6472 } else {
6473 for completion_index in completion_indices {
6474 let server_id = {
6475 let completion = &completions.borrow()[completion_index];
6476 completion.source.server_id()
6477 };
6478 if let Some(server_id) = server_id {
6479 let server_and_adapter = lsp_store
6480 .read_with(cx, |lsp_store, _| {
6481 let server = lsp_store.language_server_for_id(server_id)?;
6482 let adapter =
6483 lsp_store.language_server_adapter_for_id(server.server_id())?;
6484 Some((server, adapter))
6485 })
6486 .ok()
6487 .flatten();
6488 let Some((server, adapter)) = server_and_adapter else {
6489 continue;
6490 };
6491
6492 let resolved = Self::resolve_completion_local(
6493 server,
6494 completions.clone(),
6495 completion_index,
6496 request_timeout,
6497 )
6498 .await
6499 .log_err()
6500 .is_some();
6501 if resolved {
6502 Self::regenerate_completion_labels(
6503 adapter,
6504 &buffer_snapshot,
6505 completions.clone(),
6506 completion_index,
6507 )
6508 .await
6509 .log_err();
6510 did_resolve = true;
6511 }
6512 } else {
6513 resolve_word_completion(
6514 &buffer_snapshot,
6515 &mut completions.borrow_mut()[completion_index],
6516 );
6517 }
6518 }
6519 }
6520
6521 Ok(did_resolve)
6522 })
6523 }
6524
6525 async fn resolve_completion_local(
6526 server: Arc<lsp::LanguageServer>,
6527 completions: Rc<RefCell<Box<[Completion]>>>,
6528 completion_index: usize,
6529 request_timeout: Duration,
6530 ) -> Result<()> {
6531 let server_id = server.server_id();
6532 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6533 return Ok(());
6534 }
6535
6536 let request = {
6537 let completion = &completions.borrow()[completion_index];
6538 match &completion.source {
6539 CompletionSource::Lsp {
6540 lsp_completion,
6541 resolved,
6542 server_id: completion_server_id,
6543 ..
6544 } => {
6545 if *resolved {
6546 return Ok(());
6547 }
6548 anyhow::ensure!(
6549 server_id == *completion_server_id,
6550 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6551 );
6552 server.request::<lsp::request::ResolveCompletionItem>(
6553 *lsp_completion.clone(),
6554 request_timeout,
6555 )
6556 }
6557 CompletionSource::BufferWord { .. }
6558 | CompletionSource::Dap { .. }
6559 | CompletionSource::Custom => {
6560 return Ok(());
6561 }
6562 }
6563 };
6564 let resolved_completion = request
6565 .await
6566 .into_response()
6567 .context("resolve completion")?;
6568
6569 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6570 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6571
6572 let mut completions = completions.borrow_mut();
6573 let completion = &mut completions[completion_index];
6574 if let CompletionSource::Lsp {
6575 lsp_completion,
6576 resolved,
6577 server_id: completion_server_id,
6578 ..
6579 } = &mut completion.source
6580 {
6581 if *resolved {
6582 return Ok(());
6583 }
6584 anyhow::ensure!(
6585 server_id == *completion_server_id,
6586 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6587 );
6588 **lsp_completion = resolved_completion;
6589 *resolved = true;
6590 }
6591 Ok(())
6592 }
6593
6594 async fn regenerate_completion_labels(
6595 adapter: Arc<CachedLspAdapter>,
6596 snapshot: &BufferSnapshot,
6597 completions: Rc<RefCell<Box<[Completion]>>>,
6598 completion_index: usize,
6599 ) -> Result<()> {
6600 let completion_item = completions.borrow()[completion_index]
6601 .source
6602 .lsp_completion(true)
6603 .map(Cow::into_owned);
6604 if let Some(lsp_documentation) = completion_item
6605 .as_ref()
6606 .and_then(|completion_item| completion_item.documentation.clone())
6607 {
6608 let mut completions = completions.borrow_mut();
6609 let completion = &mut completions[completion_index];
6610 completion.documentation = Some(lsp_documentation.into());
6611 } else {
6612 let mut completions = completions.borrow_mut();
6613 let completion = &mut completions[completion_index];
6614 completion.documentation = Some(CompletionDocumentation::Undocumented);
6615 }
6616
6617 let mut new_label = match completion_item {
6618 Some(completion_item) => {
6619 // Some language servers always return `detail` lazily via resolve, regardless of
6620 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6621 // See: https://github.com/yioneko/vtsls/issues/213
6622 let language = snapshot.language();
6623 match language {
6624 Some(language) => {
6625 adapter
6626 .labels_for_completions(
6627 std::slice::from_ref(&completion_item),
6628 language,
6629 )
6630 .await?
6631 }
6632 None => Vec::new(),
6633 }
6634 .pop()
6635 .flatten()
6636 .unwrap_or_else(|| {
6637 CodeLabel::fallback_for_completion(
6638 &completion_item,
6639 language.map(|language| language.as_ref()),
6640 )
6641 })
6642 }
6643 None => CodeLabel::plain(
6644 completions.borrow()[completion_index].new_text.clone(),
6645 None,
6646 ),
6647 };
6648 ensure_uniform_list_compatible_label(&mut new_label);
6649
6650 let mut completions = completions.borrow_mut();
6651 let completion = &mut completions[completion_index];
6652 if completion.label.filter_text() == new_label.filter_text() {
6653 completion.label = new_label;
6654 } else {
6655 log::error!(
6656 "Resolved completion changed display label from {} to {}. \
6657 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6658 completion.label.text(),
6659 new_label.text(),
6660 completion.label.filter_text(),
6661 new_label.filter_text()
6662 );
6663 }
6664
6665 Ok(())
6666 }
6667
6668 async fn resolve_completion_remote(
6669 project_id: u64,
6670 server_id: LanguageServerId,
6671 buffer_id: BufferId,
6672 completions: Rc<RefCell<Box<[Completion]>>>,
6673 completion_index: usize,
6674 client: AnyProtoClient,
6675 ) -> Result<()> {
6676 let lsp_completion = {
6677 let completion = &completions.borrow()[completion_index];
6678 match &completion.source {
6679 CompletionSource::Lsp {
6680 lsp_completion,
6681 resolved,
6682 server_id: completion_server_id,
6683 ..
6684 } => {
6685 anyhow::ensure!(
6686 server_id == *completion_server_id,
6687 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6688 );
6689 if *resolved {
6690 return Ok(());
6691 }
6692 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6693 }
6694 CompletionSource::Custom
6695 | CompletionSource::Dap { .. }
6696 | CompletionSource::BufferWord { .. } => {
6697 return Ok(());
6698 }
6699 }
6700 };
6701 let request = proto::ResolveCompletionDocumentation {
6702 project_id,
6703 language_server_id: server_id.0 as u64,
6704 lsp_completion,
6705 buffer_id: buffer_id.into(),
6706 };
6707
6708 let response = client
6709 .request(request)
6710 .await
6711 .context("completion documentation resolve proto request")?;
6712 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6713
6714 let documentation = if response.documentation.is_empty() {
6715 CompletionDocumentation::Undocumented
6716 } else if response.documentation_is_markdown {
6717 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6718 } else if response.documentation.lines().count() <= 1 {
6719 CompletionDocumentation::SingleLine(response.documentation.into())
6720 } else {
6721 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6722 };
6723
6724 let mut completions = completions.borrow_mut();
6725 let completion = &mut completions[completion_index];
6726 completion.documentation = Some(documentation);
6727 if let CompletionSource::Lsp {
6728 insert_range,
6729 lsp_completion,
6730 resolved,
6731 server_id: completion_server_id,
6732 lsp_defaults: _,
6733 } = &mut completion.source
6734 {
6735 let completion_insert_range = response
6736 .old_insert_start
6737 .and_then(deserialize_anchor)
6738 .zip(response.old_insert_end.and_then(deserialize_anchor));
6739 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6740
6741 if *resolved {
6742 return Ok(());
6743 }
6744 anyhow::ensure!(
6745 server_id == *completion_server_id,
6746 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6747 );
6748 **lsp_completion = resolved_lsp_completion;
6749 *resolved = true;
6750 }
6751
6752 let replace_range = response
6753 .old_replace_start
6754 .and_then(deserialize_anchor)
6755 .zip(response.old_replace_end.and_then(deserialize_anchor));
6756 if let Some((old_replace_start, old_replace_end)) = replace_range
6757 && !response.new_text.is_empty()
6758 {
6759 completion.new_text = response.new_text;
6760 completion.replace_range = old_replace_start..old_replace_end;
6761 }
6762
6763 Ok(())
6764 }
6765
6766 pub fn apply_additional_edits_for_completion(
6767 &self,
6768 buffer_handle: Entity<Buffer>,
6769 completions: Rc<RefCell<Box<[Completion]>>>,
6770 completion_index: usize,
6771 push_to_history: bool,
6772 all_commit_ranges: Vec<Range<language::Anchor>>,
6773 cx: &mut Context<Self>,
6774 ) -> Task<Result<Option<Transaction>>> {
6775 if let Some((client, project_id)) = self.upstream_client() {
6776 let buffer = buffer_handle.read(cx);
6777 let buffer_id = buffer.remote_id();
6778 cx.spawn(async move |_, cx| {
6779 let request = {
6780 let completion = completions.borrow()[completion_index].clone();
6781 proto::ApplyCompletionAdditionalEdits {
6782 project_id,
6783 buffer_id: buffer_id.into(),
6784 completion: Some(Self::serialize_completion(&CoreCompletion {
6785 replace_range: completion.replace_range,
6786 new_text: completion.new_text,
6787 source: completion.source,
6788 })),
6789 all_commit_ranges: all_commit_ranges
6790 .iter()
6791 .cloned()
6792 .map(language::proto::serialize_anchor_range)
6793 .collect(),
6794 }
6795 };
6796
6797 let Some(transaction) = client.request(request).await?.transaction else {
6798 return Ok(None);
6799 };
6800
6801 let transaction = language::proto::deserialize_transaction(transaction)?;
6802 buffer_handle
6803 .update(cx, |buffer, _| {
6804 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6805 })
6806 .await?;
6807 if push_to_history {
6808 buffer_handle.update(cx, |buffer, _| {
6809 buffer.push_transaction(transaction.clone(), Instant::now());
6810 buffer.finalize_last_transaction();
6811 });
6812 }
6813 Ok(Some(transaction))
6814 })
6815 } else {
6816 let request_timeout = ProjectSettings::get_global(cx)
6817 .global_lsp_settings
6818 .get_request_timeout();
6819
6820 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6821 let completion = &completions.borrow()[completion_index];
6822 let server_id = completion.source.server_id()?;
6823 Some(
6824 self.language_server_for_local_buffer(buffer, server_id, cx)?
6825 .1
6826 .clone(),
6827 )
6828 }) else {
6829 return Task::ready(Ok(None));
6830 };
6831
6832 cx.spawn(async move |this, cx| {
6833 Self::resolve_completion_local(
6834 server.clone(),
6835 completions.clone(),
6836 completion_index,
6837 request_timeout,
6838 )
6839 .await
6840 .context("resolving completion")?;
6841 let completion = completions.borrow()[completion_index].clone();
6842 let additional_text_edits = completion
6843 .source
6844 .lsp_completion(true)
6845 .as_ref()
6846 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6847 if let Some(edits) = additional_text_edits {
6848 let edits = this
6849 .update(cx, |this, cx| {
6850 this.as_local_mut().unwrap().edits_from_lsp(
6851 &buffer_handle,
6852 edits,
6853 server.server_id(),
6854 None,
6855 cx,
6856 )
6857 })?
6858 .await?;
6859
6860 buffer_handle.update(cx, |buffer, cx| {
6861 buffer.finalize_last_transaction();
6862 buffer.start_transaction();
6863
6864 for (range, text) in edits {
6865 let primary = &completion.replace_range;
6866
6867 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6868 // and the primary completion is just an insertion (empty range), then this is likely
6869 // an auto-import scenario and should not be considered overlapping
6870 // https://github.com/zed-industries/zed/issues/26136
6871 let is_file_start_auto_import = {
6872 let snapshot = buffer.snapshot();
6873 let primary_start_point = primary.start.to_point(&snapshot);
6874 let range_start_point = range.start.to_point(&snapshot);
6875
6876 let result = primary_start_point.row == 0
6877 && primary_start_point.column == 0
6878 && range_start_point.row == 0
6879 && range_start_point.column == 0;
6880
6881 result
6882 };
6883
6884 let has_overlap = if is_file_start_auto_import {
6885 false
6886 } else {
6887 all_commit_ranges.iter().any(|commit_range| {
6888 let start_within =
6889 commit_range.start.cmp(&range.start, buffer).is_le()
6890 && commit_range.end.cmp(&range.start, buffer).is_ge();
6891 let end_within =
6892 range.start.cmp(&commit_range.end, buffer).is_le()
6893 && range.end.cmp(&commit_range.end, buffer).is_ge();
6894 start_within || end_within
6895 })
6896 };
6897
6898 //Skip additional edits which overlap with the primary completion edit
6899 //https://github.com/zed-industries/zed/pull/1871
6900 if !has_overlap {
6901 buffer.edit([(range, text)], None, cx);
6902 }
6903 }
6904
6905 let transaction = if buffer.end_transaction(cx).is_some() {
6906 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6907 if !push_to_history {
6908 buffer.forget_transaction(transaction.id);
6909 }
6910 Some(transaction)
6911 } else {
6912 None
6913 };
6914 Ok(transaction)
6915 })
6916 } else {
6917 Ok(None)
6918 }
6919 })
6920 }
6921 }
6922
6923 pub fn pull_diagnostics(
6924 &mut self,
6925 buffer: Entity<Buffer>,
6926 cx: &mut Context<Self>,
6927 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6928 let buffer_id = buffer.read(cx).remote_id();
6929
6930 if let Some((client, upstream_project_id)) = self.upstream_client() {
6931 let mut suitable_capabilities = None;
6932 // Are we capable for proto request?
6933 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6934 &buffer,
6935 |capabilities| {
6936 if let Some(caps) = &capabilities.diagnostic_provider {
6937 suitable_capabilities = Some(caps.clone());
6938 true
6939 } else {
6940 false
6941 }
6942 },
6943 cx,
6944 );
6945 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6946 let Some(dynamic_caps) = suitable_capabilities else {
6947 return Task::ready(Ok(None));
6948 };
6949 assert!(any_server_has_diagnostics_provider);
6950
6951 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6952 let request = GetDocumentDiagnostics {
6953 previous_result_id: None,
6954 identifier,
6955 registration_id: None,
6956 };
6957 let request_timeout = ProjectSettings::get_global(cx)
6958 .global_lsp_settings
6959 .get_request_timeout();
6960 let request_task = client.request_lsp(
6961 upstream_project_id,
6962 None,
6963 request_timeout,
6964 cx.background_executor().clone(),
6965 request.to_proto(upstream_project_id, buffer.read(cx)),
6966 );
6967 cx.background_spawn(async move {
6968 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6969 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6970 // Do not attempt to further process the dummy responses here.
6971 let _response = request_task.await?;
6972 Ok(None)
6973 })
6974 } else {
6975 let servers = buffer.update(cx, |buffer, cx| {
6976 self.running_language_servers_for_local_buffer(buffer, cx)
6977 .map(|(_, server)| server.clone())
6978 .collect::<Vec<_>>()
6979 });
6980
6981 let pull_diagnostics = servers
6982 .into_iter()
6983 .flat_map(|server| {
6984 let result = maybe!({
6985 let local = self.as_local()?;
6986 let server_id = server.server_id();
6987 let providers_with_identifiers = local
6988 .language_server_dynamic_registrations
6989 .get(&server_id)
6990 .into_iter()
6991 .flat_map(|registrations| registrations.diagnostics.clone())
6992 .collect::<Vec<_>>();
6993 Some(
6994 providers_with_identifiers
6995 .into_iter()
6996 .map(|(registration_id, dynamic_caps)| {
6997 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6998 let registration_id = registration_id.map(SharedString::from);
6999 let result_id = self.result_id_for_buffer_pull(
7000 server_id,
7001 buffer_id,
7002 ®istration_id,
7003 cx,
7004 );
7005 self.request_lsp(
7006 buffer.clone(),
7007 LanguageServerToQuery::Other(server_id),
7008 GetDocumentDiagnostics {
7009 previous_result_id: result_id,
7010 registration_id,
7011 identifier,
7012 },
7013 cx,
7014 )
7015 })
7016 .collect::<Vec<_>>(),
7017 )
7018 });
7019
7020 result.unwrap_or_default()
7021 })
7022 .collect::<Vec<_>>();
7023
7024 cx.background_spawn(async move {
7025 let mut responses = Vec::new();
7026 for diagnostics in join_all(pull_diagnostics).await {
7027 responses.extend(diagnostics?);
7028 }
7029 Ok(Some(responses))
7030 })
7031 }
7032 }
7033
7034 pub fn applicable_inlay_chunks(
7035 &mut self,
7036 buffer: &Entity<Buffer>,
7037 ranges: &[Range<text::Anchor>],
7038 cx: &mut Context<Self>,
7039 ) -> Vec<Range<BufferRow>> {
7040 let buffer_snapshot = buffer.read(cx).snapshot();
7041 let ranges = ranges
7042 .iter()
7043 .map(|range| range.to_point(&buffer_snapshot))
7044 .collect::<Vec<_>>();
7045
7046 self.latest_lsp_data(buffer, cx)
7047 .inlay_hints
7048 .applicable_chunks(ranges.as_slice())
7049 .map(|chunk| chunk.row_range())
7050 .collect()
7051 }
7052
7053 pub fn invalidate_inlay_hints<'a>(
7054 &'a mut self,
7055 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7056 ) {
7057 for buffer_id in for_buffers {
7058 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7059 lsp_data.inlay_hints.clear();
7060 }
7061 }
7062 }
7063
7064 pub fn inlay_hints(
7065 &mut self,
7066 invalidate: InvalidationStrategy,
7067 buffer: Entity<Buffer>,
7068 ranges: Vec<Range<text::Anchor>>,
7069 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7070 cx: &mut Context<Self>,
7071 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7072 let next_hint_id = self.next_hint_id.clone();
7073 let lsp_data = self.latest_lsp_data(&buffer, cx);
7074 let query_version = lsp_data.buffer_version.clone();
7075 let mut lsp_refresh_requested = false;
7076 let for_server = if let InvalidationStrategy::RefreshRequested {
7077 server_id,
7078 request_id,
7079 } = invalidate
7080 {
7081 let invalidated = lsp_data
7082 .inlay_hints
7083 .invalidate_for_server_refresh(server_id, request_id);
7084 lsp_refresh_requested = invalidated;
7085 Some(server_id)
7086 } else {
7087 None
7088 };
7089 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7090 let known_chunks = known_chunks
7091 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7092 .map(|(_, known_chunks)| known_chunks)
7093 .unwrap_or_default();
7094
7095 let buffer_snapshot = buffer.read(cx).snapshot();
7096 let ranges = ranges
7097 .iter()
7098 .map(|range| range.to_point(&buffer_snapshot))
7099 .collect::<Vec<_>>();
7100
7101 let mut hint_fetch_tasks = Vec::new();
7102 let mut cached_inlay_hints = None;
7103 let mut ranges_to_query = None;
7104 let applicable_chunks = existing_inlay_hints
7105 .applicable_chunks(ranges.as_slice())
7106 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7107 .collect::<Vec<_>>();
7108 if applicable_chunks.is_empty() {
7109 return HashMap::default();
7110 }
7111
7112 for row_chunk in applicable_chunks {
7113 match (
7114 existing_inlay_hints
7115 .cached_hints(&row_chunk)
7116 .filter(|_| !lsp_refresh_requested)
7117 .cloned(),
7118 existing_inlay_hints
7119 .fetched_hints(&row_chunk)
7120 .as_ref()
7121 .filter(|_| !lsp_refresh_requested)
7122 .cloned(),
7123 ) {
7124 (None, None) => {
7125 let chunk_range = row_chunk.anchor_range();
7126 ranges_to_query
7127 .get_or_insert_with(Vec::new)
7128 .push((row_chunk, chunk_range));
7129 }
7130 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7131 (Some(cached_hints), None) => {
7132 for (server_id, cached_hints) in cached_hints {
7133 if for_server.is_none_or(|for_server| for_server == server_id) {
7134 cached_inlay_hints
7135 .get_or_insert_with(HashMap::default)
7136 .entry(row_chunk.row_range())
7137 .or_insert_with(HashMap::default)
7138 .entry(server_id)
7139 .or_insert_with(Vec::new)
7140 .extend(cached_hints);
7141 }
7142 }
7143 }
7144 (Some(cached_hints), Some(fetched_hints)) => {
7145 hint_fetch_tasks.push((row_chunk, fetched_hints));
7146 for (server_id, cached_hints) in cached_hints {
7147 if for_server.is_none_or(|for_server| for_server == server_id) {
7148 cached_inlay_hints
7149 .get_or_insert_with(HashMap::default)
7150 .entry(row_chunk.row_range())
7151 .or_insert_with(HashMap::default)
7152 .entry(server_id)
7153 .or_insert_with(Vec::new)
7154 .extend(cached_hints);
7155 }
7156 }
7157 }
7158 }
7159 }
7160
7161 if hint_fetch_tasks.is_empty()
7162 && ranges_to_query
7163 .as_ref()
7164 .is_none_or(|ranges| ranges.is_empty())
7165 && let Some(cached_inlay_hints) = cached_inlay_hints
7166 {
7167 cached_inlay_hints
7168 .into_iter()
7169 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7170 .collect()
7171 } else {
7172 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7173 // When a server refresh was requested, other servers' cached hints
7174 // are unaffected by the refresh and must be included in the result.
7175 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7176 // removes all visible hints but only adds back the requesting
7177 // server's new hints, permanently losing other servers' hints.
7178 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7179 lsp_data
7180 .inlay_hints
7181 .cached_hints(&chunk)
7182 .cloned()
7183 .unwrap_or_default()
7184 } else {
7185 HashMap::default()
7186 };
7187
7188 let next_hint_id = next_hint_id.clone();
7189 let buffer = buffer.clone();
7190 let query_version = query_version.clone();
7191 let new_inlay_hints = cx
7192 .spawn(async move |lsp_store, cx| {
7193 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7194 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7195 })?;
7196 new_fetch_task
7197 .await
7198 .and_then(|new_hints_by_server| {
7199 lsp_store.update(cx, |lsp_store, cx| {
7200 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7201 let update_cache = lsp_data.buffer_version == query_version;
7202 if new_hints_by_server.is_empty() {
7203 if update_cache {
7204 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7205 }
7206 other_servers_cached
7207 } else {
7208 let mut result = other_servers_cached;
7209 for (server_id, new_hints) in new_hints_by_server {
7210 let new_hints = new_hints
7211 .into_iter()
7212 .map(|new_hint| {
7213 (
7214 InlayId::Hint(next_hint_id.fetch_add(
7215 1,
7216 atomic::Ordering::AcqRel,
7217 )),
7218 new_hint,
7219 )
7220 })
7221 .collect::<Vec<_>>();
7222 if update_cache {
7223 lsp_data.inlay_hints.insert_new_hints(
7224 chunk,
7225 server_id,
7226 new_hints.clone(),
7227 );
7228 }
7229 result.insert(server_id, new_hints);
7230 }
7231 result
7232 }
7233 })
7234 })
7235 .map_err(Arc::new)
7236 })
7237 .shared();
7238
7239 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7240 *fetch_task = Some(new_inlay_hints.clone());
7241 hint_fetch_tasks.push((chunk, new_inlay_hints));
7242 }
7243
7244 cached_inlay_hints
7245 .unwrap_or_default()
7246 .into_iter()
7247 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7248 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7249 (
7250 chunk.row_range(),
7251 cx.spawn(async move |_, _| {
7252 hints_fetch.await.map_err(|e| {
7253 if e.error_code() != ErrorCode::Internal {
7254 anyhow!(e.error_code())
7255 } else {
7256 anyhow!("{e:#}")
7257 }
7258 })
7259 }),
7260 )
7261 }))
7262 .collect()
7263 }
7264 }
7265
7266 fn fetch_inlay_hints(
7267 &mut self,
7268 for_server: Option<LanguageServerId>,
7269 buffer: &Entity<Buffer>,
7270 range: Range<Anchor>,
7271 cx: &mut Context<Self>,
7272 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7273 let request = InlayHints {
7274 range: range.clone(),
7275 };
7276 if let Some((upstream_client, project_id)) = self.upstream_client() {
7277 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7278 return Task::ready(Ok(HashMap::default()));
7279 }
7280 let request_timeout = ProjectSettings::get_global(cx)
7281 .global_lsp_settings
7282 .get_request_timeout();
7283 let request_task = upstream_client.request_lsp(
7284 project_id,
7285 for_server.map(|id| id.to_proto()),
7286 request_timeout,
7287 cx.background_executor().clone(),
7288 request.to_proto(project_id, buffer.read(cx)),
7289 );
7290 let buffer = buffer.clone();
7291 cx.spawn(async move |weak_lsp_store, cx| {
7292 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7293 return Ok(HashMap::default());
7294 };
7295 let Some(responses) = request_task.await? else {
7296 return Ok(HashMap::default());
7297 };
7298
7299 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7300 let lsp_store = lsp_store.clone();
7301 let buffer = buffer.clone();
7302 let cx = cx.clone();
7303 let request = request.clone();
7304 async move {
7305 (
7306 LanguageServerId::from_proto(response.server_id),
7307 request
7308 .response_from_proto(response.response, lsp_store, buffer, cx)
7309 .await,
7310 )
7311 }
7312 }))
7313 .await;
7314
7315 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7316 let mut has_errors = false;
7317 let inlay_hints = inlay_hints
7318 .into_iter()
7319 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7320 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7321 Err(e) => {
7322 has_errors = true;
7323 log::error!("{e:#}");
7324 None
7325 }
7326 })
7327 .map(|(server_id, mut new_hints)| {
7328 new_hints.retain(|hint| {
7329 hint.position.is_valid(&buffer_snapshot)
7330 && range.start.is_valid(&buffer_snapshot)
7331 && range.end.is_valid(&buffer_snapshot)
7332 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7333 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7334 });
7335 (server_id, new_hints)
7336 })
7337 .collect::<HashMap<_, _>>();
7338 anyhow::ensure!(
7339 !has_errors || !inlay_hints.is_empty(),
7340 "Failed to fetch inlay hints"
7341 );
7342 Ok(inlay_hints)
7343 })
7344 } else {
7345 let inlay_hints_task = match for_server {
7346 Some(server_id) => {
7347 let server_task = self.request_lsp(
7348 buffer.clone(),
7349 LanguageServerToQuery::Other(server_id),
7350 request,
7351 cx,
7352 );
7353 cx.background_spawn(async move {
7354 let mut responses = Vec::new();
7355 match server_task.await {
7356 Ok(response) => responses.push((server_id, response)),
7357 // rust-analyzer likes to error with this when its still loading up
7358 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7359 Err(e) => log::error!(
7360 "Error handling response for inlay hints request: {e:#}"
7361 ),
7362 }
7363 responses
7364 })
7365 }
7366 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7367 };
7368 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7369 cx.background_spawn(async move {
7370 Ok(inlay_hints_task
7371 .await
7372 .into_iter()
7373 .map(|(server_id, mut new_hints)| {
7374 new_hints.retain(|hint| {
7375 hint.position.is_valid(&buffer_snapshot)
7376 && range.start.is_valid(&buffer_snapshot)
7377 && range.end.is_valid(&buffer_snapshot)
7378 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7379 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7380 });
7381 (server_id, new_hints)
7382 })
7383 .collect())
7384 })
7385 }
7386 }
7387
7388 fn diagnostic_registration_exists(
7389 &self,
7390 server_id: LanguageServerId,
7391 registration_id: &Option<SharedString>,
7392 ) -> bool {
7393 let Some(local) = self.as_local() else {
7394 return false;
7395 };
7396 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7397 else {
7398 return false;
7399 };
7400 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7401 registrations.diagnostics.contains_key(®istration_key)
7402 }
7403
7404 pub fn pull_diagnostics_for_buffer(
7405 &mut self,
7406 buffer: Entity<Buffer>,
7407 cx: &mut Context<Self>,
7408 ) -> Task<anyhow::Result<()>> {
7409 let diagnostics = self.pull_diagnostics(buffer, cx);
7410 cx.spawn(async move |lsp_store, cx| {
7411 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7412 return Ok(());
7413 };
7414 lsp_store.update(cx, |lsp_store, cx| {
7415 if lsp_store.as_local().is_none() {
7416 return;
7417 }
7418
7419 let mut unchanged_buffers = HashMap::default();
7420 let server_diagnostics_updates = diagnostics
7421 .into_iter()
7422 .filter_map(|diagnostics_set| match diagnostics_set {
7423 LspPullDiagnostics::Response {
7424 server_id,
7425 uri,
7426 diagnostics,
7427 registration_id,
7428 } => Some((server_id, uri, diagnostics, registration_id)),
7429 LspPullDiagnostics::Default => None,
7430 })
7431 .filter(|(server_id, _, _, registration_id)| {
7432 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7433 })
7434 .fold(
7435 HashMap::default(),
7436 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7437 let (result_id, diagnostics) = match diagnostics {
7438 PulledDiagnostics::Unchanged { result_id } => {
7439 unchanged_buffers
7440 .entry(new_registration_id.clone())
7441 .or_insert_with(HashSet::default)
7442 .insert(uri.clone());
7443 (Some(result_id), Vec::new())
7444 }
7445 PulledDiagnostics::Changed {
7446 result_id,
7447 diagnostics,
7448 } => (result_id, diagnostics),
7449 };
7450 let disk_based_sources = Cow::Owned(
7451 lsp_store
7452 .language_server_adapter_for_id(server_id)
7453 .as_ref()
7454 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7455 .unwrap_or(&[])
7456 .to_vec(),
7457 );
7458 acc.entry(server_id)
7459 .or_insert_with(HashMap::default)
7460 .entry(new_registration_id.clone())
7461 .or_insert_with(Vec::new)
7462 .push(DocumentDiagnosticsUpdate {
7463 server_id,
7464 diagnostics: lsp::PublishDiagnosticsParams {
7465 uri,
7466 diagnostics,
7467 version: None,
7468 },
7469 result_id: result_id.map(SharedString::new),
7470 disk_based_sources,
7471 registration_id: new_registration_id,
7472 });
7473 acc
7474 },
7475 );
7476
7477 for diagnostic_updates in server_diagnostics_updates.into_values() {
7478 for (registration_id, diagnostic_updates) in diagnostic_updates {
7479 lsp_store
7480 .merge_lsp_diagnostics(
7481 DiagnosticSourceKind::Pulled,
7482 diagnostic_updates,
7483 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7484 DiagnosticSourceKind::Pulled => {
7485 old_diagnostic.registration_id != registration_id
7486 || unchanged_buffers
7487 .get(&old_diagnostic.registration_id)
7488 .is_some_and(|unchanged_buffers| {
7489 unchanged_buffers.contains(&document_uri)
7490 })
7491 }
7492 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7493 true
7494 }
7495 },
7496 cx,
7497 )
7498 .log_err();
7499 }
7500 }
7501 })
7502 })
7503 }
7504
7505 pub fn signature_help<T: ToPointUtf16>(
7506 &mut self,
7507 buffer: &Entity<Buffer>,
7508 position: T,
7509 cx: &mut Context<Self>,
7510 ) -> Task<Option<Vec<SignatureHelp>>> {
7511 let position = position.to_point_utf16(buffer.read(cx));
7512
7513 if let Some((client, upstream_project_id)) = self.upstream_client() {
7514 let request = GetSignatureHelp { position };
7515 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7516 return Task::ready(None);
7517 }
7518 let request_timeout = ProjectSettings::get_global(cx)
7519 .global_lsp_settings
7520 .get_request_timeout();
7521 let request_task = client.request_lsp(
7522 upstream_project_id,
7523 None,
7524 request_timeout,
7525 cx.background_executor().clone(),
7526 request.to_proto(upstream_project_id, buffer.read(cx)),
7527 );
7528 let buffer = buffer.clone();
7529 cx.spawn(async move |weak_lsp_store, cx| {
7530 let lsp_store = weak_lsp_store.upgrade()?;
7531 let signatures = join_all(
7532 request_task
7533 .await
7534 .log_err()
7535 .flatten()
7536 .map(|response| response.payload)
7537 .unwrap_or_default()
7538 .into_iter()
7539 .map(|response| {
7540 let response = GetSignatureHelp { position }.response_from_proto(
7541 response.response,
7542 lsp_store.clone(),
7543 buffer.clone(),
7544 cx.clone(),
7545 );
7546 async move { response.await.log_err().flatten() }
7547 }),
7548 )
7549 .await
7550 .into_iter()
7551 .flatten()
7552 .collect();
7553 Some(signatures)
7554 })
7555 } else {
7556 let all_actions_task = self.request_multiple_lsp_locally(
7557 buffer,
7558 Some(position),
7559 GetSignatureHelp { position },
7560 cx,
7561 );
7562 cx.background_spawn(async move {
7563 Some(
7564 all_actions_task
7565 .await
7566 .into_iter()
7567 .flat_map(|(_, actions)| actions)
7568 .collect::<Vec<_>>(),
7569 )
7570 })
7571 }
7572 }
7573
7574 pub fn hover(
7575 &mut self,
7576 buffer: &Entity<Buffer>,
7577 position: PointUtf16,
7578 cx: &mut Context<Self>,
7579 ) -> Task<Option<Vec<Hover>>> {
7580 if let Some((client, upstream_project_id)) = self.upstream_client() {
7581 let request = GetHover { position };
7582 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7583 return Task::ready(None);
7584 }
7585 let request_timeout = ProjectSettings::get_global(cx)
7586 .global_lsp_settings
7587 .get_request_timeout();
7588 let request_task = client.request_lsp(
7589 upstream_project_id,
7590 None,
7591 request_timeout,
7592 cx.background_executor().clone(),
7593 request.to_proto(upstream_project_id, buffer.read(cx)),
7594 );
7595 let buffer = buffer.clone();
7596 cx.spawn(async move |weak_lsp_store, cx| {
7597 let lsp_store = weak_lsp_store.upgrade()?;
7598 let hovers = join_all(
7599 request_task
7600 .await
7601 .log_err()
7602 .flatten()
7603 .map(|response| response.payload)
7604 .unwrap_or_default()
7605 .into_iter()
7606 .map(|response| {
7607 let response = GetHover { position }.response_from_proto(
7608 response.response,
7609 lsp_store.clone(),
7610 buffer.clone(),
7611 cx.clone(),
7612 );
7613 async move {
7614 response
7615 .await
7616 .log_err()
7617 .flatten()
7618 .and_then(remove_empty_hover_blocks)
7619 }
7620 }),
7621 )
7622 .await
7623 .into_iter()
7624 .flatten()
7625 .collect();
7626 Some(hovers)
7627 })
7628 } else {
7629 let all_actions_task = self.request_multiple_lsp_locally(
7630 buffer,
7631 Some(position),
7632 GetHover { position },
7633 cx,
7634 );
7635 cx.background_spawn(async move {
7636 Some(
7637 all_actions_task
7638 .await
7639 .into_iter()
7640 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7641 .collect::<Vec<Hover>>(),
7642 )
7643 })
7644 }
7645 }
7646
7647 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7648 let language_registry = self.languages.clone();
7649
7650 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7651 let request = upstream_client.request(proto::GetProjectSymbols {
7652 project_id: *project_id,
7653 query: query.to_string(),
7654 });
7655 cx.foreground_executor().spawn(async move {
7656 let response = request.await?;
7657 let mut symbols = Vec::new();
7658 let core_symbols = response
7659 .symbols
7660 .into_iter()
7661 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7662 .collect::<Vec<_>>();
7663 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7664 .await;
7665 Ok(symbols)
7666 })
7667 } else if let Some(local) = self.as_local() {
7668 struct WorkspaceSymbolsResult {
7669 server_id: LanguageServerId,
7670 lsp_adapter: Arc<CachedLspAdapter>,
7671 worktree: WeakEntity<Worktree>,
7672 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7673 }
7674
7675 let mut requests = Vec::new();
7676 let mut requested_servers = BTreeSet::new();
7677 let request_timeout = ProjectSettings::get_global(cx)
7678 .global_lsp_settings
7679 .get_request_timeout();
7680
7681 for (seed, state) in local.language_server_ids.iter() {
7682 let Some(worktree_handle) = self
7683 .worktree_store
7684 .read(cx)
7685 .worktree_for_id(seed.worktree_id, cx)
7686 else {
7687 continue;
7688 };
7689
7690 let worktree = worktree_handle.read(cx);
7691 if !worktree.is_visible() {
7692 continue;
7693 }
7694
7695 if !requested_servers.insert(state.id) {
7696 continue;
7697 }
7698
7699 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7700 Some(LanguageServerState::Running {
7701 adapter, server, ..
7702 }) => (adapter.clone(), server),
7703
7704 _ => continue,
7705 };
7706
7707 let supports_workspace_symbol_request =
7708 match server.capabilities().workspace_symbol_provider {
7709 Some(OneOf::Left(supported)) => supported,
7710 Some(OneOf::Right(_)) => true,
7711 None => false,
7712 };
7713
7714 if !supports_workspace_symbol_request {
7715 continue;
7716 }
7717
7718 let worktree_handle = worktree_handle.clone();
7719 let server_id = server.server_id();
7720 requests.push(
7721 server
7722 .request::<lsp::request::WorkspaceSymbolRequest>(
7723 lsp::WorkspaceSymbolParams {
7724 query: query.to_string(),
7725 ..Default::default()
7726 },
7727 request_timeout,
7728 )
7729 .map(move |response| {
7730 let lsp_symbols = response
7731 .into_response()
7732 .context("workspace symbols request")
7733 .log_err()
7734 .flatten()
7735 .map(|symbol_response| match symbol_response {
7736 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7737 flat_responses
7738 .into_iter()
7739 .map(|lsp_symbol| {
7740 (
7741 lsp_symbol.name,
7742 lsp_symbol.kind,
7743 lsp_symbol.location,
7744 lsp_symbol.container_name,
7745 )
7746 })
7747 .collect::<Vec<_>>()
7748 }
7749 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7750 nested_responses
7751 .into_iter()
7752 .filter_map(|lsp_symbol| {
7753 let location = match lsp_symbol.location {
7754 OneOf::Left(location) => location,
7755 OneOf::Right(_) => {
7756 log::error!(
7757 "Unexpected: client capabilities \
7758 forbid symbol resolutions in \
7759 workspace.symbol.resolveSupport"
7760 );
7761 return None;
7762 }
7763 };
7764 Some((
7765 lsp_symbol.name,
7766 lsp_symbol.kind,
7767 location,
7768 lsp_symbol.container_name,
7769 ))
7770 })
7771 .collect::<Vec<_>>()
7772 }
7773 })
7774 .unwrap_or_default();
7775
7776 WorkspaceSymbolsResult {
7777 server_id,
7778 lsp_adapter,
7779 worktree: worktree_handle.downgrade(),
7780 lsp_symbols,
7781 }
7782 }),
7783 );
7784 }
7785
7786 cx.spawn(async move |this, cx| {
7787 let responses = futures::future::join_all(requests).await;
7788 let this = match this.upgrade() {
7789 Some(this) => this,
7790 None => return Ok(Vec::new()),
7791 };
7792
7793 let mut symbols = Vec::new();
7794 for result in responses {
7795 let core_symbols = this.update(cx, |this, cx| {
7796 result
7797 .lsp_symbols
7798 .into_iter()
7799 .filter_map(
7800 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7801 let abs_path = symbol_location.uri.to_file_path().ok()?;
7802 let source_worktree = result.worktree.upgrade()?;
7803 let source_worktree_id = source_worktree.read(cx).id();
7804
7805 let path = if let Some((tree, rel_path)) =
7806 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7807 {
7808 let worktree_id = tree.read(cx).id();
7809 SymbolLocation::InProject(ProjectPath {
7810 worktree_id,
7811 path: rel_path,
7812 })
7813 } else {
7814 SymbolLocation::OutsideProject {
7815 signature: this.symbol_signature(&abs_path),
7816 abs_path: abs_path.into(),
7817 }
7818 };
7819
7820 Some(CoreSymbol {
7821 source_language_server_id: result.server_id,
7822 language_server_name: result.lsp_adapter.name.clone(),
7823 source_worktree_id,
7824 path,
7825 kind: symbol_kind,
7826 name: collapse_newlines(&symbol_name, "↵ "),
7827 range: range_from_lsp(symbol_location.range),
7828 container_name: container_name
7829 .map(|c| collapse_newlines(&c, "↵ ")),
7830 })
7831 },
7832 )
7833 .collect::<Vec<_>>()
7834 });
7835
7836 populate_labels_for_symbols(
7837 core_symbols,
7838 &language_registry,
7839 Some(result.lsp_adapter),
7840 &mut symbols,
7841 )
7842 .await;
7843 }
7844
7845 Ok(symbols)
7846 })
7847 } else {
7848 Task::ready(Err(anyhow!("No upstream client or local language server")))
7849 }
7850 }
7851
7852 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7853 let mut summary = DiagnosticSummary::default();
7854 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7855 summary.error_count += path_summary.error_count;
7856 summary.warning_count += path_summary.warning_count;
7857 }
7858 summary
7859 }
7860
7861 /// Returns the diagnostic summary for a specific project path.
7862 pub fn diagnostic_summary_for_path(
7863 &self,
7864 project_path: &ProjectPath,
7865 _: &App,
7866 ) -> DiagnosticSummary {
7867 if let Some(summaries) = self
7868 .diagnostic_summaries
7869 .get(&project_path.worktree_id)
7870 .and_then(|map| map.get(&project_path.path))
7871 {
7872 let (error_count, warning_count) = summaries.iter().fold(
7873 (0, 0),
7874 |(error_count, warning_count), (_language_server_id, summary)| {
7875 (
7876 error_count + summary.error_count,
7877 warning_count + summary.warning_count,
7878 )
7879 },
7880 );
7881
7882 DiagnosticSummary {
7883 error_count,
7884 warning_count,
7885 }
7886 } else {
7887 DiagnosticSummary::default()
7888 }
7889 }
7890
7891 pub fn diagnostic_summaries<'a>(
7892 &'a self,
7893 include_ignored: bool,
7894 cx: &'a App,
7895 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7896 self.worktree_store
7897 .read(cx)
7898 .visible_worktrees(cx)
7899 .filter_map(|worktree| {
7900 let worktree = worktree.read(cx);
7901 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7902 })
7903 .flat_map(move |(worktree, summaries)| {
7904 let worktree_id = worktree.id();
7905 summaries
7906 .iter()
7907 .filter(move |(path, _)| {
7908 include_ignored
7909 || worktree
7910 .entry_for_path(path.as_ref())
7911 .is_some_and(|entry| !entry.is_ignored)
7912 })
7913 .flat_map(move |(path, summaries)| {
7914 summaries.iter().map(move |(server_id, summary)| {
7915 (
7916 ProjectPath {
7917 worktree_id,
7918 path: path.clone(),
7919 },
7920 *server_id,
7921 *summary,
7922 )
7923 })
7924 })
7925 })
7926 }
7927
7928 pub fn on_buffer_edited(
7929 &mut self,
7930 buffer: Entity<Buffer>,
7931 cx: &mut Context<Self>,
7932 ) -> Option<()> {
7933 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7934 Some(
7935 self.as_local()?
7936 .language_servers_for_buffer(buffer, cx)
7937 .map(|i| i.1.clone())
7938 .collect(),
7939 )
7940 })?;
7941
7942 let buffer = buffer.read(cx);
7943 let file = File::from_dyn(buffer.file())?;
7944 let abs_path = file.as_local()?.abs_path(cx);
7945 let uri = lsp::Uri::from_file_path(&abs_path)
7946 .ok()
7947 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7948 .log_err()?;
7949 let next_snapshot = buffer.text_snapshot();
7950 for language_server in language_servers {
7951 let language_server = language_server.clone();
7952
7953 let buffer_snapshots = self
7954 .as_local_mut()?
7955 .buffer_snapshots
7956 .get_mut(&buffer.remote_id())
7957 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7958 let previous_snapshot = buffer_snapshots.last()?;
7959
7960 let build_incremental_change = || {
7961 buffer
7962 .edits_since::<Dimensions<PointUtf16, usize>>(
7963 previous_snapshot.snapshot.version(),
7964 )
7965 .map(|edit| {
7966 let edit_start = edit.new.start.0;
7967 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7968 let new_text = next_snapshot
7969 .text_for_range(edit.new.start.1..edit.new.end.1)
7970 .collect();
7971 lsp::TextDocumentContentChangeEvent {
7972 range: Some(lsp::Range::new(
7973 point_to_lsp(edit_start),
7974 point_to_lsp(edit_end),
7975 )),
7976 range_length: None,
7977 text: new_text,
7978 }
7979 })
7980 .collect()
7981 };
7982
7983 let document_sync_kind = language_server
7984 .capabilities()
7985 .text_document_sync
7986 .as_ref()
7987 .and_then(|sync| match sync {
7988 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7989 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7990 });
7991
7992 let content_changes: Vec<_> = match document_sync_kind {
7993 Some(lsp::TextDocumentSyncKind::FULL) => {
7994 vec![lsp::TextDocumentContentChangeEvent {
7995 range: None,
7996 range_length: None,
7997 text: next_snapshot.text(),
7998 }]
7999 }
8000 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8001 _ => {
8002 #[cfg(any(test, feature = "test-support"))]
8003 {
8004 build_incremental_change()
8005 }
8006
8007 #[cfg(not(any(test, feature = "test-support")))]
8008 {
8009 continue;
8010 }
8011 }
8012 };
8013
8014 let next_version = previous_snapshot.version + 1;
8015 buffer_snapshots.push(LspBufferSnapshot {
8016 version: next_version,
8017 snapshot: next_snapshot.clone(),
8018 });
8019
8020 language_server
8021 .notify::<lsp::notification::DidChangeTextDocument>(
8022 lsp::DidChangeTextDocumentParams {
8023 text_document: lsp::VersionedTextDocumentIdentifier::new(
8024 uri.clone(),
8025 next_version,
8026 ),
8027 content_changes,
8028 },
8029 )
8030 .ok();
8031 self.pull_workspace_diagnostics(language_server.server_id());
8032 }
8033
8034 None
8035 }
8036
8037 pub fn on_buffer_saved(
8038 &mut self,
8039 buffer: Entity<Buffer>,
8040 cx: &mut Context<Self>,
8041 ) -> Option<()> {
8042 let file = File::from_dyn(buffer.read(cx).file())?;
8043 let worktree_id = file.worktree_id(cx);
8044 let abs_path = file.as_local()?.abs_path(cx);
8045 let text_document = lsp::TextDocumentIdentifier {
8046 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8047 };
8048 let local = self.as_local()?;
8049
8050 for server in local.language_servers_for_worktree(worktree_id) {
8051 if let Some(include_text) = include_text(server.as_ref()) {
8052 let text = if include_text {
8053 Some(buffer.read(cx).text())
8054 } else {
8055 None
8056 };
8057 server
8058 .notify::<lsp::notification::DidSaveTextDocument>(
8059 lsp::DidSaveTextDocumentParams {
8060 text_document: text_document.clone(),
8061 text,
8062 },
8063 )
8064 .ok();
8065 }
8066 }
8067
8068 let language_servers = buffer.update(cx, |buffer, cx| {
8069 local.language_server_ids_for_buffer(buffer, cx)
8070 });
8071 for language_server_id in language_servers {
8072 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8073 }
8074
8075 None
8076 }
8077
8078 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8079 maybe!(async move {
8080 let mut refreshed_servers = HashSet::default();
8081 let servers = lsp_store
8082 .update(cx, |lsp_store, cx| {
8083 let local = lsp_store.as_local()?;
8084
8085 let servers = local
8086 .language_server_ids
8087 .iter()
8088 .filter_map(|(seed, state)| {
8089 let worktree = lsp_store
8090 .worktree_store
8091 .read(cx)
8092 .worktree_for_id(seed.worktree_id, cx);
8093 let delegate: Arc<dyn LspAdapterDelegate> =
8094 worktree.map(|worktree| {
8095 LocalLspAdapterDelegate::new(
8096 local.languages.clone(),
8097 &local.environment,
8098 cx.weak_entity(),
8099 &worktree,
8100 local.http_client.clone(),
8101 local.fs.clone(),
8102 cx,
8103 )
8104 })?;
8105 let server_id = state.id;
8106
8107 let states = local.language_servers.get(&server_id)?;
8108
8109 match states {
8110 LanguageServerState::Starting { .. } => None,
8111 LanguageServerState::Running {
8112 adapter, server, ..
8113 } => {
8114 let adapter = adapter.clone();
8115 let server = server.clone();
8116 refreshed_servers.insert(server.name());
8117 let toolchain = seed.toolchain.clone();
8118 Some(cx.spawn(async move |_, cx| {
8119 let settings =
8120 LocalLspStore::workspace_configuration_for_adapter(
8121 adapter.adapter.clone(),
8122 &delegate,
8123 toolchain,
8124 None,
8125 cx,
8126 )
8127 .await
8128 .ok()?;
8129 server
8130 .notify::<lsp::notification::DidChangeConfiguration>(
8131 lsp::DidChangeConfigurationParams { settings },
8132 )
8133 .ok()?;
8134 Some(())
8135 }))
8136 }
8137 }
8138 })
8139 .collect::<Vec<_>>();
8140
8141 Some(servers)
8142 })
8143 .ok()
8144 .flatten()?;
8145
8146 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8147 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8148 // to stop and unregister its language server wrapper.
8149 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8150 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8151 let _: Vec<Option<()>> = join_all(servers).await;
8152
8153 Some(())
8154 })
8155 .await;
8156 }
8157
8158 fn maintain_workspace_config(
8159 external_refresh_requests: watch::Receiver<()>,
8160 cx: &mut Context<Self>,
8161 ) -> Task<Result<()>> {
8162 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8163 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8164
8165 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8166 *settings_changed_tx.borrow_mut() = ();
8167 });
8168
8169 let mut joint_future =
8170 futures::stream::select(settings_changed_rx, external_refresh_requests);
8171 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8172 // - 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).
8173 // - 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.
8174 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8175 // - 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,
8176 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8177 cx.spawn(async move |this, cx| {
8178 while let Some(()) = joint_future.next().await {
8179 this.update(cx, |this, cx| {
8180 this.refresh_server_tree(cx);
8181 })
8182 .ok();
8183
8184 Self::refresh_workspace_configurations(&this, cx).await;
8185 }
8186
8187 drop(settings_observation);
8188 anyhow::Ok(())
8189 })
8190 }
8191
8192 pub fn running_language_servers_for_local_buffer<'a>(
8193 &'a self,
8194 buffer: &Buffer,
8195 cx: &mut App,
8196 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8197 let local = self.as_local();
8198 let language_server_ids = local
8199 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8200 .unwrap_or_default();
8201
8202 language_server_ids
8203 .into_iter()
8204 .filter_map(
8205 move |server_id| match local?.language_servers.get(&server_id)? {
8206 LanguageServerState::Running {
8207 adapter, server, ..
8208 } => Some((adapter, server)),
8209 _ => None,
8210 },
8211 )
8212 }
8213
8214 pub fn language_servers_for_local_buffer(
8215 &self,
8216 buffer: &Buffer,
8217 cx: &mut App,
8218 ) -> Vec<LanguageServerId> {
8219 let local = self.as_local();
8220 local
8221 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8222 .unwrap_or_default()
8223 }
8224
8225 pub fn language_server_for_local_buffer<'a>(
8226 &'a self,
8227 buffer: &'a Buffer,
8228 server_id: LanguageServerId,
8229 cx: &'a mut App,
8230 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8231 self.as_local()?
8232 .language_servers_for_buffer(buffer, cx)
8233 .find(|(_, s)| s.server_id() == server_id)
8234 }
8235
8236 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8237 self.diagnostic_summaries.remove(&id_to_remove);
8238 if let Some(local) = self.as_local_mut() {
8239 let to_remove = local.remove_worktree(id_to_remove, cx);
8240 for server in to_remove {
8241 self.language_server_statuses.remove(&server);
8242 }
8243 }
8244 }
8245
8246 fn invalidate_diagnostic_summaries_for_removed_entries(
8247 &mut self,
8248 worktree_id: WorktreeId,
8249 changes: &UpdatedEntriesSet,
8250 cx: &mut Context<Self>,
8251 ) {
8252 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8253 return;
8254 };
8255
8256 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8257 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8258 let downstream = self.downstream_client.clone();
8259
8260 for (path, _, _) in changes
8261 .iter()
8262 .filter(|(_, _, change)| *change == PathChange::Removed)
8263 {
8264 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8265 for (server_id, _) in &summaries_by_server_id {
8266 cleared_server_ids.insert(*server_id);
8267 if let Some((client, project_id)) = &downstream {
8268 client
8269 .send(proto::UpdateDiagnosticSummary {
8270 project_id: *project_id,
8271 worktree_id: worktree_id.to_proto(),
8272 summary: Some(proto::DiagnosticSummary {
8273 path: path.as_ref().to_proto(),
8274 language_server_id: server_id.0 as u64,
8275 error_count: 0,
8276 warning_count: 0,
8277 }),
8278 more_summaries: Vec::new(),
8279 })
8280 .ok();
8281 }
8282 }
8283 cleared_paths.push(ProjectPath {
8284 worktree_id,
8285 path: path.clone(),
8286 });
8287 }
8288 }
8289
8290 if !cleared_paths.is_empty() {
8291 for server_id in cleared_server_ids {
8292 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8293 server_id,
8294 paths: cleared_paths.clone(),
8295 });
8296 }
8297 }
8298 }
8299
8300 pub fn shared(
8301 &mut self,
8302 project_id: u64,
8303 downstream_client: AnyProtoClient,
8304 _: &mut Context<Self>,
8305 ) {
8306 self.downstream_client = Some((downstream_client.clone(), project_id));
8307
8308 for (server_id, status) in &self.language_server_statuses {
8309 if let Some(server) = self.language_server_for_id(*server_id) {
8310 downstream_client
8311 .send(proto::StartLanguageServer {
8312 project_id,
8313 server: Some(proto::LanguageServer {
8314 id: server_id.to_proto(),
8315 name: status.name.to_string(),
8316 worktree_id: status.worktree.map(|id| id.to_proto()),
8317 }),
8318 capabilities: serde_json::to_string(&server.capabilities())
8319 .expect("serializing server LSP capabilities"),
8320 })
8321 .log_err();
8322 }
8323 }
8324 }
8325
8326 pub fn disconnected_from_host(&mut self) {
8327 self.downstream_client.take();
8328 }
8329
8330 pub fn disconnected_from_ssh_remote(&mut self) {
8331 if let LspStoreMode::Remote(RemoteLspStore {
8332 upstream_client, ..
8333 }) = &mut self.mode
8334 {
8335 upstream_client.take();
8336 }
8337 }
8338
8339 pub(crate) fn set_language_server_statuses_from_proto(
8340 &mut self,
8341 project: WeakEntity<Project>,
8342 language_servers: Vec<proto::LanguageServer>,
8343 server_capabilities: Vec<String>,
8344 cx: &mut Context<Self>,
8345 ) {
8346 let lsp_logs = cx
8347 .try_global::<GlobalLogStore>()
8348 .map(|lsp_store| lsp_store.0.clone());
8349
8350 self.language_server_statuses = language_servers
8351 .into_iter()
8352 .zip(server_capabilities)
8353 .map(|(server, server_capabilities)| {
8354 let server_id = LanguageServerId(server.id as usize);
8355 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8356 self.lsp_server_capabilities
8357 .insert(server_id, server_capabilities);
8358 }
8359
8360 let name = LanguageServerName::from_proto(server.name);
8361 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8362
8363 if let Some(lsp_logs) = &lsp_logs {
8364 lsp_logs.update(cx, |lsp_logs, cx| {
8365 lsp_logs.add_language_server(
8366 // Only remote clients get their language servers set from proto
8367 LanguageServerKind::Remote {
8368 project: project.clone(),
8369 },
8370 server_id,
8371 Some(name.clone()),
8372 worktree,
8373 None,
8374 cx,
8375 );
8376 });
8377 }
8378
8379 (
8380 server_id,
8381 LanguageServerStatus {
8382 name,
8383 server_version: None,
8384 server_readable_version: None,
8385 pending_work: Default::default(),
8386 has_pending_diagnostic_updates: false,
8387 progress_tokens: Default::default(),
8388 worktree,
8389 binary: None,
8390 configuration: None,
8391 workspace_folders: BTreeSet::new(),
8392 process_id: None,
8393 },
8394 )
8395 })
8396 .collect();
8397 }
8398
8399 #[cfg(feature = "test-support")]
8400 pub fn update_diagnostic_entries(
8401 &mut self,
8402 server_id: LanguageServerId,
8403 abs_path: PathBuf,
8404 result_id: Option<SharedString>,
8405 version: Option<i32>,
8406 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8407 cx: &mut Context<Self>,
8408 ) -> anyhow::Result<()> {
8409 self.merge_diagnostic_entries(
8410 vec![DocumentDiagnosticsUpdate {
8411 diagnostics: DocumentDiagnostics {
8412 diagnostics,
8413 document_abs_path: abs_path,
8414 version,
8415 },
8416 result_id,
8417 server_id,
8418 disk_based_sources: Cow::Borrowed(&[]),
8419 registration_id: None,
8420 }],
8421 |_, _, _| false,
8422 cx,
8423 )?;
8424 Ok(())
8425 }
8426
8427 pub fn merge_diagnostic_entries<'a>(
8428 &mut self,
8429 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8430 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8431 cx: &mut Context<Self>,
8432 ) -> anyhow::Result<()> {
8433 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8434 let mut updated_diagnostics_paths = HashMap::default();
8435 for mut update in diagnostic_updates {
8436 let abs_path = &update.diagnostics.document_abs_path;
8437 let server_id = update.server_id;
8438 let Some((worktree, relative_path)) =
8439 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8440 else {
8441 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8442 return Ok(());
8443 };
8444
8445 let worktree_id = worktree.read(cx).id();
8446 let project_path = ProjectPath {
8447 worktree_id,
8448 path: relative_path,
8449 };
8450
8451 let document_uri = lsp::Uri::from_file_path(abs_path)
8452 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8453 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8454 let snapshot = buffer_handle.read(cx).snapshot();
8455 let buffer = buffer_handle.read(cx);
8456 let reused_diagnostics = buffer
8457 .buffer_diagnostics(Some(server_id))
8458 .iter()
8459 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8460 .map(|v| {
8461 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8462 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8463 DiagnosticEntry {
8464 range: start..end,
8465 diagnostic: v.diagnostic.clone(),
8466 }
8467 })
8468 .collect::<Vec<_>>();
8469
8470 self.as_local_mut()
8471 .context("cannot merge diagnostics on a remote LspStore")?
8472 .update_buffer_diagnostics(
8473 &buffer_handle,
8474 server_id,
8475 Some(update.registration_id),
8476 update.result_id,
8477 update.diagnostics.version,
8478 update.diagnostics.diagnostics.clone(),
8479 reused_diagnostics.clone(),
8480 cx,
8481 )?;
8482
8483 update.diagnostics.diagnostics.extend(reused_diagnostics);
8484 } else if let Some(local) = self.as_local() {
8485 let reused_diagnostics = local
8486 .diagnostics
8487 .get(&worktree_id)
8488 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8489 .and_then(|diagnostics_by_server_id| {
8490 diagnostics_by_server_id
8491 .binary_search_by_key(&server_id, |e| e.0)
8492 .ok()
8493 .map(|ix| &diagnostics_by_server_id[ix].1)
8494 })
8495 .into_iter()
8496 .flatten()
8497 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8498
8499 update
8500 .diagnostics
8501 .diagnostics
8502 .extend(reused_diagnostics.cloned());
8503 }
8504
8505 let updated = worktree.update(cx, |worktree, cx| {
8506 self.update_worktree_diagnostics(
8507 worktree.id(),
8508 server_id,
8509 project_path.path.clone(),
8510 update.diagnostics.diagnostics,
8511 cx,
8512 )
8513 })?;
8514 match updated {
8515 ControlFlow::Continue(new_summary) => {
8516 if let Some((project_id, new_summary)) = new_summary {
8517 match &mut diagnostics_summary {
8518 Some(diagnostics_summary) => {
8519 diagnostics_summary
8520 .more_summaries
8521 .push(proto::DiagnosticSummary {
8522 path: project_path.path.as_ref().to_proto(),
8523 language_server_id: server_id.0 as u64,
8524 error_count: new_summary.error_count,
8525 warning_count: new_summary.warning_count,
8526 })
8527 }
8528 None => {
8529 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8530 project_id,
8531 worktree_id: worktree_id.to_proto(),
8532 summary: Some(proto::DiagnosticSummary {
8533 path: project_path.path.as_ref().to_proto(),
8534 language_server_id: server_id.0 as u64,
8535 error_count: new_summary.error_count,
8536 warning_count: new_summary.warning_count,
8537 }),
8538 more_summaries: Vec::new(),
8539 })
8540 }
8541 }
8542 }
8543 updated_diagnostics_paths
8544 .entry(server_id)
8545 .or_insert_with(Vec::new)
8546 .push(project_path);
8547 }
8548 ControlFlow::Break(()) => {}
8549 }
8550 }
8551
8552 if let Some((diagnostics_summary, (downstream_client, _))) =
8553 diagnostics_summary.zip(self.downstream_client.as_ref())
8554 {
8555 downstream_client.send(diagnostics_summary).log_err();
8556 }
8557 for (server_id, paths) in updated_diagnostics_paths {
8558 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8559 }
8560 Ok(())
8561 }
8562
8563 fn update_worktree_diagnostics(
8564 &mut self,
8565 worktree_id: WorktreeId,
8566 server_id: LanguageServerId,
8567 path_in_worktree: Arc<RelPath>,
8568 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8569 _: &mut Context<Worktree>,
8570 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8571 let local = match &mut self.mode {
8572 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8573 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8574 };
8575
8576 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8577 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8578 let summaries_by_server_id = summaries_for_tree
8579 .entry(path_in_worktree.clone())
8580 .or_default();
8581
8582 let old_summary = summaries_by_server_id
8583 .remove(&server_id)
8584 .unwrap_or_default();
8585
8586 let new_summary = DiagnosticSummary::new(&diagnostics);
8587 if diagnostics.is_empty() {
8588 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8589 {
8590 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8591 diagnostics_by_server_id.remove(ix);
8592 }
8593 if diagnostics_by_server_id.is_empty() {
8594 diagnostics_for_tree.remove(&path_in_worktree);
8595 }
8596 }
8597 } else {
8598 summaries_by_server_id.insert(server_id, new_summary);
8599 let diagnostics_by_server_id = diagnostics_for_tree
8600 .entry(path_in_worktree.clone())
8601 .or_default();
8602 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8603 Ok(ix) => {
8604 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8605 }
8606 Err(ix) => {
8607 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8608 }
8609 }
8610 }
8611
8612 if !old_summary.is_empty() || !new_summary.is_empty() {
8613 if let Some((_, project_id)) = &self.downstream_client {
8614 Ok(ControlFlow::Continue(Some((
8615 *project_id,
8616 proto::DiagnosticSummary {
8617 path: path_in_worktree.to_proto(),
8618 language_server_id: server_id.0 as u64,
8619 error_count: new_summary.error_count as u32,
8620 warning_count: new_summary.warning_count as u32,
8621 },
8622 ))))
8623 } else {
8624 Ok(ControlFlow::Continue(None))
8625 }
8626 } else {
8627 Ok(ControlFlow::Break(()))
8628 }
8629 }
8630
8631 pub fn open_buffer_for_symbol(
8632 &mut self,
8633 symbol: &Symbol,
8634 cx: &mut Context<Self>,
8635 ) -> Task<Result<Entity<Buffer>>> {
8636 if let Some((client, project_id)) = self.upstream_client() {
8637 let request = client.request(proto::OpenBufferForSymbol {
8638 project_id,
8639 symbol: Some(Self::serialize_symbol(symbol)),
8640 });
8641 cx.spawn(async move |this, cx| {
8642 let response = request.await?;
8643 let buffer_id = BufferId::new(response.buffer_id)?;
8644 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8645 .await
8646 })
8647 } else if let Some(local) = self.as_local() {
8648 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8649 seed.worktree_id == symbol.source_worktree_id
8650 && state.id == symbol.source_language_server_id
8651 && symbol.language_server_name == seed.name
8652 });
8653 if !is_valid {
8654 return Task::ready(Err(anyhow!(
8655 "language server for worktree and language not found"
8656 )));
8657 };
8658
8659 let symbol_abs_path = match &symbol.path {
8660 SymbolLocation::InProject(project_path) => self
8661 .worktree_store
8662 .read(cx)
8663 .absolutize(&project_path, cx)
8664 .context("no such worktree"),
8665 SymbolLocation::OutsideProject {
8666 abs_path,
8667 signature: _,
8668 } => Ok(abs_path.to_path_buf()),
8669 };
8670 let symbol_abs_path = match symbol_abs_path {
8671 Ok(abs_path) => abs_path,
8672 Err(err) => return Task::ready(Err(err)),
8673 };
8674 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8675 uri
8676 } else {
8677 return Task::ready(Err(anyhow!("invalid symbol path")));
8678 };
8679
8680 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8681 } else {
8682 Task::ready(Err(anyhow!("no upstream client or local store")))
8683 }
8684 }
8685
8686 pub(crate) fn open_local_buffer_via_lsp(
8687 &mut self,
8688 abs_path: lsp::Uri,
8689 language_server_id: LanguageServerId,
8690 cx: &mut Context<Self>,
8691 ) -> Task<Result<Entity<Buffer>>> {
8692 let path_style = self.worktree_store.read(cx).path_style();
8693 cx.spawn(async move |lsp_store, cx| {
8694 // Escape percent-encoded string.
8695 let current_scheme = abs_path.scheme().to_owned();
8696 // Uri is immutable, so we can't modify the scheme
8697
8698 let abs_path = abs_path
8699 .to_file_path_ext(path_style)
8700 .map_err(|()| anyhow!("can't convert URI to path"))?;
8701 let p = abs_path.clone();
8702 let yarn_worktree = lsp_store
8703 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8704 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8705 cx.spawn(async move |this, cx| {
8706 let t = this
8707 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8708 .ok()?;
8709 t.await
8710 })
8711 }),
8712 None => Task::ready(None),
8713 })?
8714 .await;
8715 let (worktree_root_target, known_relative_path) =
8716 if let Some((zip_root, relative_path)) = yarn_worktree {
8717 (zip_root, Some(relative_path))
8718 } else {
8719 (Arc::<Path>::from(abs_path.as_path()), None)
8720 };
8721 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8722 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8723 worktree_store.find_worktree(&worktree_root_target, cx)
8724 })
8725 })?;
8726 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8727 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8728 (result.0, relative_path, None)
8729 } else {
8730 let worktree = lsp_store
8731 .update(cx, |lsp_store, cx| {
8732 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8733 worktree_store.create_worktree(&worktree_root_target, false, cx)
8734 })
8735 })?
8736 .await?;
8737 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8738 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8739 lsp_store
8740 .update(cx, |lsp_store, cx| {
8741 if let Some(local) = lsp_store.as_local_mut() {
8742 local.register_language_server_for_invisible_worktree(
8743 &worktree,
8744 language_server_id,
8745 cx,
8746 )
8747 }
8748 match lsp_store.language_server_statuses.get(&language_server_id) {
8749 Some(status) => status.worktree,
8750 None => None,
8751 }
8752 })
8753 .ok()
8754 .flatten()
8755 .zip(Some(worktree_root.clone()))
8756 } else {
8757 None
8758 };
8759 let relative_path = if let Some(known_path) = known_relative_path {
8760 known_path
8761 } else {
8762 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8763 .into_arc()
8764 };
8765 (worktree, relative_path, source_ws)
8766 };
8767 let project_path = ProjectPath {
8768 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8769 path: relative_path,
8770 };
8771 let buffer = lsp_store
8772 .update(cx, |lsp_store, cx| {
8773 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8774 buffer_store.open_buffer(project_path, cx)
8775 })
8776 })?
8777 .await?;
8778 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8779 if let Some((source_ws, worktree_root)) = source_ws {
8780 buffer.update(cx, |buffer, cx| {
8781 let settings = WorktreeSettings::get(
8782 Some(
8783 (&ProjectPath {
8784 worktree_id: source_ws,
8785 path: Arc::from(RelPath::empty()),
8786 })
8787 .into(),
8788 ),
8789 cx,
8790 );
8791 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8792 if is_read_only {
8793 buffer.set_capability(Capability::ReadOnly, cx);
8794 }
8795 });
8796 }
8797 Ok(buffer)
8798 })
8799 }
8800
8801 fn local_lsp_servers_for_buffer(
8802 &self,
8803 buffer: &Entity<Buffer>,
8804 cx: &mut Context<Self>,
8805 ) -> Vec<LanguageServerId> {
8806 let Some(local) = self.as_local() else {
8807 return Vec::new();
8808 };
8809
8810 let snapshot = buffer.read(cx).snapshot();
8811
8812 buffer.update(cx, |buffer, cx| {
8813 local
8814 .language_servers_for_buffer(buffer, cx)
8815 .map(|(_, server)| server.server_id())
8816 .filter(|server_id| {
8817 self.as_local().is_none_or(|local| {
8818 local
8819 .buffers_opened_in_servers
8820 .get(&snapshot.remote_id())
8821 .is_some_and(|servers| servers.contains(server_id))
8822 })
8823 })
8824 .collect()
8825 })
8826 }
8827
8828 fn request_multiple_lsp_locally<P, R>(
8829 &mut self,
8830 buffer: &Entity<Buffer>,
8831 position: Option<P>,
8832 request: R,
8833 cx: &mut Context<Self>,
8834 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8835 where
8836 P: ToOffset,
8837 R: LspCommand + Clone,
8838 <R::LspRequest as lsp::request::Request>::Result: Send,
8839 <R::LspRequest as lsp::request::Request>::Params: Send,
8840 {
8841 let Some(local) = self.as_local() else {
8842 return Task::ready(Vec::new());
8843 };
8844
8845 let snapshot = buffer.read(cx).snapshot();
8846 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8847
8848 let server_ids = buffer.update(cx, |buffer, cx| {
8849 local
8850 .language_servers_for_buffer(buffer, cx)
8851 .filter(|(adapter, _)| {
8852 scope
8853 .as_ref()
8854 .map(|scope| scope.language_allowed(&adapter.name))
8855 .unwrap_or(true)
8856 })
8857 .map(|(_, server)| server.server_id())
8858 .filter(|server_id| {
8859 self.as_local().is_none_or(|local| {
8860 local
8861 .buffers_opened_in_servers
8862 .get(&snapshot.remote_id())
8863 .is_some_and(|servers| servers.contains(server_id))
8864 })
8865 })
8866 .collect::<Vec<_>>()
8867 });
8868
8869 let mut response_results = server_ids
8870 .into_iter()
8871 .map(|server_id| {
8872 let task = self.request_lsp(
8873 buffer.clone(),
8874 LanguageServerToQuery::Other(server_id),
8875 request.clone(),
8876 cx,
8877 );
8878 async move { (server_id, task.await) }
8879 })
8880 .collect::<FuturesUnordered<_>>();
8881
8882 cx.background_spawn(async move {
8883 let mut responses = Vec::with_capacity(response_results.len());
8884 while let Some((server_id, response_result)) = response_results.next().await {
8885 match response_result {
8886 Ok(response) => responses.push((server_id, response)),
8887 // rust-analyzer likes to error with this when its still loading up
8888 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8889 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8890 }
8891 }
8892 responses
8893 })
8894 }
8895
8896 async fn handle_lsp_get_completions(
8897 this: Entity<Self>,
8898 envelope: TypedEnvelope<proto::GetCompletions>,
8899 mut cx: AsyncApp,
8900 ) -> Result<proto::GetCompletionsResponse> {
8901 let sender_id = envelope.original_sender_id().unwrap_or_default();
8902
8903 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8904 let buffer_handle = this.update(&mut cx, |this, cx| {
8905 this.buffer_store.read(cx).get_existing(buffer_id)
8906 })?;
8907 let request = GetCompletions::from_proto(
8908 envelope.payload,
8909 this.clone(),
8910 buffer_handle.clone(),
8911 cx.clone(),
8912 )
8913 .await?;
8914
8915 let server_to_query = match request.server_id {
8916 Some(server_id) => LanguageServerToQuery::Other(server_id),
8917 None => LanguageServerToQuery::FirstCapable,
8918 };
8919
8920 let response = this
8921 .update(&mut cx, |this, cx| {
8922 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8923 })
8924 .await?;
8925 this.update(&mut cx, |this, cx| {
8926 Ok(GetCompletions::response_to_proto(
8927 response,
8928 this,
8929 sender_id,
8930 &buffer_handle.read(cx).version(),
8931 cx,
8932 ))
8933 })
8934 }
8935
8936 async fn handle_lsp_command<T: LspCommand>(
8937 this: Entity<Self>,
8938 envelope: TypedEnvelope<T::ProtoRequest>,
8939 mut cx: AsyncApp,
8940 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8941 where
8942 <T::LspRequest as lsp::request::Request>::Params: Send,
8943 <T::LspRequest as lsp::request::Request>::Result: Send,
8944 {
8945 let sender_id = envelope.original_sender_id().unwrap_or_default();
8946 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8947 let buffer_handle = this.update(&mut cx, |this, cx| {
8948 this.buffer_store.read(cx).get_existing(buffer_id)
8949 })?;
8950 let request = T::from_proto(
8951 envelope.payload,
8952 this.clone(),
8953 buffer_handle.clone(),
8954 cx.clone(),
8955 )
8956 .await?;
8957 let response = this
8958 .update(&mut cx, |this, cx| {
8959 this.request_lsp(
8960 buffer_handle.clone(),
8961 LanguageServerToQuery::FirstCapable,
8962 request,
8963 cx,
8964 )
8965 })
8966 .await?;
8967 this.update(&mut cx, |this, cx| {
8968 Ok(T::response_to_proto(
8969 response,
8970 this,
8971 sender_id,
8972 &buffer_handle.read(cx).version(),
8973 cx,
8974 ))
8975 })
8976 }
8977
8978 async fn handle_lsp_query(
8979 lsp_store: Entity<Self>,
8980 envelope: TypedEnvelope<proto::LspQuery>,
8981 mut cx: AsyncApp,
8982 ) -> Result<proto::Ack> {
8983 use proto::lsp_query::Request;
8984 let sender_id = envelope.original_sender_id().unwrap_or_default();
8985 let lsp_query = envelope.payload;
8986 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8987 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8988 match lsp_query.request.context("invalid LSP query request")? {
8989 Request::GetReferences(get_references) => {
8990 let position = get_references.position.clone().and_then(deserialize_anchor);
8991 Self::query_lsp_locally::<GetReferences>(
8992 lsp_store,
8993 server_id,
8994 sender_id,
8995 lsp_request_id,
8996 get_references,
8997 position,
8998 &mut cx,
8999 )
9000 .await?;
9001 }
9002 Request::GetDocumentColor(get_document_color) => {
9003 Self::query_lsp_locally::<GetDocumentColor>(
9004 lsp_store,
9005 server_id,
9006 sender_id,
9007 lsp_request_id,
9008 get_document_color,
9009 None,
9010 &mut cx,
9011 )
9012 .await?;
9013 }
9014 Request::GetFoldingRanges(get_folding_ranges) => {
9015 Self::query_lsp_locally::<GetFoldingRanges>(
9016 lsp_store,
9017 server_id,
9018 sender_id,
9019 lsp_request_id,
9020 get_folding_ranges,
9021 None,
9022 &mut cx,
9023 )
9024 .await?;
9025 }
9026 Request::GetDocumentSymbols(get_document_symbols) => {
9027 Self::query_lsp_locally::<GetDocumentSymbols>(
9028 lsp_store,
9029 server_id,
9030 sender_id,
9031 lsp_request_id,
9032 get_document_symbols,
9033 None,
9034 &mut cx,
9035 )
9036 .await?;
9037 }
9038 Request::GetHover(get_hover) => {
9039 let position = get_hover.position.clone().and_then(deserialize_anchor);
9040 Self::query_lsp_locally::<GetHover>(
9041 lsp_store,
9042 server_id,
9043 sender_id,
9044 lsp_request_id,
9045 get_hover,
9046 position,
9047 &mut cx,
9048 )
9049 .await?;
9050 }
9051 Request::GetCodeActions(get_code_actions) => {
9052 Self::query_lsp_locally::<GetCodeActions>(
9053 lsp_store,
9054 server_id,
9055 sender_id,
9056 lsp_request_id,
9057 get_code_actions,
9058 None,
9059 &mut cx,
9060 )
9061 .await?;
9062 }
9063 Request::GetSignatureHelp(get_signature_help) => {
9064 let position = get_signature_help
9065 .position
9066 .clone()
9067 .and_then(deserialize_anchor);
9068 Self::query_lsp_locally::<GetSignatureHelp>(
9069 lsp_store,
9070 server_id,
9071 sender_id,
9072 lsp_request_id,
9073 get_signature_help,
9074 position,
9075 &mut cx,
9076 )
9077 .await?;
9078 }
9079 Request::GetCodeLens(get_code_lens) => {
9080 Self::query_lsp_locally::<GetCodeLens>(
9081 lsp_store,
9082 server_id,
9083 sender_id,
9084 lsp_request_id,
9085 get_code_lens,
9086 None,
9087 &mut cx,
9088 )
9089 .await?;
9090 }
9091 Request::GetDefinition(get_definition) => {
9092 let position = get_definition.position.clone().and_then(deserialize_anchor);
9093 Self::query_lsp_locally::<GetDefinitions>(
9094 lsp_store,
9095 server_id,
9096 sender_id,
9097 lsp_request_id,
9098 get_definition,
9099 position,
9100 &mut cx,
9101 )
9102 .await?;
9103 }
9104 Request::GetDeclaration(get_declaration) => {
9105 let position = get_declaration
9106 .position
9107 .clone()
9108 .and_then(deserialize_anchor);
9109 Self::query_lsp_locally::<GetDeclarations>(
9110 lsp_store,
9111 server_id,
9112 sender_id,
9113 lsp_request_id,
9114 get_declaration,
9115 position,
9116 &mut cx,
9117 )
9118 .await?;
9119 }
9120 Request::GetTypeDefinition(get_type_definition) => {
9121 let position = get_type_definition
9122 .position
9123 .clone()
9124 .and_then(deserialize_anchor);
9125 Self::query_lsp_locally::<GetTypeDefinitions>(
9126 lsp_store,
9127 server_id,
9128 sender_id,
9129 lsp_request_id,
9130 get_type_definition,
9131 position,
9132 &mut cx,
9133 )
9134 .await?;
9135 }
9136 Request::GetImplementation(get_implementation) => {
9137 let position = get_implementation
9138 .position
9139 .clone()
9140 .and_then(deserialize_anchor);
9141 Self::query_lsp_locally::<GetImplementations>(
9142 lsp_store,
9143 server_id,
9144 sender_id,
9145 lsp_request_id,
9146 get_implementation,
9147 position,
9148 &mut cx,
9149 )
9150 .await?;
9151 }
9152 Request::InlayHints(inlay_hints) => {
9153 let query_start = inlay_hints
9154 .start
9155 .clone()
9156 .and_then(deserialize_anchor)
9157 .context("invalid inlay hints range start")?;
9158 let query_end = inlay_hints
9159 .end
9160 .clone()
9161 .and_then(deserialize_anchor)
9162 .context("invalid inlay hints range end")?;
9163 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9164 &lsp_store,
9165 server_id,
9166 lsp_request_id,
9167 &inlay_hints,
9168 query_start..query_end,
9169 &mut cx,
9170 )
9171 .await
9172 .context("preparing inlay hints request")?;
9173 Self::query_lsp_locally::<InlayHints>(
9174 lsp_store,
9175 server_id,
9176 sender_id,
9177 lsp_request_id,
9178 inlay_hints,
9179 None,
9180 &mut cx,
9181 )
9182 .await
9183 .context("querying for inlay hints")?
9184 }
9185 //////////////////////////////
9186 // Below are LSP queries that need to fetch more data,
9187 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9188 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9189 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9190 &lsp_store,
9191 &get_document_diagnostics,
9192 &mut cx,
9193 )
9194 .await?;
9195 lsp_store.update(&mut cx, |lsp_store, cx| {
9196 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9197 let key = LspKey {
9198 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9199 server_queried: server_id,
9200 };
9201 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9202 ) {
9203 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9204 lsp_requests.clear();
9205 };
9206 }
9207
9208 lsp_data.lsp_requests.entry(key).or_default().insert(
9209 lsp_request_id,
9210 cx.spawn(async move |lsp_store, cx| {
9211 let diagnostics_pull = lsp_store
9212 .update(cx, |lsp_store, cx| {
9213 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9214 })
9215 .ok();
9216 if let Some(diagnostics_pull) = diagnostics_pull {
9217 match diagnostics_pull.await {
9218 Ok(()) => {}
9219 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9220 };
9221 }
9222 }),
9223 );
9224 });
9225 }
9226 Request::SemanticTokens(semantic_tokens) => {
9227 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9228 &lsp_store,
9229 &semantic_tokens,
9230 &mut cx,
9231 )
9232 .await?;
9233 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9234 lsp_store.update(&mut cx, |lsp_store, cx| {
9235 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9236 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9237 let key = LspKey {
9238 request_type: TypeId::of::<SemanticTokensFull>(),
9239 server_queried: server_id,
9240 };
9241 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9242 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9243 lsp_requests.clear();
9244 };
9245 }
9246
9247 lsp_data.lsp_requests.entry(key).or_default().insert(
9248 lsp_request_id,
9249 cx.spawn(async move |lsp_store, cx| {
9250 let tokens_fetch = lsp_store
9251 .update(cx, |lsp_store, cx| {
9252 lsp_store
9253 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9254 })
9255 .ok();
9256 if let Some(tokens_fetch) = tokens_fetch {
9257 let new_tokens = tokens_fetch.await;
9258 if let Some(new_tokens) = new_tokens {
9259 lsp_store
9260 .update(cx, |lsp_store, cx| {
9261 let response = new_tokens
9262 .into_iter()
9263 .map(|(server_id, response)| {
9264 (
9265 server_id.to_proto(),
9266 SemanticTokensFull::response_to_proto(
9267 response,
9268 lsp_store,
9269 sender_id,
9270 &buffer_version,
9271 cx,
9272 ),
9273 )
9274 })
9275 .collect::<HashMap<_, _>>();
9276 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9277 project_id,
9278 lsp_request_id,
9279 response,
9280 ) {
9281 Ok(()) => {}
9282 Err(e) => {
9283 log::error!(
9284 "Failed to send semantic tokens LSP response: {e:#}",
9285 )
9286 }
9287 }
9288 })
9289 .ok();
9290 }
9291 }
9292 }),
9293 );
9294 }
9295 });
9296 }
9297 }
9298 Ok(proto::Ack {})
9299 }
9300
9301 async fn handle_lsp_query_response(
9302 lsp_store: Entity<Self>,
9303 envelope: TypedEnvelope<proto::LspQueryResponse>,
9304 cx: AsyncApp,
9305 ) -> Result<()> {
9306 lsp_store.read_with(&cx, |lsp_store, _| {
9307 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9308 upstream_client.handle_lsp_response(envelope.clone());
9309 }
9310 });
9311 Ok(())
9312 }
9313
9314 async fn handle_apply_code_action(
9315 this: Entity<Self>,
9316 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9317 mut cx: AsyncApp,
9318 ) -> Result<proto::ApplyCodeActionResponse> {
9319 let sender_id = envelope.original_sender_id().unwrap_or_default();
9320 let action =
9321 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9322 let apply_code_action = this.update(&mut cx, |this, cx| {
9323 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9324 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9325 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9326 })?;
9327
9328 let project_transaction = apply_code_action.await?;
9329 let project_transaction = this.update(&mut cx, |this, cx| {
9330 this.buffer_store.update(cx, |buffer_store, cx| {
9331 buffer_store.serialize_project_transaction_for_peer(
9332 project_transaction,
9333 sender_id,
9334 cx,
9335 )
9336 })
9337 });
9338 Ok(proto::ApplyCodeActionResponse {
9339 transaction: Some(project_transaction),
9340 })
9341 }
9342
9343 async fn handle_register_buffer_with_language_servers(
9344 this: Entity<Self>,
9345 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9346 mut cx: AsyncApp,
9347 ) -> Result<proto::Ack> {
9348 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9349 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9350 this.update(&mut cx, |this, cx| {
9351 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9352 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9353 project_id: upstream_project_id,
9354 buffer_id: buffer_id.to_proto(),
9355 only_servers: envelope.payload.only_servers,
9356 });
9357 }
9358
9359 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9360 anyhow::bail!("buffer is not open");
9361 };
9362
9363 let handle = this.register_buffer_with_language_servers(
9364 &buffer,
9365 envelope
9366 .payload
9367 .only_servers
9368 .into_iter()
9369 .filter_map(|selector| {
9370 Some(match selector.selector? {
9371 proto::language_server_selector::Selector::ServerId(server_id) => {
9372 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9373 }
9374 proto::language_server_selector::Selector::Name(name) => {
9375 LanguageServerSelector::Name(LanguageServerName(
9376 SharedString::from(name),
9377 ))
9378 }
9379 })
9380 })
9381 .collect(),
9382 false,
9383 cx,
9384 );
9385 // Pull diagnostics for the buffer even if it was already registered.
9386 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9387 // but it's unclear if we need it.
9388 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9389 .detach();
9390 this.buffer_store().update(cx, |buffer_store, _| {
9391 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9392 });
9393
9394 Ok(())
9395 })?;
9396 Ok(proto::Ack {})
9397 }
9398
9399 async fn handle_rename_project_entry(
9400 this: Entity<Self>,
9401 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9402 mut cx: AsyncApp,
9403 ) -> Result<proto::ProjectEntryResponse> {
9404 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9405 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9406 let new_path =
9407 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9408
9409 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9410 .update(&mut cx, |this, cx| {
9411 let (worktree, entry) = this
9412 .worktree_store
9413 .read(cx)
9414 .worktree_and_entry_for_id(entry_id, cx)?;
9415 let new_worktree = this
9416 .worktree_store
9417 .read(cx)
9418 .worktree_for_id(new_worktree_id, cx)?;
9419 Some((
9420 this.worktree_store.clone(),
9421 worktree,
9422 new_worktree,
9423 entry.clone(),
9424 ))
9425 })
9426 .context("worktree not found")?;
9427 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9428 (worktree.absolutize(&old_entry.path), worktree.id())
9429 });
9430 let new_abs_path =
9431 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9432
9433 let _transaction = Self::will_rename_entry(
9434 this.downgrade(),
9435 old_worktree_id,
9436 &old_abs_path,
9437 &new_abs_path,
9438 old_entry.is_dir(),
9439 cx.clone(),
9440 )
9441 .await;
9442 let response = WorktreeStore::handle_rename_project_entry(
9443 worktree_store,
9444 envelope.payload,
9445 cx.clone(),
9446 )
9447 .await;
9448 this.read_with(&cx, |this, _| {
9449 this.did_rename_entry(
9450 old_worktree_id,
9451 &old_abs_path,
9452 &new_abs_path,
9453 old_entry.is_dir(),
9454 );
9455 });
9456 response
9457 }
9458
9459 async fn handle_update_diagnostic_summary(
9460 this: Entity<Self>,
9461 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9462 mut cx: AsyncApp,
9463 ) -> Result<()> {
9464 this.update(&mut cx, |lsp_store, cx| {
9465 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9466 let mut updated_diagnostics_paths = HashMap::default();
9467 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9468 for message_summary in envelope
9469 .payload
9470 .summary
9471 .into_iter()
9472 .chain(envelope.payload.more_summaries)
9473 {
9474 let project_path = ProjectPath {
9475 worktree_id,
9476 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9477 };
9478 let path = project_path.path.clone();
9479 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9480 let summary = DiagnosticSummary {
9481 error_count: message_summary.error_count as usize,
9482 warning_count: message_summary.warning_count as usize,
9483 };
9484
9485 if summary.is_empty() {
9486 if let Some(worktree_summaries) =
9487 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9488 && let Some(summaries) = worktree_summaries.get_mut(&path)
9489 {
9490 summaries.remove(&server_id);
9491 if summaries.is_empty() {
9492 worktree_summaries.remove(&path);
9493 }
9494 }
9495 } else {
9496 lsp_store
9497 .diagnostic_summaries
9498 .entry(worktree_id)
9499 .or_default()
9500 .entry(path)
9501 .or_default()
9502 .insert(server_id, summary);
9503 }
9504
9505 if let Some((_, project_id)) = &lsp_store.downstream_client {
9506 match &mut diagnostics_summary {
9507 Some(diagnostics_summary) => {
9508 diagnostics_summary
9509 .more_summaries
9510 .push(proto::DiagnosticSummary {
9511 path: project_path.path.as_ref().to_proto(),
9512 language_server_id: server_id.0 as u64,
9513 error_count: summary.error_count as u32,
9514 warning_count: summary.warning_count as u32,
9515 })
9516 }
9517 None => {
9518 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9519 project_id: *project_id,
9520 worktree_id: worktree_id.to_proto(),
9521 summary: Some(proto::DiagnosticSummary {
9522 path: project_path.path.as_ref().to_proto(),
9523 language_server_id: server_id.0 as u64,
9524 error_count: summary.error_count as u32,
9525 warning_count: summary.warning_count as u32,
9526 }),
9527 more_summaries: Vec::new(),
9528 })
9529 }
9530 }
9531 }
9532 updated_diagnostics_paths
9533 .entry(server_id)
9534 .or_insert_with(Vec::new)
9535 .push(project_path);
9536 }
9537
9538 if let Some((diagnostics_summary, (downstream_client, _))) =
9539 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9540 {
9541 downstream_client.send(diagnostics_summary).log_err();
9542 }
9543 for (server_id, paths) in updated_diagnostics_paths {
9544 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9545 }
9546 Ok(())
9547 })
9548 }
9549
9550 async fn handle_start_language_server(
9551 lsp_store: Entity<Self>,
9552 envelope: TypedEnvelope<proto::StartLanguageServer>,
9553 mut cx: AsyncApp,
9554 ) -> Result<()> {
9555 let server = envelope.payload.server.context("invalid server")?;
9556 let server_capabilities =
9557 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9558 .with_context(|| {
9559 format!(
9560 "incorrect server capabilities {}",
9561 envelope.payload.capabilities
9562 )
9563 })?;
9564 lsp_store.update(&mut cx, |lsp_store, cx| {
9565 let server_id = LanguageServerId(server.id as usize);
9566 let server_name = LanguageServerName::from_proto(server.name.clone());
9567 lsp_store
9568 .lsp_server_capabilities
9569 .insert(server_id, server_capabilities);
9570 lsp_store.language_server_statuses.insert(
9571 server_id,
9572 LanguageServerStatus {
9573 name: server_name.clone(),
9574 server_version: None,
9575 server_readable_version: None,
9576 pending_work: Default::default(),
9577 has_pending_diagnostic_updates: false,
9578 progress_tokens: Default::default(),
9579 worktree: server.worktree_id.map(WorktreeId::from_proto),
9580 binary: None,
9581 configuration: None,
9582 workspace_folders: BTreeSet::new(),
9583 process_id: None,
9584 },
9585 );
9586 cx.emit(LspStoreEvent::LanguageServerAdded(
9587 server_id,
9588 server_name,
9589 server.worktree_id.map(WorktreeId::from_proto),
9590 ));
9591 cx.notify();
9592 });
9593 Ok(())
9594 }
9595
9596 async fn handle_update_language_server(
9597 lsp_store: Entity<Self>,
9598 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9599 mut cx: AsyncApp,
9600 ) -> Result<()> {
9601 lsp_store.update(&mut cx, |lsp_store, cx| {
9602 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9603
9604 match envelope.payload.variant.context("invalid variant")? {
9605 proto::update_language_server::Variant::WorkStart(payload) => {
9606 lsp_store.on_lsp_work_start(
9607 language_server_id,
9608 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9609 .context("invalid progress token value")?,
9610 LanguageServerProgress {
9611 title: payload.title,
9612 is_disk_based_diagnostics_progress: false,
9613 is_cancellable: payload.is_cancellable.unwrap_or(false),
9614 message: payload.message,
9615 percentage: payload.percentage.map(|p| p as usize),
9616 last_update_at: cx.background_executor().now(),
9617 },
9618 cx,
9619 );
9620 }
9621 proto::update_language_server::Variant::WorkProgress(payload) => {
9622 lsp_store.on_lsp_work_progress(
9623 language_server_id,
9624 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9625 .context("invalid progress token value")?,
9626 LanguageServerProgress {
9627 title: None,
9628 is_disk_based_diagnostics_progress: false,
9629 is_cancellable: payload.is_cancellable.unwrap_or(false),
9630 message: payload.message,
9631 percentage: payload.percentage.map(|p| p as usize),
9632 last_update_at: cx.background_executor().now(),
9633 },
9634 cx,
9635 );
9636 }
9637
9638 proto::update_language_server::Variant::WorkEnd(payload) => {
9639 lsp_store.on_lsp_work_end(
9640 language_server_id,
9641 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9642 .context("invalid progress token value")?,
9643 cx,
9644 );
9645 }
9646
9647 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9648 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9649 }
9650
9651 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9652 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9653 }
9654
9655 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9656 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9657 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9658 cx.emit(LspStoreEvent::LanguageServerUpdate {
9659 language_server_id,
9660 name: envelope
9661 .payload
9662 .server_name
9663 .map(SharedString::new)
9664 .map(LanguageServerName),
9665 message: non_lsp,
9666 });
9667 }
9668 }
9669
9670 Ok(())
9671 })
9672 }
9673
9674 async fn handle_language_server_log(
9675 this: Entity<Self>,
9676 envelope: TypedEnvelope<proto::LanguageServerLog>,
9677 mut cx: AsyncApp,
9678 ) -> Result<()> {
9679 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9680 let log_type = envelope
9681 .payload
9682 .log_type
9683 .map(LanguageServerLogType::from_proto)
9684 .context("invalid language server log type")?;
9685
9686 let message = envelope.payload.message;
9687
9688 this.update(&mut cx, |_, cx| {
9689 cx.emit(LspStoreEvent::LanguageServerLog(
9690 language_server_id,
9691 log_type,
9692 message,
9693 ));
9694 });
9695 Ok(())
9696 }
9697
9698 async fn handle_lsp_ext_cancel_flycheck(
9699 lsp_store: Entity<Self>,
9700 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9701 cx: AsyncApp,
9702 ) -> Result<proto::Ack> {
9703 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9704 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9705 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9706 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9707 } else {
9708 None
9709 }
9710 });
9711 if let Some(task) = task {
9712 task.context("handling lsp ext cancel flycheck")?;
9713 }
9714
9715 Ok(proto::Ack {})
9716 }
9717
9718 async fn handle_lsp_ext_run_flycheck(
9719 lsp_store: Entity<Self>,
9720 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9721 mut cx: AsyncApp,
9722 ) -> Result<proto::Ack> {
9723 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9724 lsp_store.update(&mut cx, |lsp_store, cx| {
9725 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9726 let text_document = if envelope.payload.current_file_only {
9727 let buffer_id = envelope
9728 .payload
9729 .buffer_id
9730 .map(|id| BufferId::new(id))
9731 .transpose()?;
9732 buffer_id
9733 .and_then(|buffer_id| {
9734 lsp_store
9735 .buffer_store()
9736 .read(cx)
9737 .get(buffer_id)
9738 .and_then(|buffer| {
9739 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9740 })
9741 .map(|path| make_text_document_identifier(&path))
9742 })
9743 .transpose()?
9744 } else {
9745 None
9746 };
9747 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9748 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9749 )?;
9750 }
9751 anyhow::Ok(())
9752 })?;
9753
9754 Ok(proto::Ack {})
9755 }
9756
9757 async fn handle_lsp_ext_clear_flycheck(
9758 lsp_store: Entity<Self>,
9759 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9760 cx: AsyncApp,
9761 ) -> Result<proto::Ack> {
9762 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9763 lsp_store.read_with(&cx, |lsp_store, _| {
9764 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9765 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9766 } else {
9767 None
9768 }
9769 });
9770
9771 Ok(proto::Ack {})
9772 }
9773
9774 pub fn disk_based_diagnostics_started(
9775 &mut self,
9776 language_server_id: LanguageServerId,
9777 cx: &mut Context<Self>,
9778 ) {
9779 if let Some(language_server_status) =
9780 self.language_server_statuses.get_mut(&language_server_id)
9781 {
9782 language_server_status.has_pending_diagnostic_updates = true;
9783 }
9784
9785 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9786 cx.emit(LspStoreEvent::LanguageServerUpdate {
9787 language_server_id,
9788 name: self
9789 .language_server_adapter_for_id(language_server_id)
9790 .map(|adapter| adapter.name()),
9791 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9792 Default::default(),
9793 ),
9794 })
9795 }
9796
9797 pub fn disk_based_diagnostics_finished(
9798 &mut self,
9799 language_server_id: LanguageServerId,
9800 cx: &mut Context<Self>,
9801 ) {
9802 if let Some(language_server_status) =
9803 self.language_server_statuses.get_mut(&language_server_id)
9804 {
9805 language_server_status.has_pending_diagnostic_updates = false;
9806 }
9807
9808 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9809 cx.emit(LspStoreEvent::LanguageServerUpdate {
9810 language_server_id,
9811 name: self
9812 .language_server_adapter_for_id(language_server_id)
9813 .map(|adapter| adapter.name()),
9814 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9815 Default::default(),
9816 ),
9817 })
9818 }
9819
9820 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9821 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9822 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9823 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9824 // the language server might take some time to publish diagnostics.
9825 fn simulate_disk_based_diagnostics_events_if_needed(
9826 &mut self,
9827 language_server_id: LanguageServerId,
9828 cx: &mut Context<Self>,
9829 ) {
9830 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9831
9832 let Some(LanguageServerState::Running {
9833 simulate_disk_based_diagnostics_completion,
9834 adapter,
9835 ..
9836 }) = self
9837 .as_local_mut()
9838 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9839 else {
9840 return;
9841 };
9842
9843 if adapter.disk_based_diagnostics_progress_token.is_some() {
9844 return;
9845 }
9846
9847 let prev_task =
9848 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9849 cx.background_executor()
9850 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9851 .await;
9852
9853 this.update(cx, |this, cx| {
9854 this.disk_based_diagnostics_finished(language_server_id, cx);
9855
9856 if let Some(LanguageServerState::Running {
9857 simulate_disk_based_diagnostics_completion,
9858 ..
9859 }) = this.as_local_mut().and_then(|local_store| {
9860 local_store.language_servers.get_mut(&language_server_id)
9861 }) {
9862 *simulate_disk_based_diagnostics_completion = None;
9863 }
9864 })
9865 .ok();
9866 }));
9867
9868 if prev_task.is_none() {
9869 self.disk_based_diagnostics_started(language_server_id, cx);
9870 }
9871 }
9872
9873 pub fn language_server_statuses(
9874 &self,
9875 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9876 self.language_server_statuses
9877 .iter()
9878 .map(|(key, value)| (*key, value))
9879 }
9880
9881 pub(super) fn did_rename_entry(
9882 &self,
9883 worktree_id: WorktreeId,
9884 old_path: &Path,
9885 new_path: &Path,
9886 is_dir: bool,
9887 ) {
9888 maybe!({
9889 let local_store = self.as_local()?;
9890
9891 let old_uri = lsp::Uri::from_file_path(old_path)
9892 .ok()
9893 .map(|uri| uri.to_string())?;
9894 let new_uri = lsp::Uri::from_file_path(new_path)
9895 .ok()
9896 .map(|uri| uri.to_string())?;
9897
9898 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9899 let Some(filter) = local_store
9900 .language_server_paths_watched_for_rename
9901 .get(&language_server.server_id())
9902 else {
9903 continue;
9904 };
9905
9906 if filter.should_send_did_rename(&old_uri, is_dir) {
9907 language_server
9908 .notify::<DidRenameFiles>(RenameFilesParams {
9909 files: vec![FileRename {
9910 old_uri: old_uri.clone(),
9911 new_uri: new_uri.clone(),
9912 }],
9913 })
9914 .ok();
9915 }
9916 }
9917 Some(())
9918 });
9919 }
9920
9921 pub(super) fn will_rename_entry(
9922 this: WeakEntity<Self>,
9923 worktree_id: WorktreeId,
9924 old_path: &Path,
9925 new_path: &Path,
9926 is_dir: bool,
9927 cx: AsyncApp,
9928 ) -> Task<ProjectTransaction> {
9929 let old_uri = lsp::Uri::from_file_path(old_path)
9930 .ok()
9931 .map(|uri| uri.to_string());
9932 let new_uri = lsp::Uri::from_file_path(new_path)
9933 .ok()
9934 .map(|uri| uri.to_string());
9935 cx.spawn(async move |cx| {
9936 let mut tasks = vec![];
9937 this.update(cx, |this, cx| {
9938 let local_store = this.as_local()?;
9939 let old_uri = old_uri?;
9940 let new_uri = new_uri?;
9941 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9942 let Some(filter) = local_store
9943 .language_server_paths_watched_for_rename
9944 .get(&language_server.server_id())
9945 else {
9946 continue;
9947 };
9948
9949 if !filter.should_send_will_rename(&old_uri, is_dir) {
9950 continue;
9951 }
9952 let request_timeout = ProjectSettings::get_global(cx)
9953 .global_lsp_settings
9954 .get_request_timeout();
9955
9956 let apply_edit = cx.spawn({
9957 let old_uri = old_uri.clone();
9958 let new_uri = new_uri.clone();
9959 let language_server = language_server.clone();
9960 async move |this, cx| {
9961 let edit = language_server
9962 .request::<WillRenameFiles>(
9963 RenameFilesParams {
9964 files: vec![FileRename { old_uri, new_uri }],
9965 },
9966 request_timeout,
9967 )
9968 .await
9969 .into_response()
9970 .context("will rename files")
9971 .log_err()
9972 .flatten()?;
9973
9974 LocalLspStore::deserialize_workspace_edit(
9975 this.upgrade()?,
9976 edit,
9977 false,
9978 language_server.clone(),
9979 cx,
9980 )
9981 .await
9982 .ok()
9983 }
9984 });
9985 tasks.push(apply_edit);
9986 }
9987 Some(())
9988 })
9989 .ok()
9990 .flatten();
9991 let mut merged_transaction = ProjectTransaction::default();
9992 for task in tasks {
9993 // Await on tasks sequentially so that the order of application of edits is deterministic
9994 // (at least with regards to the order of registration of language servers)
9995 if let Some(transaction) = task.await {
9996 for (buffer, buffer_transaction) in transaction.0 {
9997 merged_transaction.0.insert(buffer, buffer_transaction);
9998 }
9999 }
10000 }
10001 merged_transaction
10002 })
10003 }
10004
10005 fn lsp_notify_abs_paths_changed(
10006 &mut self,
10007 server_id: LanguageServerId,
10008 changes: Vec<PathEvent>,
10009 ) {
10010 maybe!({
10011 let server = self.language_server_for_id(server_id)?;
10012 let changes = changes
10013 .into_iter()
10014 .filter_map(|event| {
10015 let typ = match event.kind? {
10016 PathEventKind::Created => lsp::FileChangeType::CREATED,
10017 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10018 PathEventKind::Changed | PathEventKind::Rescan => {
10019 lsp::FileChangeType::CHANGED
10020 }
10021 };
10022 Some(lsp::FileEvent {
10023 uri: file_path_to_lsp_url(&event.path).log_err()?,
10024 typ,
10025 })
10026 })
10027 .collect::<Vec<_>>();
10028 if !changes.is_empty() {
10029 server
10030 .notify::<lsp::notification::DidChangeWatchedFiles>(
10031 lsp::DidChangeWatchedFilesParams { changes },
10032 )
10033 .ok();
10034 }
10035 Some(())
10036 });
10037 }
10038
10039 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10040 self.as_local()?.language_server_for_id(id)
10041 }
10042
10043 fn on_lsp_progress(
10044 &mut self,
10045 progress_params: lsp::ProgressParams,
10046 language_server_id: LanguageServerId,
10047 disk_based_diagnostics_progress_token: Option<String>,
10048 cx: &mut Context<Self>,
10049 ) {
10050 match progress_params.value {
10051 lsp::ProgressParamsValue::WorkDone(progress) => {
10052 self.handle_work_done_progress(
10053 progress,
10054 language_server_id,
10055 disk_based_diagnostics_progress_token,
10056 ProgressToken::from_lsp(progress_params.token),
10057 cx,
10058 );
10059 }
10060 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10061 let registration_id = match progress_params.token {
10062 lsp::NumberOrString::Number(_) => None,
10063 lsp::NumberOrString::String(token) => token
10064 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10065 .map(|(_, id)| id.to_owned()),
10066 };
10067 if let Some(LanguageServerState::Running {
10068 workspace_diagnostics_refresh_tasks,
10069 ..
10070 }) = self
10071 .as_local_mut()
10072 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10073 && let Some(workspace_diagnostics) =
10074 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10075 {
10076 workspace_diagnostics.progress_tx.try_send(()).ok();
10077 self.apply_workspace_diagnostic_report(
10078 language_server_id,
10079 report,
10080 registration_id.map(SharedString::from),
10081 cx,
10082 )
10083 }
10084 }
10085 }
10086 }
10087
10088 fn handle_work_done_progress(
10089 &mut self,
10090 progress: lsp::WorkDoneProgress,
10091 language_server_id: LanguageServerId,
10092 disk_based_diagnostics_progress_token: Option<String>,
10093 token: ProgressToken,
10094 cx: &mut Context<Self>,
10095 ) {
10096 let language_server_status =
10097 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10098 status
10099 } else {
10100 return;
10101 };
10102
10103 if !language_server_status.progress_tokens.contains(&token) {
10104 return;
10105 }
10106
10107 let is_disk_based_diagnostics_progress =
10108 if let (Some(disk_based_token), ProgressToken::String(token)) =
10109 (&disk_based_diagnostics_progress_token, &token)
10110 {
10111 token.starts_with(disk_based_token)
10112 } else {
10113 false
10114 };
10115
10116 match progress {
10117 lsp::WorkDoneProgress::Begin(report) => {
10118 if is_disk_based_diagnostics_progress {
10119 self.disk_based_diagnostics_started(language_server_id, cx);
10120 }
10121 self.on_lsp_work_start(
10122 language_server_id,
10123 token.clone(),
10124 LanguageServerProgress {
10125 title: Some(report.title),
10126 is_disk_based_diagnostics_progress,
10127 is_cancellable: report.cancellable.unwrap_or(false),
10128 message: report.message.clone(),
10129 percentage: report.percentage.map(|p| p as usize),
10130 last_update_at: cx.background_executor().now(),
10131 },
10132 cx,
10133 );
10134 }
10135 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10136 language_server_id,
10137 token,
10138 LanguageServerProgress {
10139 title: None,
10140 is_disk_based_diagnostics_progress,
10141 is_cancellable: report.cancellable.unwrap_or(false),
10142 message: report.message,
10143 percentage: report.percentage.map(|p| p as usize),
10144 last_update_at: cx.background_executor().now(),
10145 },
10146 cx,
10147 ),
10148 lsp::WorkDoneProgress::End(_) => {
10149 language_server_status.progress_tokens.remove(&token);
10150 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10151 if is_disk_based_diagnostics_progress {
10152 self.disk_based_diagnostics_finished(language_server_id, cx);
10153 }
10154 }
10155 }
10156 }
10157
10158 fn on_lsp_work_start(
10159 &mut self,
10160 language_server_id: LanguageServerId,
10161 token: ProgressToken,
10162 progress: LanguageServerProgress,
10163 cx: &mut Context<Self>,
10164 ) {
10165 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10166 status.pending_work.insert(token.clone(), progress.clone());
10167 cx.notify();
10168 }
10169 cx.emit(LspStoreEvent::LanguageServerUpdate {
10170 language_server_id,
10171 name: self
10172 .language_server_adapter_for_id(language_server_id)
10173 .map(|adapter| adapter.name()),
10174 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10175 token: Some(token.to_proto()),
10176 title: progress.title,
10177 message: progress.message,
10178 percentage: progress.percentage.map(|p| p as u32),
10179 is_cancellable: Some(progress.is_cancellable),
10180 }),
10181 })
10182 }
10183
10184 fn on_lsp_work_progress(
10185 &mut self,
10186 language_server_id: LanguageServerId,
10187 token: ProgressToken,
10188 progress: LanguageServerProgress,
10189 cx: &mut Context<Self>,
10190 ) {
10191 let mut did_update = false;
10192 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10193 match status.pending_work.entry(token.clone()) {
10194 btree_map::Entry::Vacant(entry) => {
10195 entry.insert(progress.clone());
10196 did_update = true;
10197 }
10198 btree_map::Entry::Occupied(mut entry) => {
10199 let entry = entry.get_mut();
10200 if (progress.last_update_at - entry.last_update_at)
10201 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10202 {
10203 entry.last_update_at = progress.last_update_at;
10204 if progress.message.is_some() {
10205 entry.message = progress.message.clone();
10206 }
10207 if progress.percentage.is_some() {
10208 entry.percentage = progress.percentage;
10209 }
10210 if progress.is_cancellable != entry.is_cancellable {
10211 entry.is_cancellable = progress.is_cancellable;
10212 }
10213 did_update = true;
10214 }
10215 }
10216 }
10217 }
10218
10219 if did_update {
10220 cx.emit(LspStoreEvent::LanguageServerUpdate {
10221 language_server_id,
10222 name: self
10223 .language_server_adapter_for_id(language_server_id)
10224 .map(|adapter| adapter.name()),
10225 message: proto::update_language_server::Variant::WorkProgress(
10226 proto::LspWorkProgress {
10227 token: Some(token.to_proto()),
10228 message: progress.message,
10229 percentage: progress.percentage.map(|p| p as u32),
10230 is_cancellable: Some(progress.is_cancellable),
10231 },
10232 ),
10233 })
10234 }
10235 }
10236
10237 fn on_lsp_work_end(
10238 &mut self,
10239 language_server_id: LanguageServerId,
10240 token: ProgressToken,
10241 cx: &mut Context<Self>,
10242 ) {
10243 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10244 if let Some(work) = status.pending_work.remove(&token)
10245 && !work.is_disk_based_diagnostics_progress
10246 {
10247 cx.emit(LspStoreEvent::RefreshInlayHints {
10248 server_id: language_server_id,
10249 request_id: None,
10250 });
10251 }
10252 cx.notify();
10253 }
10254
10255 cx.emit(LspStoreEvent::LanguageServerUpdate {
10256 language_server_id,
10257 name: self
10258 .language_server_adapter_for_id(language_server_id)
10259 .map(|adapter| adapter.name()),
10260 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10261 token: Some(token.to_proto()),
10262 }),
10263 })
10264 }
10265
10266 pub async fn handle_resolve_completion_documentation(
10267 this: Entity<Self>,
10268 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10269 mut cx: AsyncApp,
10270 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10271 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10272
10273 let completion = this
10274 .read_with(&cx, |this, cx| {
10275 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10276 let server = this
10277 .language_server_for_id(id)
10278 .with_context(|| format!("No language server {id}"))?;
10279
10280 let request_timeout = ProjectSettings::get_global(cx)
10281 .global_lsp_settings
10282 .get_request_timeout();
10283
10284 anyhow::Ok(cx.background_spawn(async move {
10285 let can_resolve = server
10286 .capabilities()
10287 .completion_provider
10288 .as_ref()
10289 .and_then(|options| options.resolve_provider)
10290 .unwrap_or(false);
10291 if can_resolve {
10292 server
10293 .request::<lsp::request::ResolveCompletionItem>(
10294 lsp_completion,
10295 request_timeout,
10296 )
10297 .await
10298 .into_response()
10299 .context("resolve completion item")
10300 } else {
10301 anyhow::Ok(lsp_completion)
10302 }
10303 }))
10304 })?
10305 .await?;
10306
10307 let mut documentation_is_markdown = false;
10308 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10309 let documentation = match completion.documentation {
10310 Some(lsp::Documentation::String(text)) => text,
10311
10312 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10313 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10314 value
10315 }
10316
10317 _ => String::new(),
10318 };
10319
10320 // If we have a new buffer_id, that means we're talking to a new client
10321 // and want to check for new text_edits in the completion too.
10322 let mut old_replace_start = None;
10323 let mut old_replace_end = None;
10324 let mut old_insert_start = None;
10325 let mut old_insert_end = None;
10326 let mut new_text = String::default();
10327 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10328 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10329 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10330 anyhow::Ok(buffer.read(cx).snapshot())
10331 })?;
10332
10333 if let Some(text_edit) = completion.text_edit.as_ref() {
10334 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10335
10336 if let Some(mut edit) = edit {
10337 LineEnding::normalize(&mut edit.new_text);
10338
10339 new_text = edit.new_text;
10340 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10341 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10342 if let Some(insert_range) = edit.insert_range {
10343 old_insert_start = Some(serialize_anchor(&insert_range.start));
10344 old_insert_end = Some(serialize_anchor(&insert_range.end));
10345 }
10346 }
10347 }
10348 }
10349
10350 Ok(proto::ResolveCompletionDocumentationResponse {
10351 documentation,
10352 documentation_is_markdown,
10353 old_replace_start,
10354 old_replace_end,
10355 new_text,
10356 lsp_completion,
10357 old_insert_start,
10358 old_insert_end,
10359 })
10360 }
10361
10362 async fn handle_on_type_formatting(
10363 this: Entity<Self>,
10364 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10365 mut cx: AsyncApp,
10366 ) -> Result<proto::OnTypeFormattingResponse> {
10367 let on_type_formatting = this.update(&mut cx, |this, cx| {
10368 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10369 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10370 let position = envelope
10371 .payload
10372 .position
10373 .and_then(deserialize_anchor)
10374 .context("invalid position")?;
10375 anyhow::Ok(this.apply_on_type_formatting(
10376 buffer,
10377 position,
10378 envelope.payload.trigger.clone(),
10379 cx,
10380 ))
10381 })?;
10382
10383 let transaction = on_type_formatting
10384 .await?
10385 .as_ref()
10386 .map(language::proto::serialize_transaction);
10387 Ok(proto::OnTypeFormattingResponse { transaction })
10388 }
10389
10390 async fn handle_pull_workspace_diagnostics(
10391 lsp_store: Entity<Self>,
10392 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10393 mut cx: AsyncApp,
10394 ) -> Result<proto::Ack> {
10395 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10396 lsp_store.update(&mut cx, |lsp_store, _| {
10397 lsp_store.pull_workspace_diagnostics(server_id);
10398 });
10399 Ok(proto::Ack {})
10400 }
10401
10402 async fn handle_open_buffer_for_symbol(
10403 this: Entity<Self>,
10404 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10405 mut cx: AsyncApp,
10406 ) -> Result<proto::OpenBufferForSymbolResponse> {
10407 let peer_id = envelope.original_sender_id().unwrap_or_default();
10408 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10409 let symbol = Self::deserialize_symbol(symbol)?;
10410 this.read_with(&cx, |this, _| {
10411 if let SymbolLocation::OutsideProject {
10412 abs_path,
10413 signature,
10414 } = &symbol.path
10415 {
10416 let new_signature = this.symbol_signature(&abs_path);
10417 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10418 }
10419 Ok(())
10420 })?;
10421 let buffer = this
10422 .update(&mut cx, |this, cx| {
10423 this.open_buffer_for_symbol(
10424 &Symbol {
10425 language_server_name: symbol.language_server_name,
10426 source_worktree_id: symbol.source_worktree_id,
10427 source_language_server_id: symbol.source_language_server_id,
10428 path: symbol.path,
10429 name: symbol.name,
10430 kind: symbol.kind,
10431 range: symbol.range,
10432 label: CodeLabel::default(),
10433 container_name: symbol.container_name,
10434 },
10435 cx,
10436 )
10437 })
10438 .await?;
10439
10440 this.update(&mut cx, |this, cx| {
10441 let is_private = buffer
10442 .read(cx)
10443 .file()
10444 .map(|f| f.is_private())
10445 .unwrap_or_default();
10446 if is_private {
10447 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10448 } else {
10449 this.buffer_store
10450 .update(cx, |buffer_store, cx| {
10451 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10452 })
10453 .detach_and_log_err(cx);
10454 let buffer_id = buffer.read(cx).remote_id().to_proto();
10455 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10456 }
10457 })
10458 }
10459
10460 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10461 let mut hasher = Sha256::new();
10462 hasher.update(abs_path.to_string_lossy().as_bytes());
10463 hasher.update(self.nonce.to_be_bytes());
10464 hasher.finalize().as_slice().try_into().unwrap()
10465 }
10466
10467 pub async fn handle_get_project_symbols(
10468 this: Entity<Self>,
10469 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10470 mut cx: AsyncApp,
10471 ) -> Result<proto::GetProjectSymbolsResponse> {
10472 let symbols = this
10473 .update(&mut cx, |this, cx| {
10474 this.symbols(&envelope.payload.query, cx)
10475 })
10476 .await?;
10477
10478 Ok(proto::GetProjectSymbolsResponse {
10479 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10480 })
10481 }
10482
10483 pub async fn handle_restart_language_servers(
10484 this: Entity<Self>,
10485 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10486 mut cx: AsyncApp,
10487 ) -> Result<proto::Ack> {
10488 this.update(&mut cx, |lsp_store, cx| {
10489 let buffers =
10490 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10491 lsp_store.restart_language_servers_for_buffers(
10492 buffers,
10493 envelope
10494 .payload
10495 .only_servers
10496 .into_iter()
10497 .filter_map(|selector| {
10498 Some(match selector.selector? {
10499 proto::language_server_selector::Selector::ServerId(server_id) => {
10500 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10501 }
10502 proto::language_server_selector::Selector::Name(name) => {
10503 LanguageServerSelector::Name(LanguageServerName(
10504 SharedString::from(name),
10505 ))
10506 }
10507 })
10508 })
10509 .collect(),
10510 cx,
10511 );
10512 });
10513
10514 Ok(proto::Ack {})
10515 }
10516
10517 pub async fn handle_stop_language_servers(
10518 lsp_store: Entity<Self>,
10519 envelope: TypedEnvelope<proto::StopLanguageServers>,
10520 mut cx: AsyncApp,
10521 ) -> Result<proto::Ack> {
10522 lsp_store.update(&mut cx, |lsp_store, cx| {
10523 if envelope.payload.all
10524 && envelope.payload.also_servers.is_empty()
10525 && envelope.payload.buffer_ids.is_empty()
10526 {
10527 lsp_store.stop_all_language_servers(cx);
10528 } else {
10529 let buffers =
10530 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10531 lsp_store
10532 .stop_language_servers_for_buffers(
10533 buffers,
10534 envelope
10535 .payload
10536 .also_servers
10537 .into_iter()
10538 .filter_map(|selector| {
10539 Some(match selector.selector? {
10540 proto::language_server_selector::Selector::ServerId(
10541 server_id,
10542 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10543 server_id,
10544 )),
10545 proto::language_server_selector::Selector::Name(name) => {
10546 LanguageServerSelector::Name(LanguageServerName(
10547 SharedString::from(name),
10548 ))
10549 }
10550 })
10551 })
10552 .collect(),
10553 cx,
10554 )
10555 .detach_and_log_err(cx);
10556 }
10557 });
10558
10559 Ok(proto::Ack {})
10560 }
10561
10562 pub async fn handle_cancel_language_server_work(
10563 lsp_store: Entity<Self>,
10564 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10565 mut cx: AsyncApp,
10566 ) -> Result<proto::Ack> {
10567 lsp_store.update(&mut cx, |lsp_store, cx| {
10568 if let Some(work) = envelope.payload.work {
10569 match work {
10570 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10571 let buffers =
10572 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10573 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10574 }
10575 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10576 let server_id = LanguageServerId::from_proto(work.language_server_id);
10577 let token = work
10578 .token
10579 .map(|token| {
10580 ProgressToken::from_proto(token)
10581 .context("invalid work progress token")
10582 })
10583 .transpose()?;
10584 lsp_store.cancel_language_server_work(server_id, token, cx);
10585 }
10586 }
10587 }
10588 anyhow::Ok(())
10589 })?;
10590
10591 Ok(proto::Ack {})
10592 }
10593
10594 fn buffer_ids_to_buffers(
10595 &mut self,
10596 buffer_ids: impl Iterator<Item = u64>,
10597 cx: &mut Context<Self>,
10598 ) -> Vec<Entity<Buffer>> {
10599 buffer_ids
10600 .into_iter()
10601 .flat_map(|buffer_id| {
10602 self.buffer_store
10603 .read(cx)
10604 .get(BufferId::new(buffer_id).log_err()?)
10605 })
10606 .collect::<Vec<_>>()
10607 }
10608
10609 async fn handle_apply_additional_edits_for_completion(
10610 this: Entity<Self>,
10611 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10612 mut cx: AsyncApp,
10613 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10614 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10615 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10616 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10617 let completion = Self::deserialize_completion(
10618 envelope.payload.completion.context("invalid completion")?,
10619 )?;
10620 let all_commit_ranges = envelope
10621 .payload
10622 .all_commit_ranges
10623 .into_iter()
10624 .map(language::proto::deserialize_anchor_range)
10625 .collect::<Result<Vec<_>, _>>()?;
10626 anyhow::Ok((buffer, completion, all_commit_ranges))
10627 })?;
10628
10629 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10630 this.apply_additional_edits_for_completion(
10631 buffer,
10632 Rc::new(RefCell::new(Box::new([Completion {
10633 replace_range: completion.replace_range,
10634 new_text: completion.new_text,
10635 source: completion.source,
10636 documentation: None,
10637 label: CodeLabel::default(),
10638 match_start: None,
10639 snippet_deduplication_key: None,
10640 insert_text_mode: None,
10641 icon_path: None,
10642 confirm: None,
10643 }]))),
10644 0,
10645 false,
10646 all_commit_ranges,
10647 cx,
10648 )
10649 });
10650
10651 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10652 transaction: apply_additional_edits
10653 .await?
10654 .as_ref()
10655 .map(language::proto::serialize_transaction),
10656 })
10657 }
10658
10659 pub fn last_formatting_failure(&self) -> Option<&str> {
10660 self.last_formatting_failure.as_deref()
10661 }
10662
10663 pub fn reset_last_formatting_failure(&mut self) {
10664 self.last_formatting_failure = None;
10665 }
10666
10667 pub fn environment_for_buffer(
10668 &self,
10669 buffer: &Entity<Buffer>,
10670 cx: &mut Context<Self>,
10671 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10672 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10673 environment.update(cx, |env, cx| {
10674 env.buffer_environment(buffer, &self.worktree_store, cx)
10675 })
10676 } else {
10677 Task::ready(None).shared()
10678 }
10679 }
10680
10681 pub fn format(
10682 &mut self,
10683 buffers: HashSet<Entity<Buffer>>,
10684 target: LspFormatTarget,
10685 push_to_history: bool,
10686 trigger: FormatTrigger,
10687 cx: &mut Context<Self>,
10688 ) -> Task<anyhow::Result<ProjectTransaction>> {
10689 let logger = zlog::scoped!("format");
10690 if self.as_local().is_some() {
10691 zlog::trace!(logger => "Formatting locally");
10692 let logger = zlog::scoped!(logger => "local");
10693 let buffers = buffers
10694 .into_iter()
10695 .map(|buffer_handle| {
10696 let buffer = buffer_handle.read(cx);
10697 let buffer_abs_path = File::from_dyn(buffer.file())
10698 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10699
10700 (buffer_handle, buffer_abs_path, buffer.remote_id())
10701 })
10702 .collect::<Vec<_>>();
10703
10704 cx.spawn(async move |lsp_store, cx| {
10705 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10706
10707 for (handle, abs_path, id) in buffers {
10708 let env = lsp_store
10709 .update(cx, |lsp_store, cx| {
10710 lsp_store.environment_for_buffer(&handle, cx)
10711 })?
10712 .await;
10713
10714 let ranges = match &target {
10715 LspFormatTarget::Buffers => None,
10716 LspFormatTarget::Ranges(ranges) => {
10717 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10718 }
10719 };
10720
10721 formattable_buffers.push(FormattableBuffer {
10722 handle,
10723 abs_path,
10724 env,
10725 ranges,
10726 });
10727 }
10728 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10729
10730 let format_timer = zlog::time!(logger => "Formatting buffers");
10731 let result = LocalLspStore::format_locally(
10732 lsp_store.clone(),
10733 formattable_buffers,
10734 push_to_history,
10735 trigger,
10736 logger,
10737 cx,
10738 )
10739 .await;
10740 format_timer.end();
10741
10742 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10743
10744 lsp_store.update(cx, |lsp_store, _| {
10745 lsp_store.update_last_formatting_failure(&result);
10746 })?;
10747
10748 result
10749 })
10750 } else if let Some((client, project_id)) = self.upstream_client() {
10751 zlog::trace!(logger => "Formatting remotely");
10752 let logger = zlog::scoped!(logger => "remote");
10753
10754 let buffer_ranges = match &target {
10755 LspFormatTarget::Buffers => Vec::new(),
10756 LspFormatTarget::Ranges(ranges) => ranges
10757 .iter()
10758 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10759 buffer_id: buffer_id.to_proto(),
10760 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10761 })
10762 .collect(),
10763 };
10764
10765 let buffer_store = self.buffer_store();
10766 cx.spawn(async move |lsp_store, cx| {
10767 zlog::trace!(logger => "Sending remote format request");
10768 let request_timer = zlog::time!(logger => "remote format request");
10769 let result = client
10770 .request(proto::FormatBuffers {
10771 project_id,
10772 trigger: trigger as i32,
10773 buffer_ids: buffers
10774 .iter()
10775 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10776 .collect(),
10777 buffer_ranges,
10778 })
10779 .await
10780 .and_then(|result| result.transaction.context("missing transaction"));
10781 request_timer.end();
10782
10783 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10784
10785 lsp_store.update(cx, |lsp_store, _| {
10786 lsp_store.update_last_formatting_failure(&result);
10787 })?;
10788
10789 let transaction_response = result?;
10790 let _timer = zlog::time!(logger => "deserializing project transaction");
10791 buffer_store
10792 .update(cx, |buffer_store, cx| {
10793 buffer_store.deserialize_project_transaction(
10794 transaction_response,
10795 push_to_history,
10796 cx,
10797 )
10798 })
10799 .await
10800 })
10801 } else {
10802 zlog::trace!(logger => "Not formatting");
10803 Task::ready(Ok(ProjectTransaction::default()))
10804 }
10805 }
10806
10807 async fn handle_format_buffers(
10808 this: Entity<Self>,
10809 envelope: TypedEnvelope<proto::FormatBuffers>,
10810 mut cx: AsyncApp,
10811 ) -> Result<proto::FormatBuffersResponse> {
10812 let sender_id = envelope.original_sender_id().unwrap_or_default();
10813 let format = this.update(&mut cx, |this, cx| {
10814 let mut buffers = HashSet::default();
10815 for buffer_id in &envelope.payload.buffer_ids {
10816 let buffer_id = BufferId::new(*buffer_id)?;
10817 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10818 }
10819
10820 let target = if envelope.payload.buffer_ranges.is_empty() {
10821 LspFormatTarget::Buffers
10822 } else {
10823 let mut ranges_map = BTreeMap::new();
10824 for buffer_range in &envelope.payload.buffer_ranges {
10825 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10826 let ranges: Result<Vec<_>> = buffer_range
10827 .ranges
10828 .iter()
10829 .map(|range| {
10830 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10831 })
10832 .collect();
10833 ranges_map.insert(buffer_id, ranges?);
10834 }
10835 LspFormatTarget::Ranges(ranges_map)
10836 };
10837
10838 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10839 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10840 })?;
10841
10842 let project_transaction = format.await?;
10843 let project_transaction = this.update(&mut cx, |this, cx| {
10844 this.buffer_store.update(cx, |buffer_store, cx| {
10845 buffer_store.serialize_project_transaction_for_peer(
10846 project_transaction,
10847 sender_id,
10848 cx,
10849 )
10850 })
10851 });
10852 Ok(proto::FormatBuffersResponse {
10853 transaction: Some(project_transaction),
10854 })
10855 }
10856
10857 async fn handle_apply_code_action_kind(
10858 this: Entity<Self>,
10859 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10860 mut cx: AsyncApp,
10861 ) -> Result<proto::ApplyCodeActionKindResponse> {
10862 let sender_id = envelope.original_sender_id().unwrap_or_default();
10863 let format = this.update(&mut cx, |this, cx| {
10864 let mut buffers = HashSet::default();
10865 for buffer_id in &envelope.payload.buffer_ids {
10866 let buffer_id = BufferId::new(*buffer_id)?;
10867 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10868 }
10869 let kind = match envelope.payload.kind.as_str() {
10870 "" => CodeActionKind::EMPTY,
10871 "quickfix" => CodeActionKind::QUICKFIX,
10872 "refactor" => CodeActionKind::REFACTOR,
10873 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10874 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10875 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10876 "source" => CodeActionKind::SOURCE,
10877 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10878 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10879 _ => anyhow::bail!(
10880 "Invalid code action kind {}",
10881 envelope.payload.kind.as_str()
10882 ),
10883 };
10884 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10885 })?;
10886
10887 let project_transaction = format.await?;
10888 let project_transaction = this.update(&mut cx, |this, cx| {
10889 this.buffer_store.update(cx, |buffer_store, cx| {
10890 buffer_store.serialize_project_transaction_for_peer(
10891 project_transaction,
10892 sender_id,
10893 cx,
10894 )
10895 })
10896 });
10897 Ok(proto::ApplyCodeActionKindResponse {
10898 transaction: Some(project_transaction),
10899 })
10900 }
10901
10902 async fn shutdown_language_server(
10903 server_state: Option<LanguageServerState>,
10904 name: LanguageServerName,
10905 cx: &mut AsyncApp,
10906 ) {
10907 let server = match server_state {
10908 Some(LanguageServerState::Starting { startup, .. }) => {
10909 let mut timer = cx
10910 .background_executor()
10911 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10912 .fuse();
10913
10914 select! {
10915 server = startup.fuse() => server,
10916 () = timer => {
10917 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10918 None
10919 },
10920 }
10921 }
10922
10923 Some(LanguageServerState::Running { server, .. }) => Some(server),
10924
10925 None => None,
10926 };
10927
10928 let Some(server) = server else { return };
10929 if let Some(shutdown) = server.shutdown() {
10930 shutdown.await;
10931 }
10932 }
10933
10934 // Returns a list of all of the worktrees which no longer have a language server and the root path
10935 // for the stopped server
10936 fn stop_local_language_server(
10937 &mut self,
10938 server_id: LanguageServerId,
10939 cx: &mut Context<Self>,
10940 ) -> Task<()> {
10941 let local = match &mut self.mode {
10942 LspStoreMode::Local(local) => local,
10943 _ => {
10944 return Task::ready(());
10945 }
10946 };
10947
10948 // Remove this server ID from all entries in the given worktree.
10949 local
10950 .language_server_ids
10951 .retain(|_, state| state.id != server_id);
10952 self.buffer_store.update(cx, |buffer_store, cx| {
10953 for buffer in buffer_store.buffers() {
10954 buffer.update(cx, |buffer, cx| {
10955 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10956 buffer.set_completion_triggers(server_id, Default::default(), cx);
10957 });
10958 }
10959 });
10960
10961 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10962 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10963 summaries.retain(|path, summaries_by_server_id| {
10964 if summaries_by_server_id.remove(&server_id).is_some() {
10965 if let Some((client, project_id)) = self.downstream_client.clone() {
10966 client
10967 .send(proto::UpdateDiagnosticSummary {
10968 project_id,
10969 worktree_id: worktree_id.to_proto(),
10970 summary: Some(proto::DiagnosticSummary {
10971 path: path.as_ref().to_proto(),
10972 language_server_id: server_id.0 as u64,
10973 error_count: 0,
10974 warning_count: 0,
10975 }),
10976 more_summaries: Vec::new(),
10977 })
10978 .log_err();
10979 }
10980 cleared_paths.push(ProjectPath {
10981 worktree_id: *worktree_id,
10982 path: path.clone(),
10983 });
10984 !summaries_by_server_id.is_empty()
10985 } else {
10986 true
10987 }
10988 });
10989 }
10990 if !cleared_paths.is_empty() {
10991 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10992 server_id,
10993 paths: cleared_paths,
10994 });
10995 }
10996
10997 let local = self.as_local_mut().unwrap();
10998 for diagnostics in local.diagnostics.values_mut() {
10999 diagnostics.retain(|_, diagnostics_by_server_id| {
11000 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11001 diagnostics_by_server_id.remove(ix);
11002 !diagnostics_by_server_id.is_empty()
11003 } else {
11004 true
11005 }
11006 });
11007 }
11008 local.language_server_watched_paths.remove(&server_id);
11009
11010 let server_state = local.language_servers.remove(&server_id);
11011 self.cleanup_lsp_data(server_id);
11012 let name = self
11013 .language_server_statuses
11014 .remove(&server_id)
11015 .map(|status| status.name)
11016 .or_else(|| {
11017 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11018 Some(adapter.name())
11019 } else {
11020 None
11021 }
11022 });
11023
11024 if let Some(name) = name {
11025 log::info!("stopping language server {name}");
11026 self.languages
11027 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11028 cx.notify();
11029
11030 return cx.spawn(async move |lsp_store, cx| {
11031 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11032 lsp_store
11033 .update(cx, |lsp_store, cx| {
11034 lsp_store
11035 .languages
11036 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11037 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11038 cx.notify();
11039 })
11040 .ok();
11041 });
11042 }
11043
11044 if server_state.is_some() {
11045 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11046 }
11047 Task::ready(())
11048 }
11049
11050 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11051 self.shutdown_all_language_servers(cx).detach();
11052 }
11053
11054 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11055 if let Some((client, project_id)) = self.upstream_client() {
11056 let request = client.request(proto::StopLanguageServers {
11057 project_id,
11058 buffer_ids: Vec::new(),
11059 also_servers: Vec::new(),
11060 all: true,
11061 });
11062 cx.background_spawn(async move {
11063 request.await.ok();
11064 })
11065 } else {
11066 let Some(local) = self.as_local_mut() else {
11067 return Task::ready(());
11068 };
11069 let language_servers_to_stop = local
11070 .language_server_ids
11071 .values()
11072 .map(|state| state.id)
11073 .collect();
11074 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11075 let tasks = language_servers_to_stop
11076 .into_iter()
11077 .map(|server| self.stop_local_language_server(server, cx))
11078 .collect::<Vec<_>>();
11079 cx.background_spawn(async move {
11080 futures::future::join_all(tasks).await;
11081 })
11082 }
11083 }
11084
11085 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11086 let buffers = self.buffer_store.read(cx).buffers().collect();
11087 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11088 }
11089
11090 pub fn restart_language_servers_for_buffers(
11091 &mut self,
11092 buffers: Vec<Entity<Buffer>>,
11093 only_restart_servers: HashSet<LanguageServerSelector>,
11094 cx: &mut Context<Self>,
11095 ) {
11096 if let Some((client, project_id)) = self.upstream_client() {
11097 let request = client.request(proto::RestartLanguageServers {
11098 project_id,
11099 buffer_ids: buffers
11100 .into_iter()
11101 .map(|b| b.read(cx).remote_id().to_proto())
11102 .collect(),
11103 only_servers: only_restart_servers
11104 .into_iter()
11105 .map(|selector| {
11106 let selector = match selector {
11107 LanguageServerSelector::Id(language_server_id) => {
11108 proto::language_server_selector::Selector::ServerId(
11109 language_server_id.to_proto(),
11110 )
11111 }
11112 LanguageServerSelector::Name(language_server_name) => {
11113 proto::language_server_selector::Selector::Name(
11114 language_server_name.to_string(),
11115 )
11116 }
11117 };
11118 proto::LanguageServerSelector {
11119 selector: Some(selector),
11120 }
11121 })
11122 .collect(),
11123 all: false,
11124 });
11125 cx.background_spawn(request).detach_and_log_err(cx);
11126 } else {
11127 let stop_task = if only_restart_servers.is_empty() {
11128 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11129 } else {
11130 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11131 };
11132 cx.spawn(async move |lsp_store, cx| {
11133 stop_task.await;
11134 lsp_store.update(cx, |lsp_store, cx| {
11135 for buffer in buffers {
11136 lsp_store.register_buffer_with_language_servers(
11137 &buffer,
11138 only_restart_servers.clone(),
11139 true,
11140 cx,
11141 );
11142 }
11143 })
11144 })
11145 .detach();
11146 }
11147 }
11148
11149 pub fn stop_language_servers_for_buffers(
11150 &mut self,
11151 buffers: Vec<Entity<Buffer>>,
11152 also_stop_servers: HashSet<LanguageServerSelector>,
11153 cx: &mut Context<Self>,
11154 ) -> Task<Result<()>> {
11155 if let Some((client, project_id)) = self.upstream_client() {
11156 let request = client.request(proto::StopLanguageServers {
11157 project_id,
11158 buffer_ids: buffers
11159 .into_iter()
11160 .map(|b| b.read(cx).remote_id().to_proto())
11161 .collect(),
11162 also_servers: also_stop_servers
11163 .into_iter()
11164 .map(|selector| {
11165 let selector = match selector {
11166 LanguageServerSelector::Id(language_server_id) => {
11167 proto::language_server_selector::Selector::ServerId(
11168 language_server_id.to_proto(),
11169 )
11170 }
11171 LanguageServerSelector::Name(language_server_name) => {
11172 proto::language_server_selector::Selector::Name(
11173 language_server_name.to_string(),
11174 )
11175 }
11176 };
11177 proto::LanguageServerSelector {
11178 selector: Some(selector),
11179 }
11180 })
11181 .collect(),
11182 all: false,
11183 });
11184 cx.background_spawn(async move {
11185 let _ = request.await?;
11186 Ok(())
11187 })
11188 } else {
11189 let task =
11190 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11191 cx.background_spawn(async move {
11192 task.await;
11193 Ok(())
11194 })
11195 }
11196 }
11197
11198 fn stop_local_language_servers_for_buffers(
11199 &mut self,
11200 buffers: &[Entity<Buffer>],
11201 also_stop_servers: HashSet<LanguageServerSelector>,
11202 cx: &mut Context<Self>,
11203 ) -> Task<()> {
11204 let Some(local) = self.as_local_mut() else {
11205 return Task::ready(());
11206 };
11207 let mut language_server_names_to_stop = BTreeSet::default();
11208 let mut language_servers_to_stop = also_stop_servers
11209 .into_iter()
11210 .flat_map(|selector| match selector {
11211 LanguageServerSelector::Id(id) => Some(id),
11212 LanguageServerSelector::Name(name) => {
11213 language_server_names_to_stop.insert(name);
11214 None
11215 }
11216 })
11217 .collect::<BTreeSet<_>>();
11218
11219 let mut covered_worktrees = HashSet::default();
11220 for buffer in buffers {
11221 buffer.update(cx, |buffer, cx| {
11222 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11223 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11224 && covered_worktrees.insert(worktree_id)
11225 {
11226 language_server_names_to_stop.retain(|name| {
11227 let old_ids_count = language_servers_to_stop.len();
11228 let all_language_servers_with_this_name = local
11229 .language_server_ids
11230 .iter()
11231 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11232 language_servers_to_stop.extend(all_language_servers_with_this_name);
11233 old_ids_count == language_servers_to_stop.len()
11234 });
11235 }
11236 });
11237 }
11238 for name in language_server_names_to_stop {
11239 language_servers_to_stop.extend(
11240 local
11241 .language_server_ids
11242 .iter()
11243 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11244 );
11245 }
11246
11247 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11248 let tasks = language_servers_to_stop
11249 .into_iter()
11250 .map(|server| self.stop_local_language_server(server, cx))
11251 .collect::<Vec<_>>();
11252
11253 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11254 }
11255
11256 #[cfg(any(test, feature = "test-support"))]
11257 pub fn update_diagnostics(
11258 &mut self,
11259 server_id: LanguageServerId,
11260 diagnostics: lsp::PublishDiagnosticsParams,
11261 result_id: Option<SharedString>,
11262 source_kind: DiagnosticSourceKind,
11263 disk_based_sources: &[String],
11264 cx: &mut Context<Self>,
11265 ) -> Result<()> {
11266 self.merge_lsp_diagnostics(
11267 source_kind,
11268 vec![DocumentDiagnosticsUpdate {
11269 diagnostics,
11270 result_id,
11271 server_id,
11272 disk_based_sources: Cow::Borrowed(disk_based_sources),
11273 registration_id: None,
11274 }],
11275 |_, _, _| false,
11276 cx,
11277 )
11278 }
11279
11280 pub fn merge_lsp_diagnostics(
11281 &mut self,
11282 source_kind: DiagnosticSourceKind,
11283 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11284 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11285 cx: &mut Context<Self>,
11286 ) -> Result<()> {
11287 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11288 let updates = lsp_diagnostics
11289 .into_iter()
11290 .filter_map(|update| {
11291 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11292 Some(DocumentDiagnosticsUpdate {
11293 diagnostics: self.lsp_to_document_diagnostics(
11294 abs_path,
11295 source_kind,
11296 update.server_id,
11297 update.diagnostics,
11298 &update.disk_based_sources,
11299 update.registration_id.clone(),
11300 ),
11301 result_id: update.result_id,
11302 server_id: update.server_id,
11303 disk_based_sources: update.disk_based_sources,
11304 registration_id: update.registration_id,
11305 })
11306 })
11307 .collect();
11308 self.merge_diagnostic_entries(updates, merge, cx)?;
11309 Ok(())
11310 }
11311
11312 fn lsp_to_document_diagnostics(
11313 &mut self,
11314 document_abs_path: PathBuf,
11315 source_kind: DiagnosticSourceKind,
11316 server_id: LanguageServerId,
11317 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11318 disk_based_sources: &[String],
11319 registration_id: Option<SharedString>,
11320 ) -> DocumentDiagnostics {
11321 let mut diagnostics = Vec::default();
11322 let mut primary_diagnostic_group_ids = HashMap::default();
11323 let mut sources_by_group_id = HashMap::default();
11324 let mut supporting_diagnostics = HashMap::default();
11325
11326 let adapter = self.language_server_adapter_for_id(server_id);
11327
11328 // Ensure that primary diagnostics are always the most severe
11329 lsp_diagnostics
11330 .diagnostics
11331 .sort_by_key(|item| item.severity);
11332
11333 for diagnostic in &lsp_diagnostics.diagnostics {
11334 let source = diagnostic.source.as_ref();
11335 let range = range_from_lsp(diagnostic.range);
11336 let is_supporting = diagnostic
11337 .related_information
11338 .as_ref()
11339 .is_some_and(|infos| {
11340 infos.iter().any(|info| {
11341 primary_diagnostic_group_ids.contains_key(&(
11342 source,
11343 diagnostic.code.clone(),
11344 range_from_lsp(info.location.range),
11345 ))
11346 })
11347 });
11348
11349 let is_unnecessary = diagnostic
11350 .tags
11351 .as_ref()
11352 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11353
11354 let underline = self
11355 .language_server_adapter_for_id(server_id)
11356 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11357
11358 if is_supporting {
11359 supporting_diagnostics.insert(
11360 (source, diagnostic.code.clone(), range),
11361 (diagnostic.severity, is_unnecessary),
11362 );
11363 } else {
11364 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11365 let is_disk_based =
11366 source.is_some_and(|source| disk_based_sources.contains(source));
11367
11368 sources_by_group_id.insert(group_id, source);
11369 primary_diagnostic_group_ids
11370 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11371
11372 diagnostics.push(DiagnosticEntry {
11373 range,
11374 diagnostic: Diagnostic {
11375 source: diagnostic.source.clone(),
11376 source_kind,
11377 code: diagnostic.code.clone(),
11378 code_description: diagnostic
11379 .code_description
11380 .as_ref()
11381 .and_then(|d| d.href.clone()),
11382 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11383 markdown: adapter.as_ref().and_then(|adapter| {
11384 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11385 }),
11386 message: diagnostic.message.trim().to_string(),
11387 group_id,
11388 is_primary: true,
11389 is_disk_based,
11390 is_unnecessary,
11391 underline,
11392 data: diagnostic.data.clone(),
11393 registration_id: registration_id.clone(),
11394 },
11395 });
11396 if let Some(infos) = &diagnostic.related_information {
11397 for info in infos {
11398 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11399 let range = range_from_lsp(info.location.range);
11400 diagnostics.push(DiagnosticEntry {
11401 range,
11402 diagnostic: Diagnostic {
11403 source: diagnostic.source.clone(),
11404 source_kind,
11405 code: diagnostic.code.clone(),
11406 code_description: diagnostic
11407 .code_description
11408 .as_ref()
11409 .and_then(|d| d.href.clone()),
11410 severity: DiagnosticSeverity::INFORMATION,
11411 markdown: adapter.as_ref().and_then(|adapter| {
11412 adapter.diagnostic_message_to_markdown(&info.message)
11413 }),
11414 message: info.message.trim().to_string(),
11415 group_id,
11416 is_primary: false,
11417 is_disk_based,
11418 is_unnecessary: false,
11419 underline,
11420 data: diagnostic.data.clone(),
11421 registration_id: registration_id.clone(),
11422 },
11423 });
11424 }
11425 }
11426 }
11427 }
11428 }
11429
11430 for entry in &mut diagnostics {
11431 let diagnostic = &mut entry.diagnostic;
11432 if !diagnostic.is_primary {
11433 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11434 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11435 source,
11436 diagnostic.code.clone(),
11437 entry.range.clone(),
11438 )) {
11439 if let Some(severity) = severity {
11440 diagnostic.severity = severity;
11441 }
11442 diagnostic.is_unnecessary = is_unnecessary;
11443 }
11444 }
11445 }
11446
11447 DocumentDiagnostics {
11448 diagnostics,
11449 document_abs_path,
11450 version: lsp_diagnostics.version,
11451 }
11452 }
11453
11454 fn insert_newly_running_language_server(
11455 &mut self,
11456 adapter: Arc<CachedLspAdapter>,
11457 language_server: Arc<LanguageServer>,
11458 server_id: LanguageServerId,
11459 key: LanguageServerSeed,
11460 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11461 cx: &mut Context<Self>,
11462 ) {
11463 let Some(local) = self.as_local_mut() else {
11464 return;
11465 };
11466 // If the language server for this key doesn't match the server id, don't store the
11467 // server. Which will cause it to be dropped, killing the process
11468 if local
11469 .language_server_ids
11470 .get(&key)
11471 .map(|state| state.id != server_id)
11472 .unwrap_or(false)
11473 {
11474 return;
11475 }
11476
11477 // Update language_servers collection with Running variant of LanguageServerState
11478 // indicating that the server is up and running and ready
11479 let workspace_folders = workspace_folders.lock().clone();
11480 language_server.set_workspace_folders(workspace_folders);
11481
11482 let workspace_diagnostics_refresh_tasks = language_server
11483 .capabilities()
11484 .diagnostic_provider
11485 .and_then(|provider| {
11486 local
11487 .language_server_dynamic_registrations
11488 .entry(server_id)
11489 .or_default()
11490 .diagnostics
11491 .entry(None)
11492 .or_insert(provider.clone());
11493 let workspace_refresher =
11494 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11495
11496 Some((None, workspace_refresher))
11497 })
11498 .into_iter()
11499 .collect();
11500 local.language_servers.insert(
11501 server_id,
11502 LanguageServerState::Running {
11503 workspace_diagnostics_refresh_tasks,
11504 adapter: adapter.clone(),
11505 server: language_server.clone(),
11506 simulate_disk_based_diagnostics_completion: None,
11507 },
11508 );
11509 local
11510 .languages
11511 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11512 if let Some(file_ops_caps) = language_server
11513 .capabilities()
11514 .workspace
11515 .as_ref()
11516 .and_then(|ws| ws.file_operations.as_ref())
11517 {
11518 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11519 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11520 if did_rename_caps.or(will_rename_caps).is_some() {
11521 let watcher = RenamePathsWatchedForServer::default()
11522 .with_did_rename_patterns(did_rename_caps)
11523 .with_will_rename_patterns(will_rename_caps);
11524 local
11525 .language_server_paths_watched_for_rename
11526 .insert(server_id, watcher);
11527 }
11528 }
11529
11530 self.language_server_statuses.insert(
11531 server_id,
11532 LanguageServerStatus {
11533 name: language_server.name(),
11534 server_version: language_server.version(),
11535 server_readable_version: language_server.readable_version(),
11536 pending_work: Default::default(),
11537 has_pending_diagnostic_updates: false,
11538 progress_tokens: Default::default(),
11539 worktree: Some(key.worktree_id),
11540 binary: Some(language_server.binary().clone()),
11541 configuration: Some(language_server.configuration().clone()),
11542 workspace_folders: language_server.workspace_folders(),
11543 process_id: language_server.process_id(),
11544 },
11545 );
11546
11547 cx.emit(LspStoreEvent::LanguageServerAdded(
11548 server_id,
11549 language_server.name(),
11550 Some(key.worktree_id),
11551 ));
11552
11553 let server_capabilities = language_server.capabilities();
11554 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11555 downstream_client
11556 .send(proto::StartLanguageServer {
11557 project_id: *project_id,
11558 server: Some(proto::LanguageServer {
11559 id: server_id.to_proto(),
11560 name: language_server.name().to_string(),
11561 worktree_id: Some(key.worktree_id.to_proto()),
11562 }),
11563 capabilities: serde_json::to_string(&server_capabilities)
11564 .expect("serializing server LSP capabilities"),
11565 })
11566 .log_err();
11567 }
11568 self.lsp_server_capabilities
11569 .insert(server_id, server_capabilities);
11570
11571 // Tell the language server about every open buffer in the worktree that matches the language.
11572 // Also check for buffers in worktrees that reused this server
11573 let mut worktrees_using_server = vec![key.worktree_id];
11574 if let Some(local) = self.as_local() {
11575 // Find all worktrees that have this server in their language server tree
11576 for (worktree_id, servers) in &local.lsp_tree.instances {
11577 if *worktree_id != key.worktree_id {
11578 for server_map in servers.roots.values() {
11579 if server_map
11580 .values()
11581 .any(|(node, _)| node.id() == Some(server_id))
11582 {
11583 worktrees_using_server.push(*worktree_id);
11584 }
11585 }
11586 }
11587 }
11588 }
11589
11590 let mut buffer_paths_registered = Vec::new();
11591 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11592 let mut lsp_adapters = HashMap::default();
11593 for buffer_handle in buffer_store.buffers() {
11594 let buffer = buffer_handle.read(cx);
11595 let file = match File::from_dyn(buffer.file()) {
11596 Some(file) => file,
11597 None => continue,
11598 };
11599 let language = match buffer.language() {
11600 Some(language) => language,
11601 None => continue,
11602 };
11603
11604 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11605 || !lsp_adapters
11606 .entry(language.name())
11607 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11608 .iter()
11609 .any(|a| a.name == key.name)
11610 {
11611 continue;
11612 }
11613 // didOpen
11614 let file = match file.as_local() {
11615 Some(file) => file,
11616 None => continue,
11617 };
11618
11619 let local = self.as_local_mut().unwrap();
11620
11621 let buffer_id = buffer.remote_id();
11622 if local.registered_buffers.contains_key(&buffer_id) {
11623 let abs_path = file.abs_path(cx);
11624 let uri = match lsp::Uri::from_file_path(&abs_path) {
11625 Ok(uri) => uri,
11626 Err(()) => {
11627 log::error!("failed to convert path to URI: {:?}", abs_path);
11628 continue;
11629 }
11630 };
11631
11632 let versions = local
11633 .buffer_snapshots
11634 .entry(buffer_id)
11635 .or_default()
11636 .entry(server_id)
11637 .and_modify(|_| {
11638 assert!(
11639 false,
11640 "There should not be an existing snapshot for a newly inserted buffer"
11641 )
11642 })
11643 .or_insert_with(|| {
11644 vec![LspBufferSnapshot {
11645 version: 0,
11646 snapshot: buffer.text_snapshot(),
11647 }]
11648 });
11649
11650 let snapshot = versions.last().unwrap();
11651 let version = snapshot.version;
11652 let initial_snapshot = &snapshot.snapshot;
11653 language_server.register_buffer(
11654 uri,
11655 adapter.language_id(&language.name()),
11656 version,
11657 initial_snapshot.text(),
11658 );
11659 buffer_paths_registered.push((buffer_id, abs_path));
11660 local
11661 .buffers_opened_in_servers
11662 .entry(buffer_id)
11663 .or_default()
11664 .insert(server_id);
11665 }
11666 buffer_handle.update(cx, |buffer, cx| {
11667 buffer.set_completion_triggers(
11668 server_id,
11669 language_server
11670 .capabilities()
11671 .completion_provider
11672 .as_ref()
11673 .and_then(|provider| {
11674 provider
11675 .trigger_characters
11676 .as_ref()
11677 .map(|characters| characters.iter().cloned().collect())
11678 })
11679 .unwrap_or_default(),
11680 cx,
11681 )
11682 });
11683 }
11684 });
11685
11686 for (buffer_id, abs_path) in buffer_paths_registered {
11687 cx.emit(LspStoreEvent::LanguageServerUpdate {
11688 language_server_id: server_id,
11689 name: Some(adapter.name()),
11690 message: proto::update_language_server::Variant::RegisteredForBuffer(
11691 proto::RegisteredForBuffer {
11692 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11693 buffer_id: buffer_id.to_proto(),
11694 },
11695 ),
11696 });
11697 }
11698
11699 cx.notify();
11700 }
11701
11702 pub fn language_servers_running_disk_based_diagnostics(
11703 &self,
11704 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11705 self.language_server_statuses
11706 .iter()
11707 .filter_map(|(id, status)| {
11708 if status.has_pending_diagnostic_updates {
11709 Some(*id)
11710 } else {
11711 None
11712 }
11713 })
11714 }
11715
11716 pub(crate) fn cancel_language_server_work_for_buffers(
11717 &mut self,
11718 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11719 cx: &mut Context<Self>,
11720 ) {
11721 if let Some((client, project_id)) = self.upstream_client() {
11722 let request = client.request(proto::CancelLanguageServerWork {
11723 project_id,
11724 work: Some(proto::cancel_language_server_work::Work::Buffers(
11725 proto::cancel_language_server_work::Buffers {
11726 buffer_ids: buffers
11727 .into_iter()
11728 .map(|b| b.read(cx).remote_id().to_proto())
11729 .collect(),
11730 },
11731 )),
11732 });
11733 cx.background_spawn(request).detach_and_log_err(cx);
11734 } else if let Some(local) = self.as_local() {
11735 let servers = buffers
11736 .into_iter()
11737 .flat_map(|buffer| {
11738 buffer.update(cx, |buffer, cx| {
11739 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11740 })
11741 })
11742 .collect::<HashSet<_>>();
11743 for server_id in servers {
11744 self.cancel_language_server_work(server_id, None, cx);
11745 }
11746 }
11747 }
11748
11749 pub(crate) fn cancel_language_server_work(
11750 &mut self,
11751 server_id: LanguageServerId,
11752 token_to_cancel: Option<ProgressToken>,
11753 cx: &mut Context<Self>,
11754 ) {
11755 if let Some(local) = self.as_local() {
11756 let status = self.language_server_statuses.get(&server_id);
11757 let server = local.language_servers.get(&server_id);
11758 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11759 {
11760 for (token, progress) in &status.pending_work {
11761 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11762 && token != token_to_cancel
11763 {
11764 continue;
11765 }
11766 if progress.is_cancellable {
11767 server
11768 .notify::<lsp::notification::WorkDoneProgressCancel>(
11769 WorkDoneProgressCancelParams {
11770 token: token.to_lsp(),
11771 },
11772 )
11773 .ok();
11774 }
11775 }
11776 }
11777 } else if let Some((client, project_id)) = self.upstream_client() {
11778 let request = client.request(proto::CancelLanguageServerWork {
11779 project_id,
11780 work: Some(
11781 proto::cancel_language_server_work::Work::LanguageServerWork(
11782 proto::cancel_language_server_work::LanguageServerWork {
11783 language_server_id: server_id.to_proto(),
11784 token: token_to_cancel.map(|token| token.to_proto()),
11785 },
11786 ),
11787 ),
11788 });
11789 cx.background_spawn(request).detach_and_log_err(cx);
11790 }
11791 }
11792
11793 fn register_supplementary_language_server(
11794 &mut self,
11795 id: LanguageServerId,
11796 name: LanguageServerName,
11797 server: Arc<LanguageServer>,
11798 cx: &mut Context<Self>,
11799 ) {
11800 if let Some(local) = self.as_local_mut() {
11801 local
11802 .supplementary_language_servers
11803 .insert(id, (name.clone(), server));
11804 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11805 }
11806 }
11807
11808 fn unregister_supplementary_language_server(
11809 &mut self,
11810 id: LanguageServerId,
11811 cx: &mut Context<Self>,
11812 ) {
11813 if let Some(local) = self.as_local_mut() {
11814 local.supplementary_language_servers.remove(&id);
11815 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11816 }
11817 }
11818
11819 pub(crate) fn supplementary_language_servers(
11820 &self,
11821 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11822 self.as_local().into_iter().flat_map(|local| {
11823 local
11824 .supplementary_language_servers
11825 .iter()
11826 .map(|(id, (name, _))| (*id, name.clone()))
11827 })
11828 }
11829
11830 pub fn language_server_adapter_for_id(
11831 &self,
11832 id: LanguageServerId,
11833 ) -> Option<Arc<CachedLspAdapter>> {
11834 self.as_local()
11835 .and_then(|local| local.language_servers.get(&id))
11836 .and_then(|language_server_state| match language_server_state {
11837 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11838 _ => None,
11839 })
11840 }
11841
11842 pub(super) fn update_local_worktree_language_servers(
11843 &mut self,
11844 worktree_handle: &Entity<Worktree>,
11845 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11846 cx: &mut Context<Self>,
11847 ) {
11848 if changes.is_empty() {
11849 return;
11850 }
11851
11852 let Some(local) = self.as_local() else { return };
11853
11854 local.prettier_store.update(cx, |prettier_store, cx| {
11855 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11856 });
11857
11858 let worktree_id = worktree_handle.read(cx).id();
11859 let mut language_server_ids = local
11860 .language_server_ids
11861 .iter()
11862 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11863 .collect::<Vec<_>>();
11864 language_server_ids.sort();
11865 language_server_ids.dedup();
11866
11867 // let abs_path = worktree_handle.read(cx).abs_path();
11868 for server_id in &language_server_ids {
11869 if let Some(LanguageServerState::Running { server, .. }) =
11870 local.language_servers.get(server_id)
11871 && let Some(watched_paths) = local
11872 .language_server_watched_paths
11873 .get(server_id)
11874 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11875 {
11876 let params = lsp::DidChangeWatchedFilesParams {
11877 changes: changes
11878 .iter()
11879 .filter_map(|(path, _, change)| {
11880 if !watched_paths.is_match(path.as_std_path()) {
11881 return None;
11882 }
11883 let typ = match change {
11884 PathChange::Loaded => return None,
11885 PathChange::Added => lsp::FileChangeType::CREATED,
11886 PathChange::Removed => lsp::FileChangeType::DELETED,
11887 PathChange::Updated => lsp::FileChangeType::CHANGED,
11888 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11889 };
11890 let uri = lsp::Uri::from_file_path(
11891 worktree_handle.read(cx).absolutize(&path),
11892 )
11893 .ok()?;
11894 Some(lsp::FileEvent { uri, typ })
11895 })
11896 .collect(),
11897 };
11898 if !params.changes.is_empty() {
11899 server
11900 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11901 .ok();
11902 }
11903 }
11904 }
11905 for (path, _, _) in changes {
11906 if let Some(file_name) = path.file_name()
11907 && local.watched_manifest_filenames.contains(file_name)
11908 {
11909 self.request_workspace_config_refresh();
11910 break;
11911 }
11912 }
11913 }
11914
11915 pub fn wait_for_remote_buffer(
11916 &mut self,
11917 id: BufferId,
11918 cx: &mut Context<Self>,
11919 ) -> Task<Result<Entity<Buffer>>> {
11920 self.buffer_store.update(cx, |buffer_store, cx| {
11921 buffer_store.wait_for_remote_buffer(id, cx)
11922 })
11923 }
11924
11925 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11926 let mut result = proto::Symbol {
11927 language_server_name: symbol.language_server_name.0.to_string(),
11928 source_worktree_id: symbol.source_worktree_id.to_proto(),
11929 language_server_id: symbol.source_language_server_id.to_proto(),
11930 name: symbol.name.clone(),
11931 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11932 start: Some(proto::PointUtf16 {
11933 row: symbol.range.start.0.row,
11934 column: symbol.range.start.0.column,
11935 }),
11936 end: Some(proto::PointUtf16 {
11937 row: symbol.range.end.0.row,
11938 column: symbol.range.end.0.column,
11939 }),
11940 worktree_id: Default::default(),
11941 path: Default::default(),
11942 signature: Default::default(),
11943 container_name: symbol.container_name.clone(),
11944 };
11945 match &symbol.path {
11946 SymbolLocation::InProject(path) => {
11947 result.worktree_id = path.worktree_id.to_proto();
11948 result.path = path.path.to_proto();
11949 }
11950 SymbolLocation::OutsideProject {
11951 abs_path,
11952 signature,
11953 } => {
11954 result.path = abs_path.to_string_lossy().into_owned();
11955 result.signature = signature.to_vec();
11956 }
11957 }
11958 result
11959 }
11960
11961 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11962 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11963 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11964 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11965
11966 let path = if serialized_symbol.signature.is_empty() {
11967 SymbolLocation::InProject(ProjectPath {
11968 worktree_id,
11969 path: RelPath::from_proto(&serialized_symbol.path)
11970 .context("invalid symbol path")?,
11971 })
11972 } else {
11973 SymbolLocation::OutsideProject {
11974 abs_path: Path::new(&serialized_symbol.path).into(),
11975 signature: serialized_symbol
11976 .signature
11977 .try_into()
11978 .map_err(|_| anyhow!("invalid signature"))?,
11979 }
11980 };
11981
11982 let start = serialized_symbol.start.context("invalid start")?;
11983 let end = serialized_symbol.end.context("invalid end")?;
11984 Ok(CoreSymbol {
11985 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11986 source_worktree_id,
11987 source_language_server_id: LanguageServerId::from_proto(
11988 serialized_symbol.language_server_id,
11989 ),
11990 path,
11991 name: serialized_symbol.name,
11992 range: Unclipped(PointUtf16::new(start.row, start.column))
11993 ..Unclipped(PointUtf16::new(end.row, end.column)),
11994 kind,
11995 container_name: serialized_symbol.container_name,
11996 })
11997 }
11998
11999 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12000 let mut serialized_completion = proto::Completion {
12001 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12002 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12003 new_text: completion.new_text.clone(),
12004 ..proto::Completion::default()
12005 };
12006 match &completion.source {
12007 CompletionSource::Lsp {
12008 insert_range,
12009 server_id,
12010 lsp_completion,
12011 lsp_defaults,
12012 resolved,
12013 } => {
12014 let (old_insert_start, old_insert_end) = insert_range
12015 .as_ref()
12016 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12017 .unzip();
12018
12019 serialized_completion.old_insert_start = old_insert_start;
12020 serialized_completion.old_insert_end = old_insert_end;
12021 serialized_completion.source = proto::completion::Source::Lsp as i32;
12022 serialized_completion.server_id = server_id.0 as u64;
12023 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12024 serialized_completion.lsp_defaults = lsp_defaults
12025 .as_deref()
12026 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12027 serialized_completion.resolved = *resolved;
12028 }
12029 CompletionSource::BufferWord {
12030 word_range,
12031 resolved,
12032 } => {
12033 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12034 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12035 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12036 serialized_completion.resolved = *resolved;
12037 }
12038 CompletionSource::Custom => {
12039 serialized_completion.source = proto::completion::Source::Custom as i32;
12040 serialized_completion.resolved = true;
12041 }
12042 CompletionSource::Dap { sort_text } => {
12043 serialized_completion.source = proto::completion::Source::Dap as i32;
12044 serialized_completion.sort_text = Some(sort_text.clone());
12045 }
12046 }
12047
12048 serialized_completion
12049 }
12050
12051 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12052 let old_replace_start = completion
12053 .old_replace_start
12054 .and_then(deserialize_anchor)
12055 .context("invalid old start")?;
12056 let old_replace_end = completion
12057 .old_replace_end
12058 .and_then(deserialize_anchor)
12059 .context("invalid old end")?;
12060 let insert_range = {
12061 match completion.old_insert_start.zip(completion.old_insert_end) {
12062 Some((start, end)) => {
12063 let start = deserialize_anchor(start).context("invalid insert old start")?;
12064 let end = deserialize_anchor(end).context("invalid insert old end")?;
12065 Some(start..end)
12066 }
12067 None => None,
12068 }
12069 };
12070 Ok(CoreCompletion {
12071 replace_range: old_replace_start..old_replace_end,
12072 new_text: completion.new_text,
12073 source: match proto::completion::Source::from_i32(completion.source) {
12074 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12075 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12076 insert_range,
12077 server_id: LanguageServerId::from_proto(completion.server_id),
12078 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12079 lsp_defaults: completion
12080 .lsp_defaults
12081 .as_deref()
12082 .map(serde_json::from_slice)
12083 .transpose()?,
12084 resolved: completion.resolved,
12085 },
12086 Some(proto::completion::Source::BufferWord) => {
12087 let word_range = completion
12088 .buffer_word_start
12089 .and_then(deserialize_anchor)
12090 .context("invalid buffer word start")?
12091 ..completion
12092 .buffer_word_end
12093 .and_then(deserialize_anchor)
12094 .context("invalid buffer word end")?;
12095 CompletionSource::BufferWord {
12096 word_range,
12097 resolved: completion.resolved,
12098 }
12099 }
12100 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12101 sort_text: completion
12102 .sort_text
12103 .context("expected sort text to exist")?,
12104 },
12105 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12106 },
12107 })
12108 }
12109
12110 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12111 let (kind, lsp_action) = match &action.lsp_action {
12112 LspAction::Action(code_action) => (
12113 proto::code_action::Kind::Action as i32,
12114 serde_json::to_vec(code_action).unwrap(),
12115 ),
12116 LspAction::Command(command) => (
12117 proto::code_action::Kind::Command as i32,
12118 serde_json::to_vec(command).unwrap(),
12119 ),
12120 LspAction::CodeLens(code_lens) => (
12121 proto::code_action::Kind::CodeLens as i32,
12122 serde_json::to_vec(code_lens).unwrap(),
12123 ),
12124 };
12125
12126 proto::CodeAction {
12127 server_id: action.server_id.0 as u64,
12128 start: Some(serialize_anchor(&action.range.start)),
12129 end: Some(serialize_anchor(&action.range.end)),
12130 lsp_action,
12131 kind,
12132 resolved: action.resolved,
12133 }
12134 }
12135
12136 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12137 let start = action
12138 .start
12139 .and_then(deserialize_anchor)
12140 .context("invalid start")?;
12141 let end = action
12142 .end
12143 .and_then(deserialize_anchor)
12144 .context("invalid end")?;
12145 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12146 Some(proto::code_action::Kind::Action) => {
12147 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12148 }
12149 Some(proto::code_action::Kind::Command) => {
12150 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12151 }
12152 Some(proto::code_action::Kind::CodeLens) => {
12153 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12154 }
12155 None => anyhow::bail!("Unknown action kind {}", action.kind),
12156 };
12157 Ok(CodeAction {
12158 server_id: LanguageServerId(action.server_id as usize),
12159 range: start..end,
12160 resolved: action.resolved,
12161 lsp_action,
12162 })
12163 }
12164
12165 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12166 match &formatting_result {
12167 Ok(_) => self.last_formatting_failure = None,
12168 Err(error) => {
12169 let error_string = format!("{error:#}");
12170 log::error!("Formatting failed: {error_string}");
12171 self.last_formatting_failure
12172 .replace(error_string.lines().join(" "));
12173 }
12174 }
12175 }
12176
12177 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12178 self.lsp_server_capabilities.remove(&for_server);
12179 self.semantic_token_config.remove_server_data(for_server);
12180 for lsp_data in self.lsp_data.values_mut() {
12181 lsp_data.remove_server_data(for_server);
12182 }
12183 if let Some(local) = self.as_local_mut() {
12184 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12185 local
12186 .workspace_pull_diagnostics_result_ids
12187 .remove(&for_server);
12188 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12189 buffer_servers.remove(&for_server);
12190 }
12191 }
12192 }
12193
12194 pub fn result_id_for_buffer_pull(
12195 &self,
12196 server_id: LanguageServerId,
12197 buffer_id: BufferId,
12198 registration_id: &Option<SharedString>,
12199 cx: &App,
12200 ) -> Option<SharedString> {
12201 let abs_path = self
12202 .buffer_store
12203 .read(cx)
12204 .get(buffer_id)
12205 .and_then(|b| File::from_dyn(b.read(cx).file()))
12206 .map(|f| f.abs_path(cx))?;
12207 self.as_local()?
12208 .buffer_pull_diagnostics_result_ids
12209 .get(&server_id)?
12210 .get(registration_id)?
12211 .get(&abs_path)?
12212 .clone()
12213 }
12214
12215 /// Gets all result_ids for a workspace diagnostics pull request.
12216 /// 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.
12217 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12218 pub fn result_ids_for_workspace_refresh(
12219 &self,
12220 server_id: LanguageServerId,
12221 registration_id: &Option<SharedString>,
12222 ) -> HashMap<PathBuf, SharedString> {
12223 let Some(local) = self.as_local() else {
12224 return HashMap::default();
12225 };
12226 local
12227 .workspace_pull_diagnostics_result_ids
12228 .get(&server_id)
12229 .into_iter()
12230 .filter_map(|diagnostics| diagnostics.get(registration_id))
12231 .flatten()
12232 .filter_map(|(abs_path, result_id)| {
12233 let result_id = local
12234 .buffer_pull_diagnostics_result_ids
12235 .get(&server_id)
12236 .and_then(|buffer_ids_result_ids| {
12237 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12238 })
12239 .cloned()
12240 .flatten()
12241 .or_else(|| result_id.clone())?;
12242 Some((abs_path.clone(), result_id))
12243 })
12244 .collect()
12245 }
12246
12247 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12248 if let Some(LanguageServerState::Running {
12249 workspace_diagnostics_refresh_tasks,
12250 ..
12251 }) = self
12252 .as_local_mut()
12253 .and_then(|local| local.language_servers.get_mut(&server_id))
12254 {
12255 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12256 diagnostics.refresh_tx.try_send(()).ok();
12257 }
12258 }
12259 }
12260
12261 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12262 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12263 /// which requires refreshing both workspace and document diagnostics.
12264 pub fn pull_document_diagnostics_for_server(
12265 &mut self,
12266 server_id: LanguageServerId,
12267 source_buffer_id: Option<BufferId>,
12268 cx: &mut Context<Self>,
12269 ) -> Shared<Task<()>> {
12270 let Some(local) = self.as_local_mut() else {
12271 return Task::ready(()).shared();
12272 };
12273 let mut buffers_to_refresh = HashSet::default();
12274 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12275 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12276 buffers_to_refresh.insert(*buffer_id);
12277 }
12278 }
12279
12280 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12281 }
12282
12283 pub fn pull_document_diagnostics_for_buffer_edit(
12284 &mut self,
12285 buffer_id: BufferId,
12286 cx: &mut Context<Self>,
12287 ) {
12288 let Some(local) = self.as_local_mut() else {
12289 return;
12290 };
12291 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12292 else {
12293 return;
12294 };
12295 for server_id in languages_servers {
12296 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12297 }
12298 }
12299
12300 fn apply_workspace_diagnostic_report(
12301 &mut self,
12302 server_id: LanguageServerId,
12303 report: lsp::WorkspaceDiagnosticReportResult,
12304 registration_id: Option<SharedString>,
12305 cx: &mut Context<Self>,
12306 ) {
12307 let mut workspace_diagnostics =
12308 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12309 report,
12310 server_id,
12311 registration_id,
12312 );
12313 workspace_diagnostics.retain(|d| match &d.diagnostics {
12314 LspPullDiagnostics::Response {
12315 server_id,
12316 registration_id,
12317 ..
12318 } => self.diagnostic_registration_exists(*server_id, registration_id),
12319 LspPullDiagnostics::Default => false,
12320 });
12321 let mut unchanged_buffers = HashMap::default();
12322 let workspace_diagnostics_updates = workspace_diagnostics
12323 .into_iter()
12324 .filter_map(
12325 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12326 LspPullDiagnostics::Response {
12327 server_id,
12328 uri,
12329 diagnostics,
12330 registration_id,
12331 } => Some((
12332 server_id,
12333 uri,
12334 diagnostics,
12335 workspace_diagnostics.version,
12336 registration_id,
12337 )),
12338 LspPullDiagnostics::Default => None,
12339 },
12340 )
12341 .fold(
12342 HashMap::default(),
12343 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12344 let (result_id, diagnostics) = match diagnostics {
12345 PulledDiagnostics::Unchanged { result_id } => {
12346 unchanged_buffers
12347 .entry(new_registration_id.clone())
12348 .or_insert_with(HashSet::default)
12349 .insert(uri.clone());
12350 (Some(result_id), Vec::new())
12351 }
12352 PulledDiagnostics::Changed {
12353 result_id,
12354 diagnostics,
12355 } => (result_id, diagnostics),
12356 };
12357 let disk_based_sources = Cow::Owned(
12358 self.language_server_adapter_for_id(server_id)
12359 .as_ref()
12360 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12361 .unwrap_or(&[])
12362 .to_vec(),
12363 );
12364
12365 let Some(abs_path) = uri.to_file_path().ok() else {
12366 return acc;
12367 };
12368 let Some((worktree, relative_path)) =
12369 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12370 else {
12371 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12372 return acc;
12373 };
12374 let worktree_id = worktree.read(cx).id();
12375 let project_path = ProjectPath {
12376 worktree_id,
12377 path: relative_path,
12378 };
12379 if let Some(local_lsp_store) = self.as_local_mut() {
12380 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12381 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12382 }
12383 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12384 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12385 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12386 acc.entry(server_id)
12387 .or_insert_with(HashMap::default)
12388 .entry(new_registration_id.clone())
12389 .or_insert_with(Vec::new)
12390 .push(DocumentDiagnosticsUpdate {
12391 server_id,
12392 diagnostics: lsp::PublishDiagnosticsParams {
12393 uri,
12394 diagnostics,
12395 version,
12396 },
12397 result_id: result_id.map(SharedString::new),
12398 disk_based_sources,
12399 registration_id: new_registration_id,
12400 });
12401 }
12402 acc
12403 },
12404 );
12405
12406 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12407 for (registration_id, diagnostic_updates) in diagnostic_updates {
12408 self.merge_lsp_diagnostics(
12409 DiagnosticSourceKind::Pulled,
12410 diagnostic_updates,
12411 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12412 DiagnosticSourceKind::Pulled => {
12413 old_diagnostic.registration_id != registration_id
12414 || unchanged_buffers
12415 .get(&old_diagnostic.registration_id)
12416 .is_some_and(|unchanged_buffers| {
12417 unchanged_buffers.contains(&document_uri)
12418 })
12419 }
12420 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12421 },
12422 cx,
12423 )
12424 .log_err();
12425 }
12426 }
12427 }
12428
12429 fn register_server_capabilities(
12430 &mut self,
12431 server_id: LanguageServerId,
12432 params: lsp::RegistrationParams,
12433 cx: &mut Context<Self>,
12434 ) -> anyhow::Result<()> {
12435 let server = self
12436 .language_server_for_id(server_id)
12437 .with_context(|| format!("no server {server_id} found"))?;
12438 for reg in params.registrations {
12439 match reg.method.as_str() {
12440 "workspace/didChangeWatchedFiles" => {
12441 if let Some(options) = reg.register_options {
12442 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12443 let caps = serde_json::from_value(options)?;
12444 local_lsp_store
12445 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12446 true
12447 } else {
12448 false
12449 };
12450 if notify {
12451 notify_server_capabilities_updated(&server, cx);
12452 }
12453 }
12454 }
12455 "workspace/didChangeConfiguration" => {
12456 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12457 }
12458 "workspace/didChangeWorkspaceFolders" => {
12459 // In this case register options is an empty object, we can ignore it
12460 let caps = lsp::WorkspaceFoldersServerCapabilities {
12461 supported: Some(true),
12462 change_notifications: Some(OneOf::Right(reg.id)),
12463 };
12464 server.update_capabilities(|capabilities| {
12465 capabilities
12466 .workspace
12467 .get_or_insert_default()
12468 .workspace_folders = Some(caps);
12469 });
12470 notify_server_capabilities_updated(&server, cx);
12471 }
12472 "workspace/symbol" => {
12473 let options = parse_register_capabilities(reg)?;
12474 server.update_capabilities(|capabilities| {
12475 capabilities.workspace_symbol_provider = Some(options);
12476 });
12477 notify_server_capabilities_updated(&server, cx);
12478 }
12479 "workspace/fileOperations" => {
12480 if let Some(options) = reg.register_options {
12481 let caps = serde_json::from_value(options)?;
12482 server.update_capabilities(|capabilities| {
12483 capabilities
12484 .workspace
12485 .get_or_insert_default()
12486 .file_operations = Some(caps);
12487 });
12488 notify_server_capabilities_updated(&server, cx);
12489 }
12490 }
12491 "workspace/executeCommand" => {
12492 if let Some(options) = reg.register_options {
12493 let options = serde_json::from_value(options)?;
12494 server.update_capabilities(|capabilities| {
12495 capabilities.execute_command_provider = Some(options);
12496 });
12497 notify_server_capabilities_updated(&server, cx);
12498 }
12499 }
12500 "textDocument/rangeFormatting" => {
12501 let options = parse_register_capabilities(reg)?;
12502 server.update_capabilities(|capabilities| {
12503 capabilities.document_range_formatting_provider = Some(options);
12504 });
12505 notify_server_capabilities_updated(&server, cx);
12506 }
12507 "textDocument/onTypeFormatting" => {
12508 if let Some(options) = reg
12509 .register_options
12510 .map(serde_json::from_value)
12511 .transpose()?
12512 {
12513 server.update_capabilities(|capabilities| {
12514 capabilities.document_on_type_formatting_provider = Some(options);
12515 });
12516 notify_server_capabilities_updated(&server, cx);
12517 }
12518 }
12519 "textDocument/formatting" => {
12520 let options = parse_register_capabilities(reg)?;
12521 server.update_capabilities(|capabilities| {
12522 capabilities.document_formatting_provider = Some(options);
12523 });
12524 notify_server_capabilities_updated(&server, cx);
12525 }
12526 "textDocument/rename" => {
12527 let options = parse_register_capabilities(reg)?;
12528 server.update_capabilities(|capabilities| {
12529 capabilities.rename_provider = Some(options);
12530 });
12531 notify_server_capabilities_updated(&server, cx);
12532 }
12533 "textDocument/inlayHint" => {
12534 let options = parse_register_capabilities(reg)?;
12535 server.update_capabilities(|capabilities| {
12536 capabilities.inlay_hint_provider = Some(options);
12537 });
12538 notify_server_capabilities_updated(&server, cx);
12539 }
12540 "textDocument/documentSymbol" => {
12541 let options = parse_register_capabilities(reg)?;
12542 server.update_capabilities(|capabilities| {
12543 capabilities.document_symbol_provider = Some(options);
12544 });
12545 notify_server_capabilities_updated(&server, cx);
12546 }
12547 "textDocument/codeAction" => {
12548 let options = parse_register_capabilities(reg)?;
12549 let provider = match options {
12550 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12551 OneOf::Right(caps) => caps,
12552 };
12553 server.update_capabilities(|capabilities| {
12554 capabilities.code_action_provider = Some(provider);
12555 });
12556 notify_server_capabilities_updated(&server, cx);
12557 }
12558 "textDocument/definition" => {
12559 let options = parse_register_capabilities(reg)?;
12560 server.update_capabilities(|capabilities| {
12561 capabilities.definition_provider = Some(options);
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 "textDocument/completion" => {
12566 if let Some(caps) = reg
12567 .register_options
12568 .map(serde_json::from_value::<CompletionOptions>)
12569 .transpose()?
12570 {
12571 server.update_capabilities(|capabilities| {
12572 capabilities.completion_provider = Some(caps.clone());
12573 });
12574
12575 if let Some(local) = self.as_local() {
12576 let mut buffers_with_language_server = Vec::new();
12577 for handle in self.buffer_store.read(cx).buffers() {
12578 let buffer_id = handle.read(cx).remote_id();
12579 if local
12580 .buffers_opened_in_servers
12581 .get(&buffer_id)
12582 .filter(|s| s.contains(&server_id))
12583 .is_some()
12584 {
12585 buffers_with_language_server.push(handle);
12586 }
12587 }
12588 let triggers = caps
12589 .trigger_characters
12590 .unwrap_or_default()
12591 .into_iter()
12592 .collect::<BTreeSet<_>>();
12593 for handle in buffers_with_language_server {
12594 let triggers = triggers.clone();
12595 let _ = handle.update(cx, move |buffer, cx| {
12596 buffer.set_completion_triggers(server_id, triggers, cx);
12597 });
12598 }
12599 }
12600 notify_server_capabilities_updated(&server, cx);
12601 }
12602 }
12603 "textDocument/hover" => {
12604 let options = parse_register_capabilities(reg)?;
12605 let provider = match options {
12606 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12607 OneOf::Right(caps) => caps,
12608 };
12609 server.update_capabilities(|capabilities| {
12610 capabilities.hover_provider = Some(provider);
12611 });
12612 notify_server_capabilities_updated(&server, cx);
12613 }
12614 "textDocument/signatureHelp" => {
12615 if let Some(caps) = reg
12616 .register_options
12617 .map(serde_json::from_value)
12618 .transpose()?
12619 {
12620 server.update_capabilities(|capabilities| {
12621 capabilities.signature_help_provider = Some(caps);
12622 });
12623 notify_server_capabilities_updated(&server, cx);
12624 }
12625 }
12626 "textDocument/didChange" => {
12627 if let Some(sync_kind) = reg
12628 .register_options
12629 .and_then(|opts| opts.get("syncKind").cloned())
12630 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12631 .transpose()?
12632 {
12633 server.update_capabilities(|capabilities| {
12634 let mut sync_options =
12635 Self::take_text_document_sync_options(capabilities);
12636 sync_options.change = Some(sync_kind);
12637 capabilities.text_document_sync =
12638 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12639 });
12640 notify_server_capabilities_updated(&server, cx);
12641 }
12642 }
12643 "textDocument/didSave" => {
12644 if let Some(include_text) = reg
12645 .register_options
12646 .map(|opts| {
12647 let transpose = opts
12648 .get("includeText")
12649 .cloned()
12650 .map(serde_json::from_value::<Option<bool>>)
12651 .transpose();
12652 match transpose {
12653 Ok(value) => Ok(value.flatten()),
12654 Err(e) => Err(e),
12655 }
12656 })
12657 .transpose()?
12658 {
12659 server.update_capabilities(|capabilities| {
12660 let mut sync_options =
12661 Self::take_text_document_sync_options(capabilities);
12662 sync_options.save =
12663 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12664 include_text,
12665 }));
12666 capabilities.text_document_sync =
12667 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12668 });
12669 notify_server_capabilities_updated(&server, cx);
12670 }
12671 }
12672 "textDocument/codeLens" => {
12673 if let Some(caps) = reg
12674 .register_options
12675 .map(serde_json::from_value)
12676 .transpose()?
12677 {
12678 server.update_capabilities(|capabilities| {
12679 capabilities.code_lens_provider = Some(caps);
12680 });
12681 notify_server_capabilities_updated(&server, cx);
12682 }
12683 }
12684 "textDocument/diagnostic" => {
12685 if let Some(caps) = reg
12686 .register_options
12687 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12688 .transpose()?
12689 {
12690 let local = self
12691 .as_local_mut()
12692 .context("Expected LSP Store to be local")?;
12693 let state = local
12694 .language_servers
12695 .get_mut(&server_id)
12696 .context("Could not obtain Language Servers state")?;
12697 local
12698 .language_server_dynamic_registrations
12699 .entry(server_id)
12700 .or_default()
12701 .diagnostics
12702 .insert(Some(reg.id.clone()), caps.clone());
12703
12704 let supports_workspace_diagnostics =
12705 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12706 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12707 diagnostic_options.workspace_diagnostics
12708 }
12709 DiagnosticServerCapabilities::RegistrationOptions(
12710 diagnostic_registration_options,
12711 ) => {
12712 diagnostic_registration_options
12713 .diagnostic_options
12714 .workspace_diagnostics
12715 }
12716 };
12717
12718 if supports_workspace_diagnostics(&caps) {
12719 if let LanguageServerState::Running {
12720 workspace_diagnostics_refresh_tasks,
12721 ..
12722 } = state
12723 && let Some(task) = lsp_workspace_diagnostics_refresh(
12724 Some(reg.id.clone()),
12725 caps.clone(),
12726 server.clone(),
12727 cx,
12728 )
12729 {
12730 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12731 }
12732 }
12733
12734 server.update_capabilities(|capabilities| {
12735 capabilities.diagnostic_provider = Some(caps);
12736 });
12737
12738 notify_server_capabilities_updated(&server, cx);
12739
12740 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12741 }
12742 }
12743 "textDocument/documentColor" => {
12744 let options = parse_register_capabilities(reg)?;
12745 let provider = match options {
12746 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12747 OneOf::Right(caps) => caps,
12748 };
12749 server.update_capabilities(|capabilities| {
12750 capabilities.color_provider = Some(provider);
12751 });
12752 notify_server_capabilities_updated(&server, cx);
12753 }
12754 "textDocument/foldingRange" => {
12755 let options = parse_register_capabilities(reg)?;
12756 let provider = match options {
12757 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12758 OneOf::Right(caps) => caps,
12759 };
12760 server.update_capabilities(|capabilities| {
12761 capabilities.folding_range_provider = Some(provider);
12762 });
12763 notify_server_capabilities_updated(&server, cx);
12764 }
12765 _ => log::warn!("unhandled capability registration: {reg:?}"),
12766 }
12767 }
12768
12769 Ok(())
12770 }
12771
12772 fn unregister_server_capabilities(
12773 &mut self,
12774 server_id: LanguageServerId,
12775 params: lsp::UnregistrationParams,
12776 cx: &mut Context<Self>,
12777 ) -> anyhow::Result<()> {
12778 let server = self
12779 .language_server_for_id(server_id)
12780 .with_context(|| format!("no server {server_id} found"))?;
12781 for unreg in params.unregisterations.iter() {
12782 match unreg.method.as_str() {
12783 "workspace/didChangeWatchedFiles" => {
12784 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12785 local_lsp_store
12786 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12787 true
12788 } else {
12789 false
12790 };
12791 if notify {
12792 notify_server_capabilities_updated(&server, cx);
12793 }
12794 }
12795 "workspace/didChangeConfiguration" => {
12796 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12797 }
12798 "workspace/didChangeWorkspaceFolders" => {
12799 server.update_capabilities(|capabilities| {
12800 capabilities
12801 .workspace
12802 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12803 workspace_folders: None,
12804 file_operations: None,
12805 })
12806 .workspace_folders = None;
12807 });
12808 notify_server_capabilities_updated(&server, cx);
12809 }
12810 "workspace/symbol" => {
12811 server.update_capabilities(|capabilities| {
12812 capabilities.workspace_symbol_provider = None
12813 });
12814 notify_server_capabilities_updated(&server, cx);
12815 }
12816 "workspace/fileOperations" => {
12817 server.update_capabilities(|capabilities| {
12818 capabilities
12819 .workspace
12820 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12821 workspace_folders: None,
12822 file_operations: None,
12823 })
12824 .file_operations = None;
12825 });
12826 notify_server_capabilities_updated(&server, cx);
12827 }
12828 "workspace/executeCommand" => {
12829 server.update_capabilities(|capabilities| {
12830 capabilities.execute_command_provider = None;
12831 });
12832 notify_server_capabilities_updated(&server, cx);
12833 }
12834 "textDocument/rangeFormatting" => {
12835 server.update_capabilities(|capabilities| {
12836 capabilities.document_range_formatting_provider = None
12837 });
12838 notify_server_capabilities_updated(&server, cx);
12839 }
12840 "textDocument/onTypeFormatting" => {
12841 server.update_capabilities(|capabilities| {
12842 capabilities.document_on_type_formatting_provider = None;
12843 });
12844 notify_server_capabilities_updated(&server, cx);
12845 }
12846 "textDocument/formatting" => {
12847 server.update_capabilities(|capabilities| {
12848 capabilities.document_formatting_provider = None;
12849 });
12850 notify_server_capabilities_updated(&server, cx);
12851 }
12852 "textDocument/rename" => {
12853 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12854 notify_server_capabilities_updated(&server, cx);
12855 }
12856 "textDocument/codeAction" => {
12857 server.update_capabilities(|capabilities| {
12858 capabilities.code_action_provider = None;
12859 });
12860 notify_server_capabilities_updated(&server, cx);
12861 }
12862 "textDocument/definition" => {
12863 server.update_capabilities(|capabilities| {
12864 capabilities.definition_provider = None;
12865 });
12866 notify_server_capabilities_updated(&server, cx);
12867 }
12868 "textDocument/completion" => {
12869 server.update_capabilities(|capabilities| {
12870 capabilities.completion_provider = None;
12871 });
12872 notify_server_capabilities_updated(&server, cx);
12873 }
12874 "textDocument/hover" => {
12875 server.update_capabilities(|capabilities| {
12876 capabilities.hover_provider = None;
12877 });
12878 notify_server_capabilities_updated(&server, cx);
12879 }
12880 "textDocument/signatureHelp" => {
12881 server.update_capabilities(|capabilities| {
12882 capabilities.signature_help_provider = None;
12883 });
12884 notify_server_capabilities_updated(&server, cx);
12885 }
12886 "textDocument/didChange" => {
12887 server.update_capabilities(|capabilities| {
12888 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12889 sync_options.change = None;
12890 capabilities.text_document_sync =
12891 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12892 });
12893 notify_server_capabilities_updated(&server, cx);
12894 }
12895 "textDocument/didSave" => {
12896 server.update_capabilities(|capabilities| {
12897 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12898 sync_options.save = None;
12899 capabilities.text_document_sync =
12900 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12901 });
12902 notify_server_capabilities_updated(&server, cx);
12903 }
12904 "textDocument/codeLens" => {
12905 server.update_capabilities(|capabilities| {
12906 capabilities.code_lens_provider = None;
12907 });
12908 notify_server_capabilities_updated(&server, cx);
12909 }
12910 "textDocument/diagnostic" => {
12911 let local = self
12912 .as_local_mut()
12913 .context("Expected LSP Store to be local")?;
12914
12915 let state = local
12916 .language_servers
12917 .get_mut(&server_id)
12918 .context("Could not obtain Language Servers state")?;
12919 let registrations = local
12920 .language_server_dynamic_registrations
12921 .get_mut(&server_id)
12922 .with_context(|| {
12923 format!("Expected dynamic registration to exist for server {server_id}")
12924 })?;
12925 registrations.diagnostics
12926 .remove(&Some(unreg.id.clone()))
12927 .with_context(|| format!(
12928 "Attempted to unregister non-existent diagnostic registration with ID {}",
12929 unreg.id)
12930 )?;
12931 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12932
12933 if let LanguageServerState::Running {
12934 workspace_diagnostics_refresh_tasks,
12935 ..
12936 } = state
12937 {
12938 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12939 }
12940
12941 self.clear_unregistered_diagnostics(
12942 server_id,
12943 SharedString::from(unreg.id.clone()),
12944 cx,
12945 )?;
12946
12947 if removed_last_diagnostic_provider {
12948 server.update_capabilities(|capabilities| {
12949 debug_assert!(capabilities.diagnostic_provider.is_some());
12950 capabilities.diagnostic_provider = None;
12951 });
12952 }
12953
12954 notify_server_capabilities_updated(&server, cx);
12955 }
12956 "textDocument/documentColor" => {
12957 server.update_capabilities(|capabilities| {
12958 capabilities.color_provider = None;
12959 });
12960 notify_server_capabilities_updated(&server, cx);
12961 }
12962 "textDocument/foldingRange" => {
12963 server.update_capabilities(|capabilities| {
12964 capabilities.folding_range_provider = None;
12965 });
12966 notify_server_capabilities_updated(&server, cx);
12967 }
12968 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12969 }
12970 }
12971
12972 Ok(())
12973 }
12974
12975 fn clear_unregistered_diagnostics(
12976 &mut self,
12977 server_id: LanguageServerId,
12978 cleared_registration_id: SharedString,
12979 cx: &mut Context<Self>,
12980 ) -> anyhow::Result<()> {
12981 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12982
12983 self.buffer_store.update(cx, |buffer_store, cx| {
12984 for buffer_handle in buffer_store.buffers() {
12985 let buffer = buffer_handle.read(cx);
12986 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12987 let Some(abs_path) = abs_path else {
12988 continue;
12989 };
12990 affected_abs_paths.insert(abs_path);
12991 }
12992 });
12993
12994 let local = self.as_local().context("Expected LSP Store to be local")?;
12995 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12996 let Some(worktree) = self
12997 .worktree_store
12998 .read(cx)
12999 .worktree_for_id(*worktree_id, cx)
13000 else {
13001 continue;
13002 };
13003
13004 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13005 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13006 let has_matching_registration =
13007 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13008 entry.diagnostic.registration_id.as_ref()
13009 == Some(&cleared_registration_id)
13010 });
13011 if has_matching_registration {
13012 let abs_path = worktree.read(cx).absolutize(rel_path);
13013 affected_abs_paths.insert(abs_path);
13014 }
13015 }
13016 }
13017 }
13018
13019 if affected_abs_paths.is_empty() {
13020 return Ok(());
13021 }
13022
13023 // Send a fake diagnostic update which clears the state for the registration ID
13024 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13025 affected_abs_paths
13026 .into_iter()
13027 .map(|abs_path| DocumentDiagnosticsUpdate {
13028 diagnostics: DocumentDiagnostics {
13029 diagnostics: Vec::new(),
13030 document_abs_path: abs_path,
13031 version: None,
13032 },
13033 result_id: None,
13034 registration_id: Some(cleared_registration_id.clone()),
13035 server_id,
13036 disk_based_sources: Cow::Borrowed(&[]),
13037 })
13038 .collect();
13039
13040 let merge_registration_id = cleared_registration_id.clone();
13041 self.merge_diagnostic_entries(
13042 clears,
13043 move |_, diagnostic, _| {
13044 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13045 diagnostic.registration_id != Some(merge_registration_id.clone())
13046 } else {
13047 true
13048 }
13049 },
13050 cx,
13051 )?;
13052
13053 Ok(())
13054 }
13055
13056 async fn deduplicate_range_based_lsp_requests<T>(
13057 lsp_store: &Entity<Self>,
13058 server_id: Option<LanguageServerId>,
13059 lsp_request_id: LspRequestId,
13060 proto_request: &T::ProtoRequest,
13061 range: Range<Anchor>,
13062 cx: &mut AsyncApp,
13063 ) -> Result<()>
13064 where
13065 T: LspCommand,
13066 T::ProtoRequest: proto::LspRequestMessage,
13067 {
13068 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13069 let version = deserialize_version(proto_request.buffer_version());
13070 let buffer = lsp_store.update(cx, |this, cx| {
13071 this.buffer_store.read(cx).get_existing(buffer_id)
13072 })?;
13073 buffer
13074 .update(cx, |buffer, _| buffer.wait_for_version(version))
13075 .await?;
13076 lsp_store.update(cx, |lsp_store, cx| {
13077 let buffer_snapshot = buffer.read(cx).snapshot();
13078 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13079 let chunks_queried_for = lsp_data
13080 .inlay_hints
13081 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13082 .collect::<Vec<_>>();
13083 match chunks_queried_for.as_slice() {
13084 &[chunk] => {
13085 let key = LspKey {
13086 request_type: TypeId::of::<T>(),
13087 server_queried: server_id,
13088 };
13089 let previous_request = lsp_data
13090 .chunk_lsp_requests
13091 .entry(key)
13092 .or_default()
13093 .insert(chunk, lsp_request_id);
13094 if let Some((previous_request, running_requests)) =
13095 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13096 {
13097 running_requests.remove(&previous_request);
13098 }
13099 }
13100 _ambiguous_chunks => {
13101 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13102 // there, a buffer version-based check will be performed and outdated requests discarded.
13103 }
13104 }
13105 anyhow::Ok(())
13106 })?;
13107
13108 Ok(())
13109 }
13110
13111 async fn query_lsp_locally<T>(
13112 lsp_store: Entity<Self>,
13113 for_server_id: Option<LanguageServerId>,
13114 sender_id: proto::PeerId,
13115 lsp_request_id: LspRequestId,
13116 proto_request: T::ProtoRequest,
13117 position: Option<Anchor>,
13118 cx: &mut AsyncApp,
13119 ) -> Result<()>
13120 where
13121 T: LspCommand + Clone,
13122 T::ProtoRequest: proto::LspRequestMessage,
13123 <T::ProtoRequest as proto::RequestMessage>::Response:
13124 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13125 {
13126 let (buffer_version, buffer) =
13127 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13128 let request =
13129 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13130 let key = LspKey {
13131 request_type: TypeId::of::<T>(),
13132 server_queried: for_server_id,
13133 };
13134 lsp_store.update(cx, |lsp_store, cx| {
13135 let request_task = match for_server_id {
13136 Some(server_id) => {
13137 let server_task = lsp_store.request_lsp(
13138 buffer.clone(),
13139 LanguageServerToQuery::Other(server_id),
13140 request.clone(),
13141 cx,
13142 );
13143 cx.background_spawn(async move {
13144 let mut responses = Vec::new();
13145 match server_task.await {
13146 Ok(response) => responses.push((server_id, response)),
13147 // rust-analyzer likes to error with this when its still loading up
13148 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13149 Err(e) => log::error!(
13150 "Error handling response for request {request:?}: {e:#}"
13151 ),
13152 }
13153 responses
13154 })
13155 }
13156 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13157 };
13158 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13159 if T::ProtoRequest::stop_previous_requests() {
13160 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13161 lsp_requests.clear();
13162 }
13163 }
13164 lsp_data.lsp_requests.entry(key).or_default().insert(
13165 lsp_request_id,
13166 cx.spawn(async move |lsp_store, cx| {
13167 let response = request_task.await;
13168 lsp_store
13169 .update(cx, |lsp_store, cx| {
13170 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13171 {
13172 let response = response
13173 .into_iter()
13174 .map(|(server_id, response)| {
13175 (
13176 server_id.to_proto(),
13177 T::response_to_proto(
13178 response,
13179 lsp_store,
13180 sender_id,
13181 &buffer_version,
13182 cx,
13183 )
13184 .into(),
13185 )
13186 })
13187 .collect::<HashMap<_, _>>();
13188 match client.send_lsp_response::<T::ProtoRequest>(
13189 project_id,
13190 lsp_request_id,
13191 response,
13192 ) {
13193 Ok(()) => {}
13194 Err(e) => {
13195 log::error!("Failed to send LSP response: {e:#}",)
13196 }
13197 }
13198 }
13199 })
13200 .ok();
13201 }),
13202 );
13203 });
13204 Ok(())
13205 }
13206
13207 async fn wait_for_buffer_version<T>(
13208 lsp_store: &Entity<Self>,
13209 proto_request: &T::ProtoRequest,
13210 cx: &mut AsyncApp,
13211 ) -> Result<(Global, Entity<Buffer>)>
13212 where
13213 T: LspCommand,
13214 T::ProtoRequest: proto::LspRequestMessage,
13215 {
13216 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13217 let version = deserialize_version(proto_request.buffer_version());
13218 let buffer = lsp_store.update(cx, |this, cx| {
13219 this.buffer_store.read(cx).get_existing(buffer_id)
13220 })?;
13221 buffer
13222 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13223 .await?;
13224 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13225 Ok((buffer_version, buffer))
13226 }
13227
13228 fn take_text_document_sync_options(
13229 capabilities: &mut lsp::ServerCapabilities,
13230 ) -> lsp::TextDocumentSyncOptions {
13231 match capabilities.text_document_sync.take() {
13232 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13233 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13234 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13235 sync_options.change = Some(sync_kind);
13236 sync_options
13237 }
13238 None => lsp::TextDocumentSyncOptions::default(),
13239 }
13240 }
13241
13242 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13243 self.downstream_client.clone()
13244 }
13245
13246 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13247 self.worktree_store.clone()
13248 }
13249
13250 /// Gets what's stored in the LSP data for the given buffer.
13251 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13252 self.lsp_data.get_mut(&buffer_id)
13253 }
13254
13255 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13256 /// new [`BufferLspData`] will be created to replace the previous state.
13257 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13258 let (buffer_id, buffer_version) =
13259 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13260 let lsp_data = self
13261 .lsp_data
13262 .entry(buffer_id)
13263 .or_insert_with(|| BufferLspData::new(buffer, cx));
13264 if buffer_version.changed_since(&lsp_data.buffer_version) {
13265 // To send delta requests for semantic tokens, the previous tokens
13266 // need to be kept between buffer changes.
13267 let semantic_tokens = lsp_data.semantic_tokens.take();
13268 *lsp_data = BufferLspData::new(buffer, cx);
13269 lsp_data.semantic_tokens = semantic_tokens;
13270 }
13271 lsp_data
13272 }
13273}
13274
13275// Registration with registerOptions as null, should fallback to true.
13276// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13277fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13278 reg: lsp::Registration,
13279) -> Result<OneOf<bool, T>> {
13280 Ok(match reg.register_options {
13281 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13282 None => OneOf::Left(true),
13283 })
13284}
13285
13286fn subscribe_to_binary_statuses(
13287 languages: &Arc<LanguageRegistry>,
13288 cx: &mut Context<'_, LspStore>,
13289) -> Task<()> {
13290 let mut server_statuses = languages.language_server_binary_statuses();
13291 cx.spawn(async move |lsp_store, cx| {
13292 while let Some((server_name, binary_status)) = server_statuses.next().await {
13293 if lsp_store
13294 .update(cx, |_, cx| {
13295 let mut message = None;
13296 let binary_status = match binary_status {
13297 BinaryStatus::None => proto::ServerBinaryStatus::None,
13298 BinaryStatus::CheckingForUpdate => {
13299 proto::ServerBinaryStatus::CheckingForUpdate
13300 }
13301 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13302 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13303 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13304 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13305 BinaryStatus::Failed { error } => {
13306 message = Some(error);
13307 proto::ServerBinaryStatus::Failed
13308 }
13309 };
13310 cx.emit(LspStoreEvent::LanguageServerUpdate {
13311 // Binary updates are about the binary that might not have any language server id at that point.
13312 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13313 language_server_id: LanguageServerId(0),
13314 name: Some(server_name),
13315 message: proto::update_language_server::Variant::StatusUpdate(
13316 proto::StatusUpdate {
13317 message,
13318 status: Some(proto::status_update::Status::Binary(
13319 binary_status as i32,
13320 )),
13321 },
13322 ),
13323 });
13324 })
13325 .is_err()
13326 {
13327 break;
13328 }
13329 }
13330 })
13331}
13332
13333fn lsp_workspace_diagnostics_refresh(
13334 registration_id: Option<String>,
13335 options: DiagnosticServerCapabilities,
13336 server: Arc<LanguageServer>,
13337 cx: &mut Context<'_, LspStore>,
13338) -> Option<WorkspaceRefreshTask> {
13339 let identifier = workspace_diagnostic_identifier(&options)?;
13340 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13341
13342 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13343 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13344 refresh_tx.try_send(()).ok();
13345
13346 let request_timeout = ProjectSettings::get_global(cx)
13347 .global_lsp_settings
13348 .get_request_timeout();
13349
13350 // 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.
13351 // This allows users to increase the duration if need be
13352 let timeout = if request_timeout != Duration::ZERO {
13353 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13354 } else {
13355 request_timeout
13356 };
13357
13358 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13359 let mut attempts = 0;
13360 let max_attempts = 50;
13361 let mut requests = 0;
13362
13363 loop {
13364 let Some(()) = refresh_rx.recv().await else {
13365 return;
13366 };
13367
13368 'request: loop {
13369 requests += 1;
13370 if attempts > max_attempts {
13371 log::error!(
13372 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13373 );
13374 return;
13375 }
13376 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13377 cx.background_executor()
13378 .timer(Duration::from_millis(backoff_millis))
13379 .await;
13380 attempts += 1;
13381
13382 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13383 lsp_store
13384 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13385 .into_iter()
13386 .filter_map(|(abs_path, result_id)| {
13387 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13388 Some(lsp::PreviousResultId {
13389 uri,
13390 value: result_id.to_string(),
13391 })
13392 })
13393 .collect()
13394 }) else {
13395 return;
13396 };
13397
13398 let token = if let Some(registration_id) = ®istration_id {
13399 format!(
13400 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13401 server.server_id(),
13402 )
13403 } else {
13404 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13405 };
13406
13407 progress_rx.try_recv().ok();
13408 let timer = server.request_timer(timeout).fuse();
13409 let progress = pin!(progress_rx.recv().fuse());
13410 let response_result = server
13411 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13412 lsp::WorkspaceDiagnosticParams {
13413 previous_result_ids,
13414 identifier: identifier.clone(),
13415 work_done_progress_params: Default::default(),
13416 partial_result_params: lsp::PartialResultParams {
13417 partial_result_token: Some(lsp::ProgressToken::String(token)),
13418 },
13419 },
13420 select(timer, progress).then(|either| match either {
13421 Either::Left((message, ..)) => ready(message).left_future(),
13422 Either::Right(..) => pending::<String>().right_future(),
13423 }),
13424 )
13425 .await;
13426
13427 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13428 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13429 match response_result {
13430 ConnectionResult::Timeout => {
13431 log::error!("Timeout during workspace diagnostics pull");
13432 continue 'request;
13433 }
13434 ConnectionResult::ConnectionReset => {
13435 log::error!("Server closed a workspace diagnostics pull request");
13436 continue 'request;
13437 }
13438 ConnectionResult::Result(Err(e)) => {
13439 log::error!("Error during workspace diagnostics pull: {e:#}");
13440 break 'request;
13441 }
13442 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13443 attempts = 0;
13444 if lsp_store
13445 .update(cx, |lsp_store, cx| {
13446 lsp_store.apply_workspace_diagnostic_report(
13447 server.server_id(),
13448 pulled_diagnostics,
13449 registration_id_shared.clone(),
13450 cx,
13451 )
13452 })
13453 .is_err()
13454 {
13455 return;
13456 }
13457 break 'request;
13458 }
13459 }
13460 }
13461 }
13462 });
13463
13464 Some(WorkspaceRefreshTask {
13465 refresh_tx,
13466 progress_tx,
13467 task: workspace_query_language_server,
13468 })
13469}
13470
13471fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13472 match &options {
13473 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13474 .identifier
13475 .as_deref()
13476 .map(SharedString::new),
13477 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13478 let diagnostic_options = ®istration_options.diagnostic_options;
13479 diagnostic_options
13480 .identifier
13481 .as_deref()
13482 .map(SharedString::new)
13483 }
13484 }
13485}
13486
13487fn workspace_diagnostic_identifier(
13488 options: &DiagnosticServerCapabilities,
13489) -> Option<Option<String>> {
13490 match &options {
13491 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13492 if !diagnostic_options.workspace_diagnostics {
13493 return None;
13494 }
13495 Some(diagnostic_options.identifier.clone())
13496 }
13497 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13498 let diagnostic_options = ®istration_options.diagnostic_options;
13499 if !diagnostic_options.workspace_diagnostics {
13500 return None;
13501 }
13502 Some(diagnostic_options.identifier.clone())
13503 }
13504 }
13505}
13506
13507fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13508 let CompletionSource::BufferWord {
13509 word_range,
13510 resolved,
13511 } = &mut completion.source
13512 else {
13513 return;
13514 };
13515 if *resolved {
13516 return;
13517 }
13518
13519 if completion.new_text
13520 != snapshot
13521 .text_for_range(word_range.clone())
13522 .collect::<String>()
13523 {
13524 return;
13525 }
13526
13527 let mut offset = 0;
13528 for chunk in snapshot.chunks(word_range.clone(), true) {
13529 let end_offset = offset + chunk.text.len();
13530 if let Some(highlight_id) = chunk.syntax_highlight_id {
13531 completion
13532 .label
13533 .runs
13534 .push((offset..end_offset, highlight_id));
13535 }
13536 offset = end_offset;
13537 }
13538 *resolved = true;
13539}
13540
13541impl EventEmitter<LspStoreEvent> for LspStore {}
13542
13543fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13544 hover
13545 .contents
13546 .retain(|hover_block| !hover_block.text.trim().is_empty());
13547 if hover.contents.is_empty() {
13548 None
13549 } else {
13550 Some(hover)
13551 }
13552}
13553
13554async fn populate_labels_for_completions(
13555 new_completions: Vec<CoreCompletion>,
13556 language: Option<Arc<Language>>,
13557 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13558) -> Vec<Completion> {
13559 let lsp_completions = new_completions
13560 .iter()
13561 .filter_map(|new_completion| {
13562 new_completion
13563 .source
13564 .lsp_completion(true)
13565 .map(|lsp_completion| lsp_completion.into_owned())
13566 })
13567 .collect::<Vec<_>>();
13568
13569 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13570 lsp_adapter
13571 .labels_for_completions(&lsp_completions, language)
13572 .await
13573 .log_err()
13574 .unwrap_or_default()
13575 } else {
13576 Vec::new()
13577 }
13578 .into_iter()
13579 .fuse();
13580
13581 let mut completions = Vec::new();
13582 for completion in new_completions {
13583 match completion.source.lsp_completion(true) {
13584 Some(lsp_completion) => {
13585 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13586
13587 let mut label = labels.next().flatten().unwrap_or_else(|| {
13588 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13589 });
13590 ensure_uniform_list_compatible_label(&mut label);
13591 completions.push(Completion {
13592 label,
13593 documentation,
13594 replace_range: completion.replace_range,
13595 new_text: completion.new_text,
13596 insert_text_mode: lsp_completion.insert_text_mode,
13597 source: completion.source,
13598 icon_path: None,
13599 confirm: None,
13600 match_start: None,
13601 snippet_deduplication_key: None,
13602 });
13603 }
13604 None => {
13605 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13606 ensure_uniform_list_compatible_label(&mut label);
13607 completions.push(Completion {
13608 label,
13609 documentation: None,
13610 replace_range: completion.replace_range,
13611 new_text: completion.new_text,
13612 source: completion.source,
13613 insert_text_mode: None,
13614 icon_path: None,
13615 confirm: None,
13616 match_start: None,
13617 snippet_deduplication_key: None,
13618 });
13619 }
13620 }
13621 }
13622 completions
13623}
13624
13625#[derive(Debug)]
13626pub enum LanguageServerToQuery {
13627 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13628 FirstCapable,
13629 /// Query a specific language server.
13630 Other(LanguageServerId),
13631}
13632
13633#[derive(Default)]
13634struct RenamePathsWatchedForServer {
13635 did_rename: Vec<RenameActionPredicate>,
13636 will_rename: Vec<RenameActionPredicate>,
13637}
13638
13639impl RenamePathsWatchedForServer {
13640 fn with_did_rename_patterns(
13641 mut self,
13642 did_rename: Option<&FileOperationRegistrationOptions>,
13643 ) -> Self {
13644 if let Some(did_rename) = did_rename {
13645 self.did_rename = did_rename
13646 .filters
13647 .iter()
13648 .filter_map(|filter| filter.try_into().log_err())
13649 .collect();
13650 }
13651 self
13652 }
13653 fn with_will_rename_patterns(
13654 mut self,
13655 will_rename: Option<&FileOperationRegistrationOptions>,
13656 ) -> Self {
13657 if let Some(will_rename) = will_rename {
13658 self.will_rename = will_rename
13659 .filters
13660 .iter()
13661 .filter_map(|filter| filter.try_into().log_err())
13662 .collect();
13663 }
13664 self
13665 }
13666
13667 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13668 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13669 }
13670 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13671 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13672 }
13673}
13674
13675impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13676 type Error = globset::Error;
13677 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13678 Ok(Self {
13679 kind: ops.pattern.matches.clone(),
13680 glob: GlobBuilder::new(&ops.pattern.glob)
13681 .case_insensitive(
13682 ops.pattern
13683 .options
13684 .as_ref()
13685 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13686 )
13687 .build()?
13688 .compile_matcher(),
13689 })
13690 }
13691}
13692struct RenameActionPredicate {
13693 glob: GlobMatcher,
13694 kind: Option<FileOperationPatternKind>,
13695}
13696
13697impl RenameActionPredicate {
13698 // Returns true if language server should be notified
13699 fn eval(&self, path: &str, is_dir: bool) -> bool {
13700 self.kind.as_ref().is_none_or(|kind| {
13701 let expected_kind = if is_dir {
13702 FileOperationPatternKind::Folder
13703 } else {
13704 FileOperationPatternKind::File
13705 };
13706 kind == &expected_kind
13707 }) && self.glob.is_match(path)
13708 }
13709}
13710
13711#[derive(Default)]
13712struct LanguageServerWatchedPaths {
13713 worktree_paths: HashMap<WorktreeId, GlobSet>,
13714 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13715}
13716
13717#[derive(Default)]
13718struct LanguageServerWatchedPathsBuilder {
13719 worktree_paths: HashMap<WorktreeId, GlobSet>,
13720 abs_paths: HashMap<Arc<Path>, GlobSet>,
13721}
13722
13723impl LanguageServerWatchedPathsBuilder {
13724 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13725 self.worktree_paths.insert(worktree_id, glob_set);
13726 }
13727 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13728 self.abs_paths.insert(path, glob_set);
13729 }
13730 fn build(
13731 self,
13732 fs: Arc<dyn Fs>,
13733 language_server_id: LanguageServerId,
13734 cx: &mut Context<LspStore>,
13735 ) -> LanguageServerWatchedPaths {
13736 let lsp_store = cx.weak_entity();
13737
13738 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13739 let abs_paths = self
13740 .abs_paths
13741 .into_iter()
13742 .map(|(abs_path, globset)| {
13743 let task = cx.spawn({
13744 let abs_path = abs_path.clone();
13745 let fs = fs.clone();
13746
13747 let lsp_store = lsp_store.clone();
13748 async move |_, cx| {
13749 maybe!(async move {
13750 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13751 while let Some(update) = push_updates.0.next().await {
13752 let action = lsp_store
13753 .update(cx, |this, _| {
13754 let Some(local) = this.as_local() else {
13755 return ControlFlow::Break(());
13756 };
13757 let Some(watcher) = local
13758 .language_server_watched_paths
13759 .get(&language_server_id)
13760 else {
13761 return ControlFlow::Break(());
13762 };
13763 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13764 "Watched abs path is not registered with a watcher",
13765 );
13766 let matching_entries = update
13767 .into_iter()
13768 .filter(|event| globs.is_match(&event.path))
13769 .collect::<Vec<_>>();
13770 this.lsp_notify_abs_paths_changed(
13771 language_server_id,
13772 matching_entries,
13773 );
13774 ControlFlow::Continue(())
13775 })
13776 .ok()?;
13777
13778 if action.is_break() {
13779 break;
13780 }
13781 }
13782 Some(())
13783 })
13784 .await;
13785 }
13786 });
13787 (abs_path, (globset, task))
13788 })
13789 .collect();
13790 LanguageServerWatchedPaths {
13791 worktree_paths: self.worktree_paths,
13792 abs_paths,
13793 }
13794 }
13795}
13796
13797struct LspBufferSnapshot {
13798 version: i32,
13799 snapshot: TextBufferSnapshot,
13800}
13801
13802/// A prompt requested by LSP server.
13803#[derive(Clone, Debug)]
13804pub struct LanguageServerPromptRequest {
13805 pub id: usize,
13806 pub level: PromptLevel,
13807 pub message: String,
13808 pub actions: Vec<MessageActionItem>,
13809 pub lsp_name: String,
13810 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13811}
13812
13813impl LanguageServerPromptRequest {
13814 pub fn new(
13815 level: PromptLevel,
13816 message: String,
13817 actions: Vec<MessageActionItem>,
13818 lsp_name: String,
13819 response_channel: smol::channel::Sender<MessageActionItem>,
13820 ) -> Self {
13821 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13822 LanguageServerPromptRequest {
13823 id,
13824 level,
13825 message,
13826 actions,
13827 lsp_name,
13828 response_channel,
13829 }
13830 }
13831 pub async fn respond(self, index: usize) -> Option<()> {
13832 if let Some(response) = self.actions.into_iter().nth(index) {
13833 self.response_channel.send(response).await.ok()
13834 } else {
13835 None
13836 }
13837 }
13838
13839 #[cfg(any(test, feature = "test-support"))]
13840 pub fn test(
13841 level: PromptLevel,
13842 message: String,
13843 actions: Vec<MessageActionItem>,
13844 lsp_name: String,
13845 ) -> Self {
13846 let (tx, _rx) = smol::channel::unbounded();
13847 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13848 }
13849}
13850impl PartialEq for LanguageServerPromptRequest {
13851 fn eq(&self, other: &Self) -> bool {
13852 self.message == other.message && self.actions == other.actions
13853 }
13854}
13855
13856#[derive(Clone, Debug, PartialEq)]
13857pub enum LanguageServerLogType {
13858 Log(MessageType),
13859 Trace { verbose_info: Option<String> },
13860 Rpc { received: bool },
13861}
13862
13863impl LanguageServerLogType {
13864 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13865 match self {
13866 Self::Log(log_type) => {
13867 use proto::log_message::LogLevel;
13868 let level = match *log_type {
13869 MessageType::ERROR => LogLevel::Error,
13870 MessageType::WARNING => LogLevel::Warning,
13871 MessageType::INFO => LogLevel::Info,
13872 MessageType::LOG => LogLevel::Log,
13873 other => {
13874 log::warn!("Unknown lsp log message type: {other:?}");
13875 LogLevel::Log
13876 }
13877 };
13878 proto::language_server_log::LogType::Log(proto::LogMessage {
13879 level: level as i32,
13880 })
13881 }
13882 Self::Trace { verbose_info } => {
13883 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13884 verbose_info: verbose_info.to_owned(),
13885 })
13886 }
13887 Self::Rpc { received } => {
13888 let kind = if *received {
13889 proto::rpc_message::Kind::Received
13890 } else {
13891 proto::rpc_message::Kind::Sent
13892 };
13893 let kind = kind as i32;
13894 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13895 }
13896 }
13897 }
13898
13899 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13900 use proto::log_message::LogLevel;
13901 use proto::rpc_message;
13902 match log_type {
13903 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13904 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13905 LogLevel::Error => MessageType::ERROR,
13906 LogLevel::Warning => MessageType::WARNING,
13907 LogLevel::Info => MessageType::INFO,
13908 LogLevel::Log => MessageType::LOG,
13909 },
13910 ),
13911 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13912 verbose_info: trace_message.verbose_info,
13913 },
13914 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13915 received: match rpc_message::Kind::from_i32(message.kind)
13916 .unwrap_or(rpc_message::Kind::Received)
13917 {
13918 rpc_message::Kind::Received => true,
13919 rpc_message::Kind::Sent => false,
13920 },
13921 },
13922 }
13923 }
13924}
13925
13926pub struct WorkspaceRefreshTask {
13927 refresh_tx: mpsc::Sender<()>,
13928 progress_tx: mpsc::Sender<()>,
13929 #[allow(dead_code)]
13930 task: Task<()>,
13931}
13932
13933pub enum LanguageServerState {
13934 Starting {
13935 startup: Task<Option<Arc<LanguageServer>>>,
13936 /// List of language servers that will be added to the workspace once it's initialization completes.
13937 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13938 },
13939
13940 Running {
13941 adapter: Arc<CachedLspAdapter>,
13942 server: Arc<LanguageServer>,
13943 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13944 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13945 },
13946}
13947
13948impl LanguageServerState {
13949 fn add_workspace_folder(&self, uri: Uri) {
13950 match self {
13951 LanguageServerState::Starting {
13952 pending_workspace_folders,
13953 ..
13954 } => {
13955 pending_workspace_folders.lock().insert(uri);
13956 }
13957 LanguageServerState::Running { server, .. } => {
13958 server.add_workspace_folder(uri);
13959 }
13960 }
13961 }
13962 fn _remove_workspace_folder(&self, uri: Uri) {
13963 match self {
13964 LanguageServerState::Starting {
13965 pending_workspace_folders,
13966 ..
13967 } => {
13968 pending_workspace_folders.lock().remove(&uri);
13969 }
13970 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13971 }
13972 }
13973}
13974
13975impl std::fmt::Debug for LanguageServerState {
13976 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13977 match self {
13978 LanguageServerState::Starting { .. } => {
13979 f.debug_struct("LanguageServerState::Starting").finish()
13980 }
13981 LanguageServerState::Running { .. } => {
13982 f.debug_struct("LanguageServerState::Running").finish()
13983 }
13984 }
13985 }
13986}
13987
13988#[derive(Clone, Debug, Serialize)]
13989pub struct LanguageServerProgress {
13990 pub is_disk_based_diagnostics_progress: bool,
13991 pub is_cancellable: bool,
13992 pub title: Option<String>,
13993 pub message: Option<String>,
13994 pub percentage: Option<usize>,
13995 #[serde(skip_serializing)]
13996 pub last_update_at: Instant,
13997}
13998
13999#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14000pub struct DiagnosticSummary {
14001 pub error_count: usize,
14002 pub warning_count: usize,
14003}
14004
14005impl DiagnosticSummary {
14006 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14007 let mut this = Self {
14008 error_count: 0,
14009 warning_count: 0,
14010 };
14011
14012 for entry in diagnostics {
14013 if entry.diagnostic.is_primary {
14014 match entry.diagnostic.severity {
14015 DiagnosticSeverity::ERROR => this.error_count += 1,
14016 DiagnosticSeverity::WARNING => this.warning_count += 1,
14017 _ => {}
14018 }
14019 }
14020 }
14021
14022 this
14023 }
14024
14025 pub fn is_empty(&self) -> bool {
14026 self.error_count == 0 && self.warning_count == 0
14027 }
14028
14029 pub fn to_proto(
14030 self,
14031 language_server_id: LanguageServerId,
14032 path: &RelPath,
14033 ) -> proto::DiagnosticSummary {
14034 proto::DiagnosticSummary {
14035 path: path.to_proto(),
14036 language_server_id: language_server_id.0 as u64,
14037 error_count: self.error_count as u32,
14038 warning_count: self.warning_count as u32,
14039 }
14040 }
14041}
14042
14043#[derive(Clone, Debug)]
14044pub enum CompletionDocumentation {
14045 /// There is no documentation for this completion.
14046 Undocumented,
14047 /// A single line of documentation.
14048 SingleLine(SharedString),
14049 /// Multiple lines of plain text documentation.
14050 MultiLinePlainText(SharedString),
14051 /// Markdown documentation.
14052 MultiLineMarkdown(SharedString),
14053 /// Both single line and multiple lines of plain text documentation.
14054 SingleLineAndMultiLinePlainText {
14055 single_line: SharedString,
14056 plain_text: Option<SharedString>,
14057 },
14058}
14059
14060impl CompletionDocumentation {
14061 #[cfg(any(test, feature = "test-support"))]
14062 pub fn text(&self) -> SharedString {
14063 match self {
14064 CompletionDocumentation::Undocumented => "".into(),
14065 CompletionDocumentation::SingleLine(s) => s.clone(),
14066 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14067 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14068 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14069 single_line.clone()
14070 }
14071 }
14072 }
14073}
14074
14075impl From<lsp::Documentation> for CompletionDocumentation {
14076 fn from(docs: lsp::Documentation) -> Self {
14077 match docs {
14078 lsp::Documentation::String(text) => {
14079 if text.lines().count() <= 1 {
14080 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14081 } else {
14082 CompletionDocumentation::MultiLinePlainText(text.into())
14083 }
14084 }
14085
14086 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14087 lsp::MarkupKind::PlainText => {
14088 if value.lines().count() <= 1 {
14089 CompletionDocumentation::SingleLine(value.into())
14090 } else {
14091 CompletionDocumentation::MultiLinePlainText(value.into())
14092 }
14093 }
14094
14095 lsp::MarkupKind::Markdown => {
14096 CompletionDocumentation::MultiLineMarkdown(value.into())
14097 }
14098 },
14099 }
14100 }
14101}
14102
14103pub enum ResolvedHint {
14104 Resolved(InlayHint),
14105 Resolving(Shared<Task<()>>),
14106}
14107
14108pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14109 glob.components()
14110 .take_while(|component| match component {
14111 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14112 _ => true,
14113 })
14114 .collect()
14115}
14116
14117pub struct SshLspAdapter {
14118 name: LanguageServerName,
14119 binary: LanguageServerBinary,
14120 initialization_options: Option<String>,
14121 code_action_kinds: Option<Vec<CodeActionKind>>,
14122}
14123
14124impl SshLspAdapter {
14125 pub fn new(
14126 name: LanguageServerName,
14127 binary: LanguageServerBinary,
14128 initialization_options: Option<String>,
14129 code_action_kinds: Option<String>,
14130 ) -> Self {
14131 Self {
14132 name,
14133 binary,
14134 initialization_options,
14135 code_action_kinds: code_action_kinds
14136 .as_ref()
14137 .and_then(|c| serde_json::from_str(c).ok()),
14138 }
14139 }
14140}
14141
14142impl LspInstaller for SshLspAdapter {
14143 type BinaryVersion = ();
14144 async fn check_if_user_installed(
14145 &self,
14146 _: &dyn LspAdapterDelegate,
14147 _: Option<Toolchain>,
14148 _: &AsyncApp,
14149 ) -> Option<LanguageServerBinary> {
14150 Some(self.binary.clone())
14151 }
14152
14153 async fn cached_server_binary(
14154 &self,
14155 _: PathBuf,
14156 _: &dyn LspAdapterDelegate,
14157 ) -> Option<LanguageServerBinary> {
14158 None
14159 }
14160
14161 async fn fetch_latest_server_version(
14162 &self,
14163 _: &dyn LspAdapterDelegate,
14164 _: bool,
14165 _: &mut AsyncApp,
14166 ) -> Result<()> {
14167 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14168 }
14169
14170 async fn fetch_server_binary(
14171 &self,
14172 _: (),
14173 _: PathBuf,
14174 _: &dyn LspAdapterDelegate,
14175 ) -> Result<LanguageServerBinary> {
14176 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14177 }
14178}
14179
14180#[async_trait(?Send)]
14181impl LspAdapter for SshLspAdapter {
14182 fn name(&self) -> LanguageServerName {
14183 self.name.clone()
14184 }
14185
14186 async fn initialization_options(
14187 self: Arc<Self>,
14188 _: &Arc<dyn LspAdapterDelegate>,
14189 _: &mut AsyncApp,
14190 ) -> Result<Option<serde_json::Value>> {
14191 let Some(options) = &self.initialization_options else {
14192 return Ok(None);
14193 };
14194 let result = serde_json::from_str(options)?;
14195 Ok(result)
14196 }
14197
14198 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14199 self.code_action_kinds.clone()
14200 }
14201}
14202
14203pub fn language_server_settings<'a>(
14204 delegate: &'a dyn LspAdapterDelegate,
14205 language: &LanguageServerName,
14206 cx: &'a App,
14207) -> Option<&'a LspSettings> {
14208 language_server_settings_for(
14209 SettingsLocation {
14210 worktree_id: delegate.worktree_id(),
14211 path: RelPath::empty(),
14212 },
14213 language,
14214 cx,
14215 )
14216}
14217
14218pub fn language_server_settings_for<'a>(
14219 location: SettingsLocation<'a>,
14220 language: &LanguageServerName,
14221 cx: &'a App,
14222) -> Option<&'a LspSettings> {
14223 ProjectSettings::get(Some(location), cx).lsp.get(language)
14224}
14225
14226pub struct LocalLspAdapterDelegate {
14227 lsp_store: WeakEntity<LspStore>,
14228 worktree: worktree::Snapshot,
14229 fs: Arc<dyn Fs>,
14230 http_client: Arc<dyn HttpClient>,
14231 language_registry: Arc<LanguageRegistry>,
14232 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14233}
14234
14235impl LocalLspAdapterDelegate {
14236 pub fn new(
14237 language_registry: Arc<LanguageRegistry>,
14238 environment: &Entity<ProjectEnvironment>,
14239 lsp_store: WeakEntity<LspStore>,
14240 worktree: &Entity<Worktree>,
14241 http_client: Arc<dyn HttpClient>,
14242 fs: Arc<dyn Fs>,
14243 cx: &mut App,
14244 ) -> Arc<Self> {
14245 let load_shell_env_task =
14246 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14247
14248 Arc::new(Self {
14249 lsp_store,
14250 worktree: worktree.read(cx).snapshot(),
14251 fs,
14252 http_client,
14253 language_registry,
14254 load_shell_env_task,
14255 })
14256 }
14257
14258 pub fn from_local_lsp(
14259 local: &LocalLspStore,
14260 worktree: &Entity<Worktree>,
14261 cx: &mut App,
14262 ) -> Arc<Self> {
14263 Self::new(
14264 local.languages.clone(),
14265 &local.environment,
14266 local.weak.clone(),
14267 worktree,
14268 local.http_client.clone(),
14269 local.fs.clone(),
14270 cx,
14271 )
14272 }
14273}
14274
14275#[async_trait]
14276impl LspAdapterDelegate for LocalLspAdapterDelegate {
14277 fn show_notification(&self, message: &str, cx: &mut App) {
14278 self.lsp_store
14279 .update(cx, |_, cx| {
14280 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14281 })
14282 .ok();
14283 }
14284
14285 fn http_client(&self) -> Arc<dyn HttpClient> {
14286 self.http_client.clone()
14287 }
14288
14289 fn worktree_id(&self) -> WorktreeId {
14290 self.worktree.id()
14291 }
14292
14293 fn worktree_root_path(&self) -> &Path {
14294 self.worktree.abs_path().as_ref()
14295 }
14296
14297 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14298 self.worktree.resolve_relative_path(path)
14299 }
14300
14301 async fn shell_env(&self) -> HashMap<String, String> {
14302 let task = self.load_shell_env_task.clone();
14303 task.await.unwrap_or_default()
14304 }
14305
14306 async fn npm_package_installed_version(
14307 &self,
14308 package_name: &str,
14309 ) -> Result<Option<(PathBuf, Version)>> {
14310 let local_package_directory = self.worktree_root_path();
14311 let node_modules_directory = local_package_directory.join("node_modules");
14312
14313 if let Some(version) =
14314 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14315 {
14316 return Ok(Some((node_modules_directory, version)));
14317 }
14318 let Some(npm) = self.which("npm".as_ref()).await else {
14319 log::warn!(
14320 "Failed to find npm executable for {:?}",
14321 local_package_directory
14322 );
14323 return Ok(None);
14324 };
14325
14326 let env = self.shell_env().await;
14327 let output = util::command::new_command(&npm)
14328 .args(["root", "-g"])
14329 .envs(env)
14330 .current_dir(local_package_directory)
14331 .output()
14332 .await?;
14333 let global_node_modules =
14334 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14335
14336 if let Some(version) =
14337 read_package_installed_version(global_node_modules.clone(), package_name).await?
14338 {
14339 return Ok(Some((global_node_modules, version)));
14340 }
14341 return Ok(None);
14342 }
14343
14344 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14345 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14346 if self.fs.is_file(&worktree_abs_path).await {
14347 worktree_abs_path.pop();
14348 }
14349
14350 let env = self.shell_env().await;
14351
14352 let shell_path = env.get("PATH").cloned();
14353
14354 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14355 }
14356
14357 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14358 let mut working_dir = self.worktree_root_path().to_path_buf();
14359 if self.fs.is_file(&working_dir).await {
14360 working_dir.pop();
14361 }
14362 let output = util::command::new_command(&command.path)
14363 .args(command.arguments)
14364 .envs(command.env.clone().unwrap_or_default())
14365 .current_dir(working_dir)
14366 .output()
14367 .await?;
14368
14369 anyhow::ensure!(
14370 output.status.success(),
14371 "{}, stdout: {:?}, stderr: {:?}",
14372 output.status,
14373 String::from_utf8_lossy(&output.stdout),
14374 String::from_utf8_lossy(&output.stderr)
14375 );
14376 Ok(())
14377 }
14378
14379 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14380 self.language_registry
14381 .update_lsp_binary_status(server_name, status);
14382 }
14383
14384 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14385 self.language_registry
14386 .all_lsp_adapters()
14387 .into_iter()
14388 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14389 .collect()
14390 }
14391
14392 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14393 let dir = self.language_registry.language_server_download_dir(name)?;
14394
14395 if !dir.exists() {
14396 smol::fs::create_dir_all(&dir)
14397 .await
14398 .context("failed to create container directory")
14399 .log_err()?;
14400 }
14401
14402 Some(dir)
14403 }
14404
14405 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14406 let entry = self
14407 .worktree
14408 .entry_for_path(path)
14409 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14410 let abs_path = self.worktree.absolutize(&entry.path);
14411 self.fs.load(&abs_path).await
14412 }
14413}
14414
14415async fn populate_labels_for_symbols(
14416 symbols: Vec<CoreSymbol>,
14417 language_registry: &Arc<LanguageRegistry>,
14418 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14419 output: &mut Vec<Symbol>,
14420) {
14421 #[allow(clippy::mutable_key_type)]
14422 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14423
14424 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14425 for symbol in symbols {
14426 let Some(file_name) = symbol.path.file_name() else {
14427 continue;
14428 };
14429 let language = language_registry
14430 .load_language_for_file_path(Path::new(file_name))
14431 .await
14432 .ok()
14433 .or_else(|| {
14434 unknown_paths.insert(file_name.into());
14435 None
14436 });
14437 symbols_by_language
14438 .entry(language)
14439 .or_default()
14440 .push(symbol);
14441 }
14442
14443 for unknown_path in unknown_paths {
14444 log::info!("no language found for symbol in file {unknown_path:?}");
14445 }
14446
14447 let mut label_params = Vec::new();
14448 for (language, mut symbols) in symbols_by_language {
14449 label_params.clear();
14450 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14451 name: mem::take(&mut symbol.name),
14452 kind: symbol.kind,
14453 container_name: symbol.container_name.take(),
14454 }));
14455
14456 let mut labels = Vec::new();
14457 if let Some(language) = language {
14458 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14459 language_registry
14460 .lsp_adapters(&language.name())
14461 .first()
14462 .cloned()
14463 });
14464 if let Some(lsp_adapter) = lsp_adapter {
14465 labels = lsp_adapter
14466 .labels_for_symbols(&label_params, &language)
14467 .await
14468 .log_err()
14469 .unwrap_or_default();
14470 }
14471 }
14472
14473 for (
14474 (
14475 symbol,
14476 language::Symbol {
14477 name,
14478 container_name,
14479 ..
14480 },
14481 ),
14482 label,
14483 ) in symbols
14484 .into_iter()
14485 .zip(label_params.drain(..))
14486 .zip(labels.into_iter().chain(iter::repeat(None)))
14487 {
14488 output.push(Symbol {
14489 language_server_name: symbol.language_server_name,
14490 source_worktree_id: symbol.source_worktree_id,
14491 source_language_server_id: symbol.source_language_server_id,
14492 path: symbol.path,
14493 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14494 name,
14495 kind: symbol.kind,
14496 range: symbol.range,
14497 container_name,
14498 });
14499 }
14500 }
14501}
14502
14503pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14504 text.lines()
14505 .map(|line| line.trim())
14506 .filter(|line| !line.is_empty())
14507 .join(separator)
14508}
14509
14510fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14511 match server.capabilities().text_document_sync.as_ref()? {
14512 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14513 // Server wants didSave but didn't specify includeText.
14514 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14515 // Server doesn't want didSave at all.
14516 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14517 // Server provided SaveOptions.
14518 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14519 Some(save_options.include_text.unwrap_or(false))
14520 }
14521 },
14522 // We do not have any save info. Kind affects didChange only.
14523 lsp::TextDocumentSyncCapability::Kind(_) => None,
14524 }
14525}
14526
14527/// Completion items are displayed in a `UniformList`.
14528/// Usually, those items are single-line strings, but in LSP responses,
14529/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14530/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14531/// 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,
14532/// breaking the completions menu presentation.
14533///
14534/// 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.
14535pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14536 let mut new_text = String::with_capacity(label.text.len());
14537 let mut offset_map = vec![0; label.text.len() + 1];
14538 let mut last_char_was_space = false;
14539 let mut new_idx = 0;
14540 let chars = label.text.char_indices().fuse();
14541 let mut newlines_removed = false;
14542
14543 for (idx, c) in chars {
14544 offset_map[idx] = new_idx;
14545
14546 match c {
14547 '\n' if last_char_was_space => {
14548 newlines_removed = true;
14549 }
14550 '\t' | ' ' if last_char_was_space => {}
14551 '\n' if !last_char_was_space => {
14552 new_text.push(' ');
14553 new_idx += 1;
14554 last_char_was_space = true;
14555 newlines_removed = true;
14556 }
14557 ' ' | '\t' => {
14558 new_text.push(' ');
14559 new_idx += 1;
14560 last_char_was_space = true;
14561 }
14562 _ => {
14563 new_text.push(c);
14564 new_idx += c.len_utf8();
14565 last_char_was_space = false;
14566 }
14567 }
14568 }
14569 offset_map[label.text.len()] = new_idx;
14570
14571 // Only modify the label if newlines were removed.
14572 if !newlines_removed {
14573 return;
14574 }
14575
14576 let last_index = new_idx;
14577 let mut run_ranges_errors = Vec::new();
14578 label.runs.retain_mut(|(range, _)| {
14579 match offset_map.get(range.start) {
14580 Some(&start) => range.start = start,
14581 None => {
14582 run_ranges_errors.push(range.clone());
14583 return false;
14584 }
14585 }
14586
14587 match offset_map.get(range.end) {
14588 Some(&end) => range.end = end,
14589 None => {
14590 run_ranges_errors.push(range.clone());
14591 range.end = last_index;
14592 }
14593 }
14594 true
14595 });
14596 if !run_ranges_errors.is_empty() {
14597 log::error!(
14598 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14599 label.text
14600 );
14601 }
14602
14603 let mut wrong_filter_range = None;
14604 if label.filter_range == (0..label.text.len()) {
14605 label.filter_range = 0..new_text.len();
14606 } else {
14607 let mut original_filter_range = Some(label.filter_range.clone());
14608 match offset_map.get(label.filter_range.start) {
14609 Some(&start) => label.filter_range.start = start,
14610 None => {
14611 wrong_filter_range = original_filter_range.take();
14612 label.filter_range.start = last_index;
14613 }
14614 }
14615
14616 match offset_map.get(label.filter_range.end) {
14617 Some(&end) => label.filter_range.end = end,
14618 None => {
14619 wrong_filter_range = original_filter_range.take();
14620 label.filter_range.end = last_index;
14621 }
14622 }
14623 }
14624 if let Some(wrong_filter_range) = wrong_filter_range {
14625 log::error!(
14626 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14627 label.text
14628 );
14629 }
14630
14631 label.text = new_text;
14632}
14633
14634/// Apply edits to the buffer that will become part of the formatting transaction.
14635/// Fails if the buffer has been edited since the start of that transaction.
14636fn extend_formatting_transaction(
14637 buffer: &FormattableBuffer,
14638 formatting_transaction_id: text::TransactionId,
14639 cx: &mut AsyncApp,
14640 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14641) -> anyhow::Result<()> {
14642 buffer.handle.update(cx, |buffer, cx| {
14643 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14644 if last_transaction_id != Some(formatting_transaction_id) {
14645 anyhow::bail!("Buffer edited while formatting. Aborting")
14646 }
14647 buffer.start_transaction();
14648 operation(buffer, cx);
14649 if let Some(transaction_id) = buffer.end_transaction(cx) {
14650 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14651 }
14652 Ok(())
14653 })
14654}