1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 CodeLabelExt, Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff,
75 File as _, Language, LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate,
76 LspInstaller, ManifestDelegate, ManifestName, ModelineSettings, OffsetUtf16, Patch, PointUtf16,
77 TextBufferSnapshot, ToOffset, ToOffsetUtf16, ToPointUtf16, Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 },
81 modeline, point_to_lsp,
82 proto::{
83 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
84 serialize_anchor_range, serialize_version,
85 },
86 range_from_lsp, range_to_lsp,
87 row_chunk::RowChunk,
88};
89use lsp::{
90 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
91 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
92 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
93 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
94 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
95 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
96 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
97 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
98};
99use node_runtime::read_package_installed_version;
100use parking_lot::Mutex;
101use postage::{mpsc, sink::Sink, stream::Stream, watch};
102use rand::prelude::*;
103use rpc::{
104 AnyProtoClient, ErrorCode, ErrorExt as _,
105 proto::{LspRequestId, LspRequestMessage as _},
106};
107use semver::Version;
108use serde::Serialize;
109use serde_json::Value;
110use settings::{Settings, SettingsLocation, SettingsStore};
111use sha2::{Digest, Sha256};
112use snippet::Snippet;
113use std::{
114 any::TypeId,
115 borrow::Cow,
116 cell::RefCell,
117 cmp::{Ordering, Reverse},
118 collections::{VecDeque, hash_map},
119 convert::TryInto,
120 ffi::OsStr,
121 future::ready,
122 iter, mem,
123 ops::{ControlFlow, Range},
124 path::{self, Path, PathBuf},
125 pin::pin,
126 rc::Rc,
127 sync::{
128 Arc,
129 atomic::{self, AtomicUsize},
130 },
131 time::{Duration, Instant},
132 vec,
133};
134use sum_tree::Dimensions;
135use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
136
137use util::{
138 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
139 paths::{PathStyle, SanitizedPath, UrlExt},
140 post_inc,
141 redact::redact_command,
142 rel_path::RelPath,
143};
144
145pub use document_colors::DocumentColors;
146pub use folding_ranges::LspFoldingRange;
147pub use fs::*;
148pub use language::Location;
149pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
150#[cfg(any(test, feature = "test-support"))]
151pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
152#[cfg(any(test, feature = "test-support"))]
153pub use prettier::RANGE_FORMAT_SUFFIX as TEST_PRETTIER_RANGE_FORMAT_SUFFIX;
154pub use semantic_tokens::{
155 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
156};
157
158pub use worktree::{
159 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
160 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
161};
162
163const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
164pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
165const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
166const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
167static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
168
169#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
170pub enum ProgressToken {
171 Number(i32),
172 String(SharedString),
173}
174
175impl std::fmt::Display for ProgressToken {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 Self::Number(number) => write!(f, "{number}"),
179 Self::String(string) => write!(f, "{string}"),
180 }
181 }
182}
183
184impl ProgressToken {
185 fn from_lsp(value: lsp::NumberOrString) -> Self {
186 match value {
187 lsp::NumberOrString::Number(number) => Self::Number(number),
188 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
189 }
190 }
191
192 fn to_lsp(&self) -> lsp::NumberOrString {
193 match self {
194 Self::Number(number) => lsp::NumberOrString::Number(*number),
195 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
196 }
197 }
198
199 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
200 Some(match value.value? {
201 proto::progress_token::Value::Number(number) => Self::Number(number),
202 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
203 })
204 }
205
206 fn to_proto(&self) -> proto::ProgressToken {
207 proto::ProgressToken {
208 value: Some(match self {
209 Self::Number(number) => proto::progress_token::Value::Number(*number),
210 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
211 }),
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum FormatTrigger {
218 Save,
219 Manual,
220}
221
222pub enum LspFormatTarget {
223 Buffers,
224 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
229
230struct OpenLspBuffer(Entity<Buffer>);
231
232impl FormatTrigger {
233 fn from_proto(value: i32) -> FormatTrigger {
234 match value {
235 0 => FormatTrigger::Save,
236 1 => FormatTrigger::Manual,
237 _ => FormatTrigger::Save,
238 }
239 }
240}
241
242#[derive(Clone)]
243struct UnifiedLanguageServer {
244 id: LanguageServerId,
245 project_roots: HashSet<Arc<RelPath>>,
246}
247
248/// Settings that affect language server identity.
249///
250/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
251/// updated via `workspace/didChangeConfiguration` without restarting the server.
252#[derive(Clone, Debug, Hash, PartialEq, Eq)]
253struct LanguageServerSeedSettings {
254 binary: Option<BinarySettings>,
255 initialization_options: Option<serde_json::Value>,
256}
257
258#[derive(Clone, Debug, Hash, PartialEq, Eq)]
259struct LanguageServerSeed {
260 worktree_id: WorktreeId,
261 name: LanguageServerName,
262 toolchain: Option<Toolchain>,
263 settings: LanguageServerSeedSettings,
264}
265
266#[derive(Debug)]
267pub struct DocumentDiagnosticsUpdate<'a, D> {
268 pub diagnostics: D,
269 pub result_id: Option<SharedString>,
270 pub registration_id: Option<SharedString>,
271 pub server_id: LanguageServerId,
272 pub disk_based_sources: Cow<'a, [String]>,
273}
274
275pub struct DocumentDiagnostics {
276 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
277 document_abs_path: PathBuf,
278 version: Option<i32>,
279}
280
281#[derive(Default, Debug)]
282struct DynamicRegistrations {
283 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
284 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
285}
286
287pub struct LocalLspStore {
288 weak: WeakEntity<LspStore>,
289 pub worktree_store: Entity<WorktreeStore>,
290 toolchain_store: Entity<LocalToolchainStore>,
291 http_client: Arc<dyn HttpClient>,
292 environment: Entity<ProjectEnvironment>,
293 fs: Arc<dyn Fs>,
294 languages: Arc<LanguageRegistry>,
295 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
296 yarn: Entity<YarnPathStore>,
297 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
298 buffers_being_formatted: HashSet<BufferId>,
299 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
300 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
301 watched_manifest_filenames: HashSet<ManifestName>,
302 language_server_paths_watched_for_rename:
303 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
304 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
305 supplementary_language_servers:
306 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
307 prettier_store: Entity<PrettierStore>,
308 next_diagnostic_group_id: usize,
309 diagnostics: HashMap<
310 WorktreeId,
311 HashMap<
312 Arc<RelPath>,
313 Vec<(
314 LanguageServerId,
315 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
316 )>,
317 >,
318 >,
319 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
320 _subscription: gpui::Subscription,
321 lsp_tree: LanguageServerTree,
322 registered_buffers: HashMap<BufferId, usize>,
323 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
324 buffer_pull_diagnostics_result_ids: HashMap<
325 LanguageServerId,
326 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
327 >,
328 workspace_pull_diagnostics_result_ids: HashMap<
329 LanguageServerId,
330 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
331 >,
332 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
333
334 buffers_to_refresh_hash_set: HashSet<BufferId>,
335 buffers_to_refresh_queue: VecDeque<BufferId>,
336 _background_diagnostics_worker: Shared<Task<()>>,
337}
338
339impl LocalLspStore {
340 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
341 pub fn running_language_server_for_id(
342 &self,
343 id: LanguageServerId,
344 ) -> Option<&Arc<LanguageServer>> {
345 let language_server_state = self.language_servers.get(&id)?;
346
347 match language_server_state {
348 LanguageServerState::Running { server, .. } => Some(server),
349 LanguageServerState::Starting { .. } => None,
350 }
351 }
352
353 fn get_or_insert_language_server(
354 &mut self,
355 worktree_handle: &Entity<Worktree>,
356 delegate: Arc<LocalLspAdapterDelegate>,
357 disposition: &Arc<LaunchDisposition>,
358 language_name: &LanguageName,
359 cx: &mut App,
360 ) -> LanguageServerId {
361 let key = LanguageServerSeed {
362 worktree_id: worktree_handle.read(cx).id(),
363 name: disposition.server_name.clone(),
364 settings: LanguageServerSeedSettings {
365 binary: disposition.settings.binary.clone(),
366 initialization_options: disposition.settings.initialization_options.clone(),
367 },
368 toolchain: disposition.toolchain.clone(),
369 };
370 if let Some(state) = self.language_server_ids.get_mut(&key) {
371 state.project_roots.insert(disposition.path.path.clone());
372 state.id
373 } else {
374 let adapter = self
375 .languages
376 .lsp_adapters(language_name)
377 .into_iter()
378 .find(|adapter| adapter.name() == disposition.server_name)
379 .expect("To find LSP adapter");
380 let new_language_server_id = self.start_language_server(
381 worktree_handle,
382 delegate,
383 adapter,
384 disposition.settings.clone(),
385 key.clone(),
386 language_name.clone(),
387 cx,
388 );
389 if let Some(state) = self.language_server_ids.get_mut(&key) {
390 state.project_roots.insert(disposition.path.path.clone());
391 } else {
392 debug_assert!(
393 false,
394 "Expected `start_language_server` to ensure that `key` exists in a map"
395 );
396 }
397 new_language_server_id
398 }
399 }
400
401 fn start_language_server(
402 &mut self,
403 worktree_handle: &Entity<Worktree>,
404 delegate: Arc<LocalLspAdapterDelegate>,
405 adapter: Arc<CachedLspAdapter>,
406 settings: Arc<LspSettings>,
407 key: LanguageServerSeed,
408 language_name: LanguageName,
409 cx: &mut App,
410 ) -> LanguageServerId {
411 let worktree = worktree_handle.read(cx);
412
413 let worktree_id = worktree.id();
414 let worktree_abs_path = worktree.abs_path();
415 let toolchain = key.toolchain.clone();
416 let override_options = settings.initialization_options.clone();
417
418 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
419
420 let server_id = self.languages.next_language_server_id();
421 log::trace!(
422 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
423 adapter.name.0
424 );
425
426 let wait_until_worktree_trust =
427 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
428 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
429 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
430 });
431 if can_trust {
432 self.restricted_worktrees_tasks.remove(&worktree_id);
433 None
434 } else {
435 match self.restricted_worktrees_tasks.entry(worktree_id) {
436 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
437 hash_map::Entry::Vacant(v) => {
438 let (mut tx, rx) = watch::channel::<bool>();
439 let lsp_store = self.weak.clone();
440 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
441 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
442 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
443 tx.blocking_send(true).ok();
444 lsp_store
445 .update(cx, |lsp_store, _| {
446 if let Some(local_lsp_store) =
447 lsp_store.as_local_mut()
448 {
449 local_lsp_store
450 .restricted_worktrees_tasks
451 .remove(&worktree_id);
452 }
453 })
454 .ok();
455 }
456 }
457 });
458 v.insert((subscription, rx.clone()));
459 Some(rx)
460 }
461 }
462 }
463 });
464 let update_binary_status = wait_until_worktree_trust.is_none();
465
466 let binary = self.get_language_server_binary(
467 worktree_abs_path.clone(),
468 adapter.clone(),
469 settings,
470 toolchain.clone(),
471 delegate.clone(),
472 true,
473 wait_until_worktree_trust,
474 cx,
475 );
476 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
477
478 let pending_server = cx.spawn({
479 let adapter = adapter.clone();
480 let server_name = adapter.name.clone();
481 let stderr_capture = stderr_capture.clone();
482 #[cfg(any(test, feature = "test-support"))]
483 let lsp_store = self.weak.clone();
484 let pending_workspace_folders = pending_workspace_folders.clone();
485 async move |cx| {
486 let binary = binary.await?;
487 #[cfg(any(test, feature = "test-support"))]
488 if let Some(server) = lsp_store
489 .update(&mut cx.clone(), |this, cx| {
490 this.languages.create_fake_language_server(
491 server_id,
492 &server_name,
493 binary.clone(),
494 &mut cx.to_async(),
495 )
496 })
497 .ok()
498 .flatten()
499 {
500 return Ok(server);
501 }
502
503 let code_action_kinds = adapter.code_action_kinds();
504 lsp::LanguageServer::new(
505 stderr_capture,
506 server_id,
507 server_name,
508 binary,
509 &worktree_abs_path,
510 code_action_kinds,
511 Some(pending_workspace_folders),
512 cx,
513 )
514 }
515 });
516
517 let startup = {
518 let server_name = adapter.name.0.clone();
519 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
520 let key = key.clone();
521 let adapter = adapter.clone();
522 let lsp_store = self.weak.clone();
523 let pending_workspace_folders = pending_workspace_folders.clone();
524 let pull_diagnostics = ProjectSettings::get_global(cx)
525 .diagnostics
526 .lsp_pull_diagnostics
527 .enabled;
528 let settings_location = SettingsLocation {
529 worktree_id,
530 path: RelPath::empty(),
531 };
532 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
533 .language(Some(settings_location), Some(&language_name), cx)
534 .semantic_tokens
535 .use_tree_sitter();
536 cx.spawn(async move |cx| {
537 let result = async {
538 let language_server = pending_server.await?;
539
540 let workspace_config = Self::workspace_configuration_for_adapter(
541 adapter.adapter.clone(),
542 &delegate,
543 toolchain,
544 None,
545 cx,
546 )
547 .await?;
548
549 let mut initialization_options = Self::initialization_options_for_adapter(
550 adapter.adapter.clone(),
551 &delegate,
552 cx,
553 )
554 .await?;
555
556 match (&mut initialization_options, override_options) {
557 (Some(initialization_options), Some(override_options)) => {
558 merge_json_value_into(override_options, initialization_options);
559 }
560 (None, override_options) => initialization_options = override_options,
561 _ => {}
562 }
563
564 let initialization_params = cx.update(|cx| {
565 let mut params = language_server.default_initialize_params(
566 pull_diagnostics,
567 augments_syntax_tokens,
568 cx,
569 );
570 params.initialization_options = initialization_options;
571 adapter.adapter.prepare_initialize_params(params, cx)
572 })?;
573
574 Self::setup_lsp_messages(
575 lsp_store.clone(),
576 &language_server,
577 delegate.clone(),
578 adapter.clone(),
579 );
580
581 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
582 settings: workspace_config,
583 };
584 let language_server = cx
585 .update(|cx| {
586 let request_timeout = ProjectSettings::get_global(cx)
587 .global_lsp_settings
588 .get_request_timeout();
589
590 language_server.initialize(
591 initialization_params,
592 Arc::new(did_change_configuration_params.clone()),
593 request_timeout,
594 cx,
595 )
596 })
597 .await
598 .inspect_err(|_| {
599 if let Some(lsp_store) = lsp_store.upgrade() {
600 lsp_store.update(cx, |lsp_store, cx| {
601 lsp_store.cleanup_lsp_data(server_id);
602 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
603 });
604 }
605 })?;
606
607 language_server.notify::<lsp::notification::DidChangeConfiguration>(
608 did_change_configuration_params,
609 )?;
610
611 anyhow::Ok(language_server)
612 }
613 .await;
614
615 match result {
616 Ok(server) => {
617 lsp_store
618 .update(cx, |lsp_store, cx| {
619 lsp_store.insert_newly_running_language_server(
620 adapter,
621 server.clone(),
622 server_id,
623 key,
624 pending_workspace_folders,
625 cx,
626 );
627 })
628 .ok();
629 stderr_capture.lock().take();
630 Some(server)
631 }
632
633 Err(err) => {
634 let log = stderr_capture.lock().take().unwrap_or_default();
635 delegate.update_status(
636 adapter.name(),
637 BinaryStatus::Failed {
638 error: if log.is_empty() {
639 format!("{err:#}")
640 } else {
641 format!("{err:#}\n-- stderr --\n{log}")
642 },
643 },
644 );
645 log::error!(
646 "Failed to start language server {server_name:?}: {}",
647 redact_command(&format!("{err:?}"))
648 );
649 if !log.is_empty() {
650 log::error!("server stderr: {}", redact_command(&log));
651 }
652 None
653 }
654 }
655 })
656 };
657 let state = LanguageServerState::Starting {
658 startup,
659 pending_workspace_folders,
660 };
661
662 if update_binary_status {
663 self.languages
664 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
665 }
666
667 self.language_servers.insert(server_id, state);
668 self.language_server_ids
669 .entry(key)
670 .or_insert(UnifiedLanguageServer {
671 id: server_id,
672 project_roots: Default::default(),
673 });
674 server_id
675 }
676
677 fn get_language_server_binary(
678 &self,
679 worktree_abs_path: Arc<Path>,
680 adapter: Arc<CachedLspAdapter>,
681 settings: Arc<LspSettings>,
682 toolchain: Option<Toolchain>,
683 delegate: Arc<dyn LspAdapterDelegate>,
684 allow_binary_download: bool,
685 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
686 cx: &mut App,
687 ) -> Task<Result<LanguageServerBinary>> {
688 if let Some(settings) = &settings.binary
689 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
690 {
691 let settings = settings.clone();
692 let languages = self.languages.clone();
693 return cx.background_spawn(async move {
694 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
695 let already_trusted = *wait_until_worktree_trust.borrow();
696 if !already_trusted {
697 log::info!(
698 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
699 adapter.name(),
700 );
701 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
702 if worktree_trusted {
703 break;
704 }
705 }
706 log::info!(
707 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
708 adapter.name(),
709 );
710 }
711 languages
712 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
713 }
714 let mut env = delegate.shell_env().await;
715 env.extend(settings.env.unwrap_or_default());
716
717 Ok(LanguageServerBinary {
718 path: delegate.resolve_relative_path(path),
719 env: Some(env),
720 arguments: settings
721 .arguments
722 .unwrap_or_default()
723 .iter()
724 .map(Into::into)
725 .collect(),
726 })
727 });
728 }
729 let lsp_binary_options = LanguageServerBinaryOptions {
730 allow_path_lookup: !settings
731 .binary
732 .as_ref()
733 .and_then(|b| b.ignore_system_version)
734 .unwrap_or_default(),
735 allow_binary_download,
736 pre_release: settings
737 .fetch
738 .as_ref()
739 .and_then(|f| f.pre_release)
740 .unwrap_or(false),
741 };
742
743 cx.spawn(async move |cx| {
744 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
745 let already_trusted = *wait_until_worktree_trust.borrow();
746 if !already_trusted {
747 log::info!(
748 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
749 adapter.name(),
750 );
751 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
752 if worktree_trusted {
753 break;
754 }
755 }
756 log::info!(
757 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
758 adapter.name(),
759 );
760 }
761 }
762
763 let (existing_binary, maybe_download_binary) = adapter
764 .clone()
765 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
766 .await
767 .await;
768
769 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
770
771 let mut binary = match (existing_binary, maybe_download_binary) {
772 (binary, None) => binary?,
773 (Err(_), Some(downloader)) => downloader.await?,
774 (Ok(existing_binary), Some(downloader)) => {
775 let mut download_timeout = cx
776 .background_executor()
777 .timer(SERVER_DOWNLOAD_TIMEOUT)
778 .fuse();
779 let mut downloader = downloader.fuse();
780 futures::select! {
781 _ = download_timeout => {
782 // Return existing binary and kick the existing work to the background.
783 cx.spawn(async move |_| downloader.await).detach();
784 Ok(existing_binary)
785 },
786 downloaded_or_existing_binary = downloader => {
787 // If download fails, this results in the existing binary.
788 downloaded_or_existing_binary
789 }
790 }?
791 }
792 };
793 let mut shell_env = delegate.shell_env().await;
794
795 shell_env.extend(binary.env.unwrap_or_default());
796
797 if let Some(settings) = settings.binary.as_ref() {
798 if let Some(arguments) = &settings.arguments {
799 binary.arguments = arguments.iter().map(Into::into).collect();
800 }
801 if let Some(env) = &settings.env {
802 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
803 }
804 }
805
806 binary.env = Some(shell_env);
807 Ok(binary)
808 })
809 }
810
811 fn setup_lsp_messages(
812 lsp_store: WeakEntity<LspStore>,
813 language_server: &LanguageServer,
814 delegate: Arc<dyn LspAdapterDelegate>,
815 adapter: Arc<CachedLspAdapter>,
816 ) {
817 let name = language_server.name();
818 let server_id = language_server.server_id();
819 language_server
820 .on_notification::<lsp::notification::PublishDiagnostics, _>({
821 let adapter = adapter.clone();
822 let this = lsp_store.clone();
823 move |mut params, cx| {
824 let adapter = adapter.clone();
825 if let Some(this) = this.upgrade() {
826 this.update(cx, |this, cx| {
827 adapter.process_diagnostics(&mut params, server_id);
828
829 this.merge_lsp_diagnostics(
830 DiagnosticSourceKind::Pushed,
831 vec![DocumentDiagnosticsUpdate {
832 server_id,
833 diagnostics: params,
834 result_id: None,
835 disk_based_sources: Cow::Borrowed(
836 &adapter.disk_based_diagnostic_sources,
837 ),
838 registration_id: None,
839 }],
840 |_, diagnostic, _cx| match diagnostic.source_kind {
841 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
842 adapter.retain_old_diagnostic(diagnostic)
843 }
844 DiagnosticSourceKind::Pulled => true,
845 },
846 cx,
847 )
848 .log_err();
849 });
850 }
851 }
852 })
853 .detach();
854 language_server
855 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
856 let adapter = adapter.adapter.clone();
857 let delegate = delegate.clone();
858 let this = lsp_store.clone();
859 move |params, cx| {
860 let adapter = adapter.clone();
861 let delegate = delegate.clone();
862 let this = this.clone();
863 let mut cx = cx.clone();
864 async move {
865 let toolchain_for_id = this
866 .update(&mut cx, |this, _| {
867 this.as_local()?.language_server_ids.iter().find_map(
868 |(seed, value)| {
869 (value.id == server_id).then(|| seed.toolchain.clone())
870 },
871 )
872 })?
873 .context("Expected the LSP store to be in a local mode")?;
874
875 let mut scope_uri_to_workspace_config = BTreeMap::new();
876 for item in ¶ms.items {
877 let scope_uri = item.scope_uri.clone();
878 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
879 scope_uri_to_workspace_config.entry(scope_uri.clone())
880 else {
881 // We've already queried workspace configuration of this URI.
882 continue;
883 };
884 let workspace_config = Self::workspace_configuration_for_adapter(
885 adapter.clone(),
886 &delegate,
887 toolchain_for_id.clone(),
888 scope_uri,
889 &mut cx,
890 )
891 .await?;
892 new_scope_uri.insert(workspace_config);
893 }
894
895 Ok(params
896 .items
897 .into_iter()
898 .filter_map(|item| {
899 let workspace_config =
900 scope_uri_to_workspace_config.get(&item.scope_uri)?;
901 if let Some(section) = &item.section {
902 Some(
903 workspace_config
904 .get(section)
905 .cloned()
906 .unwrap_or(serde_json::Value::Null),
907 )
908 } else {
909 Some(workspace_config.clone())
910 }
911 })
912 .collect())
913 }
914 }
915 })
916 .detach();
917
918 language_server
919 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
920 let this = lsp_store.clone();
921 move |_, cx| {
922 let this = this.clone();
923 let cx = cx.clone();
924 async move {
925 let Some(server) =
926 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
927 else {
928 return Ok(None);
929 };
930 let root = server.workspace_folders();
931 Ok(Some(
932 root.into_iter()
933 .map(|uri| WorkspaceFolder {
934 uri,
935 name: Default::default(),
936 })
937 .collect(),
938 ))
939 }
940 }
941 })
942 .detach();
943 // Even though we don't have handling for these requests, respond to them to
944 // avoid stalling any language server like `gopls` which waits for a response
945 // to these requests when initializing.
946 language_server
947 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
948 let this = lsp_store.clone();
949 move |params, cx| {
950 let this = this.clone();
951 let mut cx = cx.clone();
952 async move {
953 this.update(&mut cx, |this, _| {
954 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
955 {
956 status
957 .progress_tokens
958 .insert(ProgressToken::from_lsp(params.token));
959 }
960 })?;
961
962 Ok(())
963 }
964 }
965 })
966 .detach();
967
968 language_server
969 .on_request::<lsp::request::RegisterCapability, _, _>({
970 let lsp_store = lsp_store.clone();
971 move |params, cx| {
972 let lsp_store = lsp_store.clone();
973 let mut cx = cx.clone();
974 async move {
975 lsp_store
976 .update(&mut cx, |lsp_store, cx| {
977 if lsp_store.as_local().is_some() {
978 match lsp_store
979 .register_server_capabilities(server_id, params, cx)
980 {
981 Ok(()) => {}
982 Err(e) => {
983 log::error!(
984 "Failed to register server capabilities: {e:#}"
985 );
986 }
987 };
988 }
989 })
990 .ok();
991 Ok(())
992 }
993 }
994 })
995 .detach();
996
997 language_server
998 .on_request::<lsp::request::UnregisterCapability, _, _>({
999 let lsp_store = lsp_store.clone();
1000 move |params, cx| {
1001 let lsp_store = lsp_store.clone();
1002 let mut cx = cx.clone();
1003 async move {
1004 lsp_store
1005 .update(&mut cx, |lsp_store, cx| {
1006 if lsp_store.as_local().is_some() {
1007 match lsp_store
1008 .unregister_server_capabilities(server_id, params, cx)
1009 {
1010 Ok(()) => {}
1011 Err(e) => {
1012 log::error!(
1013 "Failed to unregister server capabilities: {e:#}"
1014 );
1015 }
1016 }
1017 }
1018 })
1019 .ok();
1020 Ok(())
1021 }
1022 }
1023 })
1024 .detach();
1025
1026 language_server
1027 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1028 let this = lsp_store.clone();
1029 move |params, cx| {
1030 let mut cx = cx.clone();
1031 let this = this.clone();
1032 async move {
1033 LocalLspStore::on_lsp_workspace_edit(
1034 this.clone(),
1035 params,
1036 server_id,
1037 &mut cx,
1038 )
1039 .await
1040 }
1041 }
1042 })
1043 .detach();
1044
1045 language_server
1046 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1047 let lsp_store = lsp_store.clone();
1048 let request_id = Arc::new(AtomicUsize::new(0));
1049 move |(), cx| {
1050 let lsp_store = lsp_store.clone();
1051 let request_id = request_id.clone();
1052 let mut cx = cx.clone();
1053 async move {
1054 lsp_store
1055 .update(&mut cx, |lsp_store, cx| {
1056 let request_id =
1057 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1058 cx.emit(LspStoreEvent::RefreshInlayHints {
1059 server_id,
1060 request_id,
1061 });
1062 lsp_store
1063 .downstream_client
1064 .as_ref()
1065 .map(|(client, project_id)| {
1066 client.send(proto::RefreshInlayHints {
1067 project_id: *project_id,
1068 server_id: server_id.to_proto(),
1069 request_id: request_id.map(|id| id as u64),
1070 })
1071 })
1072 })?
1073 .transpose()?;
1074 Ok(())
1075 }
1076 }
1077 })
1078 .detach();
1079
1080 language_server
1081 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1082 let this = lsp_store.clone();
1083 move |(), cx| {
1084 let this = this.clone();
1085 let mut cx = cx.clone();
1086 async move {
1087 this.update(&mut cx, |this, cx| {
1088 cx.emit(LspStoreEvent::RefreshCodeLens);
1089 this.downstream_client.as_ref().map(|(client, project_id)| {
1090 client.send(proto::RefreshCodeLens {
1091 project_id: *project_id,
1092 })
1093 })
1094 })?
1095 .transpose()?;
1096 Ok(())
1097 }
1098 }
1099 })
1100 .detach();
1101
1102 language_server
1103 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1104 let lsp_store = lsp_store.clone();
1105 let request_id = Arc::new(AtomicUsize::new(0));
1106 move |(), cx| {
1107 let lsp_store = lsp_store.clone();
1108 let request_id = request_id.clone();
1109 let mut cx = cx.clone();
1110 async move {
1111 lsp_store
1112 .update(&mut cx, |lsp_store, cx| {
1113 let request_id =
1114 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1115 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1116 server_id,
1117 request_id,
1118 });
1119 lsp_store
1120 .downstream_client
1121 .as_ref()
1122 .map(|(client, project_id)| {
1123 client.send(proto::RefreshSemanticTokens {
1124 project_id: *project_id,
1125 server_id: server_id.to_proto(),
1126 request_id: request_id.map(|id| id as u64),
1127 })
1128 })
1129 })?
1130 .transpose()?;
1131 Ok(())
1132 }
1133 }
1134 })
1135 .detach();
1136
1137 language_server
1138 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1139 let this = lsp_store.clone();
1140 move |(), cx| {
1141 let this = this.clone();
1142 let mut cx = cx.clone();
1143 async move {
1144 this.update(&mut cx, |lsp_store, cx| {
1145 lsp_store.pull_workspace_diagnostics(server_id);
1146 lsp_store
1147 .downstream_client
1148 .as_ref()
1149 .map(|(client, project_id)| {
1150 client.send(proto::PullWorkspaceDiagnostics {
1151 project_id: *project_id,
1152 server_id: server_id.to_proto(),
1153 })
1154 })
1155 .transpose()?;
1156 anyhow::Ok(
1157 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1158 )
1159 })??
1160 .await;
1161 Ok(())
1162 }
1163 }
1164 })
1165 .detach();
1166
1167 language_server
1168 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1169 let this = lsp_store.clone();
1170 let name = name.to_string();
1171 let adapter = adapter.clone();
1172 move |params, cx| {
1173 let this = this.clone();
1174 let name = name.to_string();
1175 let adapter = adapter.clone();
1176 let mut cx = cx.clone();
1177 async move {
1178 let actions = params.actions.unwrap_or_default();
1179 let message = params.message.clone();
1180 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1181 let level = match params.typ {
1182 lsp::MessageType::ERROR => PromptLevel::Critical,
1183 lsp::MessageType::WARNING => PromptLevel::Warning,
1184 _ => PromptLevel::Info,
1185 };
1186 let request = LanguageServerPromptRequest::new(
1187 level,
1188 params.message,
1189 actions,
1190 name.clone(),
1191 tx,
1192 );
1193
1194 let did_update = this
1195 .update(&mut cx, |_, cx| {
1196 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1197 })
1198 .is_ok();
1199 if did_update {
1200 let response = rx.recv().await.ok();
1201 if let Some(ref selected_action) = response {
1202 let context = language::PromptResponseContext {
1203 message,
1204 selected_action: selected_action.clone(),
1205 };
1206 adapter.process_prompt_response(&context, &mut cx)
1207 }
1208
1209 Ok(response)
1210 } else {
1211 Ok(None)
1212 }
1213 }
1214 }
1215 })
1216 .detach();
1217 language_server
1218 .on_notification::<lsp::notification::ShowMessage, _>({
1219 let this = lsp_store.clone();
1220 let name = name.to_string();
1221 move |params, cx| {
1222 let this = this.clone();
1223 let name = name.to_string();
1224 let mut cx = cx.clone();
1225
1226 let (tx, _) = smol::channel::bounded(1);
1227 let level = match params.typ {
1228 lsp::MessageType::ERROR => PromptLevel::Critical,
1229 lsp::MessageType::WARNING => PromptLevel::Warning,
1230 _ => PromptLevel::Info,
1231 };
1232 let request =
1233 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1234
1235 let _ = this.update(&mut cx, |_, cx| {
1236 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1237 });
1238 }
1239 })
1240 .detach();
1241
1242 let disk_based_diagnostics_progress_token =
1243 adapter.disk_based_diagnostics_progress_token.clone();
1244
1245 language_server
1246 .on_notification::<lsp::notification::Progress, _>({
1247 let this = lsp_store.clone();
1248 move |params, cx| {
1249 if let Some(this) = this.upgrade() {
1250 this.update(cx, |this, cx| {
1251 this.on_lsp_progress(
1252 params,
1253 server_id,
1254 disk_based_diagnostics_progress_token.clone(),
1255 cx,
1256 );
1257 });
1258 }
1259 }
1260 })
1261 .detach();
1262
1263 language_server
1264 .on_notification::<lsp::notification::LogMessage, _>({
1265 let this = lsp_store.clone();
1266 move |params, cx| {
1267 if let Some(this) = this.upgrade() {
1268 this.update(cx, |_, cx| {
1269 cx.emit(LspStoreEvent::LanguageServerLog(
1270 server_id,
1271 LanguageServerLogType::Log(params.typ),
1272 params.message,
1273 ));
1274 });
1275 }
1276 }
1277 })
1278 .detach();
1279
1280 language_server
1281 .on_notification::<lsp::notification::LogTrace, _>({
1282 let this = lsp_store.clone();
1283 move |params, cx| {
1284 let mut cx = cx.clone();
1285 if let Some(this) = this.upgrade() {
1286 this.update(&mut cx, |_, cx| {
1287 cx.emit(LspStoreEvent::LanguageServerLog(
1288 server_id,
1289 LanguageServerLogType::Trace {
1290 verbose_info: params.verbose,
1291 },
1292 params.message,
1293 ));
1294 });
1295 }
1296 }
1297 })
1298 .detach();
1299
1300 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1301 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1302 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1303 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1304 }
1305
1306 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1307 let shutdown_futures = self
1308 .language_servers
1309 .drain()
1310 .map(|(_, server_state)| Self::shutdown_server(server_state))
1311 .collect::<Vec<_>>();
1312
1313 async move {
1314 join_all(shutdown_futures).await;
1315 }
1316 }
1317
1318 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1319 match server_state {
1320 LanguageServerState::Running { server, .. } => {
1321 if let Some(shutdown) = server.shutdown() {
1322 shutdown.await;
1323 }
1324 }
1325 LanguageServerState::Starting { startup, .. } => {
1326 if let Some(server) = startup.await
1327 && let Some(shutdown) = server.shutdown()
1328 {
1329 shutdown.await;
1330 }
1331 }
1332 }
1333 Ok(())
1334 }
1335
1336 fn language_servers_for_worktree(
1337 &self,
1338 worktree_id: WorktreeId,
1339 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1340 self.language_server_ids
1341 .iter()
1342 .filter_map(move |(seed, state)| {
1343 if seed.worktree_id != worktree_id {
1344 return None;
1345 }
1346
1347 if let Some(LanguageServerState::Running { server, .. }) =
1348 self.language_servers.get(&state.id)
1349 {
1350 Some(server)
1351 } else {
1352 None
1353 }
1354 })
1355 }
1356
1357 fn language_server_ids_for_project_path(
1358 &self,
1359 project_path: ProjectPath,
1360 language: &Language,
1361 cx: &mut App,
1362 ) -> Vec<LanguageServerId> {
1363 let Some(worktree) = self
1364 .worktree_store
1365 .read(cx)
1366 .worktree_for_id(project_path.worktree_id, cx)
1367 else {
1368 return Vec::new();
1369 };
1370 let delegate: Arc<dyn ManifestDelegate> =
1371 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1372
1373 self.lsp_tree
1374 .get(
1375 project_path,
1376 language.name(),
1377 language.manifest(),
1378 &delegate,
1379 cx,
1380 )
1381 .collect::<Vec<_>>()
1382 }
1383
1384 fn language_server_ids_for_buffer(
1385 &self,
1386 buffer: &Buffer,
1387 cx: &mut App,
1388 ) -> Vec<LanguageServerId> {
1389 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1390 let worktree_id = file.worktree_id(cx);
1391
1392 let path: Arc<RelPath> = file
1393 .path()
1394 .parent()
1395 .map(Arc::from)
1396 .unwrap_or_else(|| file.path().clone());
1397 let worktree_path = ProjectPath { worktree_id, path };
1398 self.language_server_ids_for_project_path(worktree_path, language, cx)
1399 } else {
1400 Vec::new()
1401 }
1402 }
1403
1404 fn language_servers_for_buffer<'a>(
1405 &'a self,
1406 buffer: &'a Buffer,
1407 cx: &'a mut App,
1408 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1409 self.language_server_ids_for_buffer(buffer, cx)
1410 .into_iter()
1411 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1412 LanguageServerState::Running {
1413 adapter, server, ..
1414 } => Some((adapter, server)),
1415 _ => None,
1416 })
1417 }
1418
1419 async fn execute_code_action_kind_locally(
1420 lsp_store: WeakEntity<LspStore>,
1421 mut buffers: Vec<Entity<Buffer>>,
1422 kind: CodeActionKind,
1423 push_to_history: bool,
1424 cx: &mut AsyncApp,
1425 ) -> anyhow::Result<ProjectTransaction> {
1426 // Do not allow multiple concurrent code actions requests for the
1427 // same buffer.
1428 lsp_store.update(cx, |this, cx| {
1429 let this = this.as_local_mut().unwrap();
1430 buffers.retain(|buffer| {
1431 this.buffers_being_formatted
1432 .insert(buffer.read(cx).remote_id())
1433 });
1434 })?;
1435 let _cleanup = defer({
1436 let this = lsp_store.clone();
1437 let mut cx = cx.clone();
1438 let buffers = &buffers;
1439 move || {
1440 this.update(&mut cx, |this, cx| {
1441 let this = this.as_local_mut().unwrap();
1442 for buffer in buffers {
1443 this.buffers_being_formatted
1444 .remove(&buffer.read(cx).remote_id());
1445 }
1446 })
1447 .ok();
1448 }
1449 });
1450 let mut project_transaction = ProjectTransaction::default();
1451
1452 for buffer in &buffers {
1453 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1454 buffer.update(cx, |buffer, cx| {
1455 lsp_store
1456 .as_local()
1457 .unwrap()
1458 .language_servers_for_buffer(buffer, cx)
1459 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1460 .collect::<Vec<_>>()
1461 })
1462 })?;
1463 for (_, language_server) in adapters_and_servers.iter() {
1464 let actions = Self::get_server_code_actions_from_action_kinds(
1465 &lsp_store,
1466 language_server.server_id(),
1467 vec![kind.clone()],
1468 buffer,
1469 cx,
1470 )
1471 .await?;
1472 Self::execute_code_actions_on_server(
1473 &lsp_store,
1474 language_server,
1475 actions,
1476 push_to_history,
1477 &mut project_transaction,
1478 cx,
1479 )
1480 .await?;
1481 }
1482 }
1483 Ok(project_transaction)
1484 }
1485
1486 async fn format_locally(
1487 lsp_store: WeakEntity<LspStore>,
1488 mut buffers: Vec<FormattableBuffer>,
1489 push_to_history: bool,
1490 trigger: FormatTrigger,
1491 logger: zlog::Logger,
1492 cx: &mut AsyncApp,
1493 ) -> anyhow::Result<ProjectTransaction> {
1494 // Do not allow multiple concurrent formatting requests for the
1495 // same buffer.
1496 lsp_store.update(cx, |this, cx| {
1497 let this = this.as_local_mut().unwrap();
1498 buffers.retain(|buffer| {
1499 this.buffers_being_formatted
1500 .insert(buffer.handle.read(cx).remote_id())
1501 });
1502 })?;
1503
1504 let _cleanup = defer({
1505 let this = lsp_store.clone();
1506 let mut cx = cx.clone();
1507 let buffers = &buffers;
1508 move || {
1509 this.update(&mut cx, |this, cx| {
1510 let this = this.as_local_mut().unwrap();
1511 for buffer in buffers {
1512 this.buffers_being_formatted
1513 .remove(&buffer.handle.read(cx).remote_id());
1514 }
1515 })
1516 .ok();
1517 }
1518 });
1519
1520 let mut project_transaction = ProjectTransaction::default();
1521
1522 for buffer in &buffers {
1523 zlog::debug!(
1524 logger =>
1525 "formatting buffer '{:?}'",
1526 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1527 );
1528 // Create an empty transaction to hold all of the formatting edits.
1529 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1530 // ensure no transactions created while formatting are
1531 // grouped with the previous transaction in the history
1532 // based on the transaction group interval
1533 buffer.finalize_last_transaction();
1534 buffer
1535 .start_transaction()
1536 .context("transaction already open")?;
1537 buffer.end_transaction(cx);
1538 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1539 buffer.finalize_last_transaction();
1540 anyhow::Ok(transaction_id)
1541 })?;
1542
1543 let result = Self::format_buffer_locally(
1544 lsp_store.clone(),
1545 buffer,
1546 formatting_transaction_id,
1547 trigger,
1548 logger,
1549 cx,
1550 )
1551 .await;
1552
1553 buffer.handle.update(cx, |buffer, cx| {
1554 let Some(formatting_transaction) =
1555 buffer.get_transaction(formatting_transaction_id).cloned()
1556 else {
1557 zlog::warn!(logger => "no formatting transaction");
1558 return;
1559 };
1560 if formatting_transaction.edit_ids.is_empty() {
1561 zlog::debug!(logger => "no changes made while formatting");
1562 buffer.forget_transaction(formatting_transaction_id);
1563 return;
1564 }
1565 if !push_to_history {
1566 zlog::trace!(logger => "forgetting format transaction");
1567 buffer.forget_transaction(formatting_transaction.id);
1568 }
1569 project_transaction
1570 .0
1571 .insert(cx.entity(), formatting_transaction);
1572 });
1573
1574 result?;
1575 }
1576
1577 Ok(project_transaction)
1578 }
1579
1580 async fn format_buffer_locally(
1581 lsp_store: WeakEntity<LspStore>,
1582 buffer: &FormattableBuffer,
1583 formatting_transaction_id: clock::Lamport,
1584 trigger: FormatTrigger,
1585 logger: zlog::Logger,
1586 cx: &mut AsyncApp,
1587 ) -> Result<()> {
1588 let (adapters_and_servers, settings, request_timeout) =
1589 lsp_store.update(cx, |lsp_store, cx| {
1590 buffer.handle.update(cx, |buffer, cx| {
1591 let adapters_and_servers = lsp_store
1592 .as_local()
1593 .unwrap()
1594 .language_servers_for_buffer(buffer, cx)
1595 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1596 .collect::<Vec<_>>();
1597 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1598 let request_timeout = ProjectSettings::get_global(cx)
1599 .global_lsp_settings
1600 .get_request_timeout();
1601 (adapters_and_servers, settings, request_timeout)
1602 })
1603 })?;
1604
1605 // handle whitespace formatting
1606 if settings.remove_trailing_whitespace_on_save {
1607 zlog::trace!(logger => "removing trailing whitespace");
1608 let diff = buffer
1609 .handle
1610 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1611 .await;
1612 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1613 buffer.apply_diff(diff, cx);
1614 })?;
1615 }
1616
1617 if settings.ensure_final_newline_on_save {
1618 zlog::trace!(logger => "ensuring final newline");
1619 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1620 buffer.ensure_final_newline(cx);
1621 })?;
1622 }
1623
1624 // Formatter for `code_actions_on_format` that runs before
1625 // the rest of the formatters
1626 let mut code_actions_on_format_formatters = None;
1627 let should_run_code_actions_on_format = !matches!(
1628 (trigger, &settings.format_on_save),
1629 (FormatTrigger::Save, &FormatOnSave::Off)
1630 );
1631 if should_run_code_actions_on_format {
1632 let have_code_actions_to_run_on_format = settings
1633 .code_actions_on_format
1634 .values()
1635 .any(|enabled| *enabled);
1636 if have_code_actions_to_run_on_format {
1637 zlog::trace!(logger => "going to run code actions on format");
1638 code_actions_on_format_formatters = Some(
1639 settings
1640 .code_actions_on_format
1641 .iter()
1642 .filter_map(|(action, enabled)| enabled.then_some(action))
1643 .cloned()
1644 .map(Formatter::CodeAction)
1645 .collect::<Vec<_>>(),
1646 );
1647 }
1648 }
1649
1650 let formatters = match (trigger, &settings.format_on_save) {
1651 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1652 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1653 settings.formatter.as_ref()
1654 }
1655 };
1656
1657 let formatters = code_actions_on_format_formatters
1658 .iter()
1659 .flatten()
1660 .chain(formatters);
1661
1662 for formatter in formatters {
1663 let formatter = if formatter == &Formatter::Auto {
1664 if settings.prettier.allowed {
1665 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1666 &Formatter::Prettier
1667 } else {
1668 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1669 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1670 }
1671 } else {
1672 formatter
1673 };
1674 if let Err(err) = Self::apply_formatter(
1675 formatter,
1676 &lsp_store,
1677 buffer,
1678 formatting_transaction_id,
1679 &adapters_and_servers,
1680 &settings,
1681 request_timeout,
1682 logger,
1683 cx,
1684 )
1685 .await
1686 {
1687 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1688 }
1689 }
1690
1691 Ok(())
1692 }
1693
1694 async fn apply_formatter(
1695 formatter: &Formatter,
1696 lsp_store: &WeakEntity<LspStore>,
1697 buffer: &FormattableBuffer,
1698 formatting_transaction_id: clock::Lamport,
1699 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1700 settings: &LanguageSettings,
1701 request_timeout: Duration,
1702 logger: zlog::Logger,
1703 cx: &mut AsyncApp,
1704 ) -> anyhow::Result<()> {
1705 match formatter {
1706 Formatter::None => {
1707 zlog::trace!(logger => "skipping formatter 'none'");
1708 return Ok(());
1709 }
1710 Formatter::Auto => {
1711 debug_panic!("Auto resolved above");
1712 return Ok(());
1713 }
1714 Formatter::Prettier => {
1715 let logger = zlog::scoped!(logger => "prettier");
1716 zlog::trace!(logger => "formatting");
1717 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1718
1719 // When selection ranges are provided (via FormatSelections), we pass the
1720 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1721 // After diffing, we filter the resulting edits to only keep those that
1722 // overlap with the original byte-level selection ranges.
1723 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1724 Some(ranges) if !ranges.is_empty() => {
1725 let (utf16_range, byte_ranges) =
1726 buffer.handle.read_with(cx, |buffer, _cx| {
1727 let snapshot = buffer.snapshot();
1728 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1729 let mut max_end_utf16 = OffsetUtf16(0);
1730 let mut byte_ranges = Vec::with_capacity(ranges.len());
1731 for range in ranges {
1732 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1733 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1734 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1735 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1736
1737 let start_byte = range.start.to_offset(&snapshot);
1738 let end_byte = range.end.to_offset(&snapshot);
1739 byte_ranges.push(start_byte..end_byte);
1740 }
1741 (min_start_utf16..max_end_utf16, byte_ranges)
1742 });
1743 (Some(utf16_range), Some(byte_ranges))
1744 }
1745 _ => (None, None),
1746 };
1747
1748 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1749 lsp_store.prettier_store().unwrap().downgrade()
1750 })?;
1751 let diff = prettier_store::format_with_prettier(
1752 &prettier,
1753 &buffer.handle,
1754 range_utf16,
1755 cx,
1756 )
1757 .await
1758 .transpose()?;
1759 let Some(mut diff) = diff else {
1760 zlog::trace!(logger => "No changes");
1761 return Ok(());
1762 };
1763
1764 if let Some(byte_ranges) = byte_ranges {
1765 diff.edits.retain(|(edit_range, _)| {
1766 byte_ranges.iter().any(|selection_range| {
1767 edit_range.start < selection_range.end
1768 && edit_range.end > selection_range.start
1769 })
1770 });
1771 if diff.edits.is_empty() {
1772 zlog::trace!(logger => "No changes within selection");
1773 return Ok(());
1774 }
1775 }
1776
1777 extend_formatting_transaction(
1778 buffer,
1779 formatting_transaction_id,
1780 cx,
1781 |buffer, cx| {
1782 buffer.apply_diff(diff, cx);
1783 },
1784 )?;
1785 }
1786 Formatter::External { command, arguments } => {
1787 let logger = zlog::scoped!(logger => "command");
1788
1789 if buffer.ranges.is_some() {
1790 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1791 return Ok(());
1792 }
1793
1794 zlog::trace!(logger => "formatting");
1795 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1796
1797 let diff =
1798 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1799 .await
1800 .with_context(|| {
1801 format!("Failed to format buffer via external command: {}", command)
1802 })?;
1803 let Some(diff) = diff else {
1804 zlog::trace!(logger => "No changes");
1805 return Ok(());
1806 };
1807
1808 extend_formatting_transaction(
1809 buffer,
1810 formatting_transaction_id,
1811 cx,
1812 |buffer, cx| {
1813 buffer.apply_diff(diff, cx);
1814 },
1815 )?;
1816 }
1817 Formatter::LanguageServer(specifier) => {
1818 let logger = zlog::scoped!(logger => "language-server");
1819 zlog::trace!(logger => "formatting");
1820 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1821
1822 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1823 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1824 return Ok(());
1825 };
1826
1827 let language_server = match specifier {
1828 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1829 adapters_and_servers.iter().find_map(|(adapter, server)| {
1830 if adapter.name.0.as_ref() == name {
1831 Some(server.clone())
1832 } else {
1833 None
1834 }
1835 })
1836 }
1837 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1838 .iter()
1839 .find(|(_, server)| Self::server_supports_formatting(server))
1840 .map(|(_, server)| server.clone()),
1841 };
1842
1843 let Some(language_server) = language_server else {
1844 log::debug!(
1845 "No language server found to format buffer '{:?}'. Skipping",
1846 buffer_path_abs.as_path().to_string_lossy()
1847 );
1848 return Ok(());
1849 };
1850
1851 zlog::trace!(
1852 logger =>
1853 "Formatting buffer '{:?}' using language server '{:?}'",
1854 buffer_path_abs.as_path().to_string_lossy(),
1855 language_server.name()
1856 );
1857
1858 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1859 zlog::trace!(logger => "formatting ranges");
1860 Self::format_ranges_via_lsp(
1861 &lsp_store,
1862 &buffer.handle,
1863 ranges,
1864 buffer_path_abs,
1865 &language_server,
1866 &settings,
1867 cx,
1868 )
1869 .await
1870 .context("Failed to format ranges via language server")?
1871 } else {
1872 zlog::trace!(logger => "formatting full");
1873 Self::format_via_lsp(
1874 &lsp_store,
1875 &buffer.handle,
1876 buffer_path_abs,
1877 &language_server,
1878 &settings,
1879 cx,
1880 )
1881 .await
1882 .context("failed to format via language server")?
1883 };
1884
1885 if edits.is_empty() {
1886 zlog::trace!(logger => "No changes");
1887 return Ok(());
1888 }
1889 extend_formatting_transaction(
1890 buffer,
1891 formatting_transaction_id,
1892 cx,
1893 |buffer, cx| {
1894 buffer.edit(edits, None, cx);
1895 },
1896 )?;
1897 }
1898 Formatter::CodeAction(code_action_name) => {
1899 let logger = zlog::scoped!(logger => "code-actions");
1900 zlog::trace!(logger => "formatting");
1901 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1902
1903 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1904 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1905 return Ok(());
1906 };
1907
1908 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1909 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1910
1911 let mut actions_and_servers = Vec::new();
1912
1913 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1914 let actions_result = Self::get_server_code_actions_from_action_kinds(
1915 &lsp_store,
1916 language_server.server_id(),
1917 vec![code_action_kind.clone()],
1918 &buffer.handle,
1919 cx,
1920 )
1921 .await
1922 .with_context(|| {
1923 format!(
1924 "Failed to resolve code action {:?} with language server {}",
1925 code_action_kind,
1926 language_server.name()
1927 )
1928 });
1929 let Ok(actions) = actions_result else {
1930 // note: it may be better to set result to the error and break formatters here
1931 // but for now we try to execute the actions that we can resolve and skip the rest
1932 zlog::error!(
1933 logger =>
1934 "Failed to resolve code action {:?} with language server {}",
1935 code_action_kind,
1936 language_server.name()
1937 );
1938 continue;
1939 };
1940 for action in actions {
1941 actions_and_servers.push((action, index));
1942 }
1943 }
1944
1945 if actions_and_servers.is_empty() {
1946 zlog::warn!(logger => "No code actions were resolved, continuing");
1947 return Ok(());
1948 }
1949
1950 'actions: for (mut action, server_index) in actions_and_servers {
1951 let server = &adapters_and_servers[server_index].1;
1952
1953 let describe_code_action = |action: &CodeAction| {
1954 format!(
1955 "code action '{}' with title \"{}\" on server {}",
1956 action
1957 .lsp_action
1958 .action_kind()
1959 .unwrap_or("unknown".into())
1960 .as_str(),
1961 action.lsp_action.title(),
1962 server.name(),
1963 )
1964 };
1965
1966 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1967
1968 if let Err(err) =
1969 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1970 {
1971 zlog::error!(
1972 logger =>
1973 "Failed to resolve {}. Error: {}",
1974 describe_code_action(&action),
1975 err
1976 );
1977 continue;
1978 }
1979
1980 if let Some(edit) = action.lsp_action.edit().cloned() {
1981 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1982 // but filters out and logs warnings for code actions that require unreasonably
1983 // difficult handling on our part, such as:
1984 // - applying edits that call commands
1985 // which can result in arbitrary workspace edits being sent from the server that
1986 // have no way of being tied back to the command that initiated them (i.e. we
1987 // can't know which edits are part of the format request, or if the server is done sending
1988 // actions in response to the command)
1989 // - actions that create/delete/modify/rename files other than the one we are formatting
1990 // as we then would need to handle such changes correctly in the local history as well
1991 // as the remote history through the ProjectTransaction
1992 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1993 // Supporting these actions is not impossible, but not supported as of yet.
1994 if edit.changes.is_none() && edit.document_changes.is_none() {
1995 zlog::trace!(
1996 logger =>
1997 "No changes for code action. Skipping {}",
1998 describe_code_action(&action),
1999 );
2000 continue;
2001 }
2002
2003 let mut operations = Vec::new();
2004 if let Some(document_changes) = edit.document_changes {
2005 match document_changes {
2006 lsp::DocumentChanges::Edits(edits) => operations.extend(
2007 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2008 ),
2009 lsp::DocumentChanges::Operations(ops) => operations = ops,
2010 }
2011 } else if let Some(changes) = edit.changes {
2012 operations.extend(changes.into_iter().map(|(uri, edits)| {
2013 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2014 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2015 uri,
2016 version: None,
2017 },
2018 edits: edits.into_iter().map(Edit::Plain).collect(),
2019 })
2020 }));
2021 }
2022
2023 let mut edits = Vec::with_capacity(operations.len());
2024
2025 if operations.is_empty() {
2026 zlog::trace!(
2027 logger =>
2028 "No changes for code action. Skipping {}",
2029 describe_code_action(&action),
2030 );
2031 continue;
2032 }
2033 for operation in operations {
2034 let op = match operation {
2035 lsp::DocumentChangeOperation::Edit(op) => op,
2036 lsp::DocumentChangeOperation::Op(_) => {
2037 zlog::warn!(
2038 logger =>
2039 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2040 describe_code_action(&action),
2041 );
2042 continue 'actions;
2043 }
2044 };
2045 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2046 zlog::warn!(
2047 logger =>
2048 "Failed to convert URI '{:?}' to file path. Skipping {}",
2049 &op.text_document.uri,
2050 describe_code_action(&action),
2051 );
2052 continue 'actions;
2053 };
2054 if &file_path != buffer_path_abs {
2055 zlog::warn!(
2056 logger =>
2057 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2058 file_path,
2059 buffer_path_abs,
2060 describe_code_action(&action),
2061 );
2062 continue 'actions;
2063 }
2064
2065 let mut lsp_edits = Vec::new();
2066 for edit in op.edits {
2067 match edit {
2068 Edit::Plain(edit) => {
2069 if !lsp_edits.contains(&edit) {
2070 lsp_edits.push(edit);
2071 }
2072 }
2073 Edit::Annotated(edit) => {
2074 if !lsp_edits.contains(&edit.text_edit) {
2075 lsp_edits.push(edit.text_edit);
2076 }
2077 }
2078 Edit::Snippet(_) => {
2079 zlog::warn!(
2080 logger =>
2081 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2082 describe_code_action(&action),
2083 );
2084 continue 'actions;
2085 }
2086 }
2087 }
2088 let edits_result = lsp_store
2089 .update(cx, |lsp_store, cx| {
2090 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2091 &buffer.handle,
2092 lsp_edits,
2093 server.server_id(),
2094 op.text_document.version,
2095 cx,
2096 )
2097 })?
2098 .await;
2099 let Ok(resolved_edits) = edits_result else {
2100 zlog::warn!(
2101 logger =>
2102 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2103 buffer_path_abs.as_path(),
2104 describe_code_action(&action),
2105 );
2106 continue 'actions;
2107 };
2108 edits.extend(resolved_edits);
2109 }
2110
2111 if edits.is_empty() {
2112 zlog::warn!(logger => "No edits resolved from LSP");
2113 continue;
2114 }
2115
2116 extend_formatting_transaction(
2117 buffer,
2118 formatting_transaction_id,
2119 cx,
2120 |buffer, cx| {
2121 zlog::info!(
2122 "Applying edits {edits:?}. Content: {:?}",
2123 buffer.text()
2124 );
2125 buffer.edit(edits, None, cx);
2126 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2127 },
2128 )?;
2129 }
2130
2131 let Some(command) = action.lsp_action.command() else {
2132 continue;
2133 };
2134
2135 zlog::warn!(
2136 logger =>
2137 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2138 &command.command,
2139 );
2140
2141 let server_capabilities = server.capabilities();
2142 let available_commands = server_capabilities
2143 .execute_command_provider
2144 .as_ref()
2145 .map(|options| options.commands.as_slice())
2146 .unwrap_or_default();
2147 if !available_commands.contains(&command.command) {
2148 zlog::warn!(
2149 logger =>
2150 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2151 command.command,
2152 server.name(),
2153 );
2154 continue;
2155 }
2156
2157 extend_formatting_transaction(
2158 buffer,
2159 formatting_transaction_id,
2160 cx,
2161 |_, _| {},
2162 )?;
2163 zlog::info!(logger => "Executing command {}", &command.command);
2164
2165 lsp_store.update(cx, |this, _| {
2166 this.as_local_mut()
2167 .unwrap()
2168 .last_workspace_edits_by_language_server
2169 .remove(&server.server_id());
2170 })?;
2171
2172 let execute_command_result = server
2173 .request::<lsp::request::ExecuteCommand>(
2174 lsp::ExecuteCommandParams {
2175 command: command.command.clone(),
2176 arguments: command.arguments.clone().unwrap_or_default(),
2177 ..Default::default()
2178 },
2179 request_timeout,
2180 )
2181 .await
2182 .into_response();
2183
2184 if execute_command_result.is_err() {
2185 zlog::error!(
2186 logger =>
2187 "Failed to execute command '{}' as part of {}",
2188 &command.command,
2189 describe_code_action(&action),
2190 );
2191 continue 'actions;
2192 }
2193
2194 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2195 this.as_local_mut()
2196 .unwrap()
2197 .last_workspace_edits_by_language_server
2198 .remove(&server.server_id())
2199 .unwrap_or_default()
2200 })?;
2201
2202 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2203 {
2204 zlog::trace!(
2205 logger =>
2206 "Successfully captured {} edits that resulted from command {}",
2207 transaction.edit_ids.len(),
2208 &command.command,
2209 );
2210 let transaction_id_project_transaction = transaction.id;
2211 buffer.handle.update(cx, |buffer, _| {
2212 // it may have been removed from history if push_to_history was
2213 // false in deserialize_workspace_edit. If so push it so we
2214 // can merge it with the format transaction
2215 // and pop the combined transaction off the history stack
2216 // later if push_to_history is false
2217 if buffer.get_transaction(transaction.id).is_none() {
2218 buffer.push_transaction(transaction, Instant::now());
2219 }
2220 buffer.merge_transactions(
2221 transaction_id_project_transaction,
2222 formatting_transaction_id,
2223 );
2224 });
2225 }
2226
2227 if project_transaction_command.0.is_empty() {
2228 continue;
2229 }
2230
2231 let mut extra_buffers = String::new();
2232 for buffer in project_transaction_command.0.keys() {
2233 buffer.read_with(cx, |b, cx| {
2234 let Some(path) = b.project_path(cx) else {
2235 return;
2236 };
2237
2238 if !extra_buffers.is_empty() {
2239 extra_buffers.push_str(", ");
2240 }
2241 extra_buffers.push_str(path.path.as_unix_str());
2242 });
2243 }
2244 zlog::warn!(
2245 logger =>
2246 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2247 &command.command,
2248 extra_buffers,
2249 );
2250 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2251 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2252 // add it so it's included, and merge it into the format transaction when its created later
2253 }
2254 }
2255 }
2256
2257 Ok(())
2258 }
2259
2260 pub async fn format_ranges_via_lsp(
2261 this: &WeakEntity<LspStore>,
2262 buffer_handle: &Entity<Buffer>,
2263 ranges: &[Range<Anchor>],
2264 abs_path: &Path,
2265 language_server: &Arc<LanguageServer>,
2266 settings: &LanguageSettings,
2267 cx: &mut AsyncApp,
2268 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2269 let capabilities = &language_server.capabilities();
2270 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2271 if range_formatting_provider == Some(&OneOf::Left(false)) {
2272 anyhow::bail!(
2273 "{} language server does not support range formatting",
2274 language_server.name()
2275 );
2276 }
2277
2278 let uri = file_path_to_lsp_url(abs_path)?;
2279 let text_document = lsp::TextDocumentIdentifier::new(uri);
2280
2281 let request_timeout = cx.update(|app| {
2282 ProjectSettings::get_global(app)
2283 .global_lsp_settings
2284 .get_request_timeout()
2285 });
2286 let lsp_edits = {
2287 let mut lsp_ranges = Vec::new();
2288 this.update(cx, |_this, cx| {
2289 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2290 // not have been sent to the language server. This seems like a fairly systemic
2291 // issue, though, the resolution probably is not specific to formatting.
2292 //
2293 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2294 // LSP.
2295 let snapshot = buffer_handle.read(cx).snapshot();
2296 for range in ranges {
2297 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2298 }
2299 anyhow::Ok(())
2300 })??;
2301
2302 let mut edits = None;
2303 for range in lsp_ranges {
2304 if let Some(mut edit) = language_server
2305 .request::<lsp::request::RangeFormatting>(
2306 lsp::DocumentRangeFormattingParams {
2307 text_document: text_document.clone(),
2308 range,
2309 options: lsp_command::lsp_formatting_options(settings),
2310 work_done_progress_params: Default::default(),
2311 },
2312 request_timeout,
2313 )
2314 .await
2315 .into_response()?
2316 {
2317 edits.get_or_insert_with(Vec::new).append(&mut edit);
2318 }
2319 }
2320 edits
2321 };
2322
2323 if let Some(lsp_edits) = lsp_edits {
2324 this.update(cx, |this, cx| {
2325 this.as_local_mut().unwrap().edits_from_lsp(
2326 buffer_handle,
2327 lsp_edits,
2328 language_server.server_id(),
2329 None,
2330 cx,
2331 )
2332 })?
2333 .await
2334 } else {
2335 Ok(Vec::with_capacity(0))
2336 }
2337 }
2338
2339 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2340 let capabilities = server.capabilities();
2341 let formatting = capabilities.document_formatting_provider.as_ref();
2342 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2343 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2344 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2345 }
2346
2347 async fn format_via_lsp(
2348 this: &WeakEntity<LspStore>,
2349 buffer: &Entity<Buffer>,
2350 abs_path: &Path,
2351 language_server: &Arc<LanguageServer>,
2352 settings: &LanguageSettings,
2353 cx: &mut AsyncApp,
2354 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2355 let logger = zlog::scoped!("lsp_format");
2356 zlog::debug!(logger => "Formatting via LSP");
2357
2358 let uri = file_path_to_lsp_url(abs_path)?;
2359 let text_document = lsp::TextDocumentIdentifier::new(uri);
2360 let capabilities = &language_server.capabilities();
2361
2362 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2363 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2364
2365 let request_timeout = cx.update(|app| {
2366 ProjectSettings::get_global(app)
2367 .global_lsp_settings
2368 .get_request_timeout()
2369 });
2370
2371 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2372 let _timer = zlog::time!(logger => "format-full");
2373 language_server
2374 .request::<lsp::request::Formatting>(
2375 lsp::DocumentFormattingParams {
2376 text_document,
2377 options: lsp_command::lsp_formatting_options(settings),
2378 work_done_progress_params: Default::default(),
2379 },
2380 request_timeout,
2381 )
2382 .await
2383 .into_response()?
2384 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2385 let _timer = zlog::time!(logger => "format-range");
2386 let buffer_start = lsp::Position::new(0, 0);
2387 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2388 language_server
2389 .request::<lsp::request::RangeFormatting>(
2390 lsp::DocumentRangeFormattingParams {
2391 text_document: text_document.clone(),
2392 range: lsp::Range::new(buffer_start, buffer_end),
2393 options: lsp_command::lsp_formatting_options(settings),
2394 work_done_progress_params: Default::default(),
2395 },
2396 request_timeout,
2397 )
2398 .await
2399 .into_response()?
2400 } else {
2401 None
2402 };
2403
2404 if let Some(lsp_edits) = lsp_edits {
2405 this.update(cx, |this, cx| {
2406 this.as_local_mut().unwrap().edits_from_lsp(
2407 buffer,
2408 lsp_edits,
2409 language_server.server_id(),
2410 None,
2411 cx,
2412 )
2413 })?
2414 .await
2415 } else {
2416 Ok(Vec::with_capacity(0))
2417 }
2418 }
2419
2420 async fn format_via_external_command(
2421 buffer: &FormattableBuffer,
2422 command: &str,
2423 arguments: Option<&[String]>,
2424 cx: &mut AsyncApp,
2425 ) -> Result<Option<Diff>> {
2426 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2427 let file = File::from_dyn(buffer.file())?;
2428 let worktree = file.worktree.read(cx);
2429 let mut worktree_path = worktree.abs_path().to_path_buf();
2430 if worktree.root_entry()?.is_file() {
2431 worktree_path.pop();
2432 }
2433 Some(worktree_path)
2434 });
2435
2436 use util::command::Stdio;
2437 let mut child = util::command::new_command(command);
2438
2439 if let Some(buffer_env) = buffer.env.as_ref() {
2440 child.envs(buffer_env);
2441 }
2442
2443 if let Some(working_dir_path) = working_dir_path {
2444 child.current_dir(working_dir_path);
2445 }
2446
2447 if let Some(arguments) = arguments {
2448 child.args(arguments.iter().map(|arg| {
2449 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2450 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2451 } else {
2452 arg.replace("{buffer_path}", "Untitled")
2453 }
2454 }));
2455 }
2456
2457 let mut child = child
2458 .stdin(Stdio::piped())
2459 .stdout(Stdio::piped())
2460 .stderr(Stdio::piped())
2461 .spawn()?;
2462
2463 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2464 let text = buffer
2465 .handle
2466 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2467 for chunk in text.chunks() {
2468 stdin.write_all(chunk.as_bytes()).await?;
2469 }
2470 stdin.flush().await?;
2471
2472 let output = child.output().await?;
2473 anyhow::ensure!(
2474 output.status.success(),
2475 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2476 output.status.code(),
2477 String::from_utf8_lossy(&output.stdout),
2478 String::from_utf8_lossy(&output.stderr),
2479 );
2480
2481 let stdout = String::from_utf8(output.stdout)?;
2482 Ok(Some(
2483 buffer
2484 .handle
2485 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2486 .await,
2487 ))
2488 }
2489
2490 async fn try_resolve_code_action(
2491 lang_server: &LanguageServer,
2492 action: &mut CodeAction,
2493 request_timeout: Duration,
2494 ) -> anyhow::Result<()> {
2495 match &mut action.lsp_action {
2496 LspAction::Action(lsp_action) => {
2497 if !action.resolved
2498 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2499 && lsp_action.data.is_some()
2500 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2501 {
2502 **lsp_action = lang_server
2503 .request::<lsp::request::CodeActionResolveRequest>(
2504 *lsp_action.clone(),
2505 request_timeout,
2506 )
2507 .await
2508 .into_response()?;
2509 }
2510 }
2511 LspAction::CodeLens(lens) => {
2512 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2513 *lens = lang_server
2514 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2515 .await
2516 .into_response()?;
2517 }
2518 }
2519 LspAction::Command(_) => {}
2520 }
2521
2522 action.resolved = true;
2523 anyhow::Ok(())
2524 }
2525
2526 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2527 let buffer = buffer_handle.read(cx);
2528
2529 let file = buffer.file().cloned();
2530
2531 let Some(file) = File::from_dyn(file.as_ref()) else {
2532 return;
2533 };
2534 if !file.is_local() {
2535 return;
2536 }
2537 let path = ProjectPath::from_file(file, cx);
2538 let worktree_id = file.worktree_id(cx);
2539 let language = buffer.language().cloned();
2540
2541 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2542 for (server_id, diagnostics) in
2543 diagnostics.get(file.path()).cloned().unwrap_or_default()
2544 {
2545 self.update_buffer_diagnostics(
2546 buffer_handle,
2547 server_id,
2548 None,
2549 None,
2550 None,
2551 Vec::new(),
2552 diagnostics,
2553 cx,
2554 )
2555 .log_err();
2556 }
2557 }
2558 let Some(language) = language else {
2559 return;
2560 };
2561 let Some(snapshot) = self
2562 .worktree_store
2563 .read(cx)
2564 .worktree_for_id(worktree_id, cx)
2565 .map(|worktree| worktree.read(cx).snapshot())
2566 else {
2567 return;
2568 };
2569 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2570
2571 for server_id in
2572 self.lsp_tree
2573 .get(path, language.name(), language.manifest(), &delegate, cx)
2574 {
2575 let server = self
2576 .language_servers
2577 .get(&server_id)
2578 .and_then(|server_state| {
2579 if let LanguageServerState::Running { server, .. } = server_state {
2580 Some(server.clone())
2581 } else {
2582 None
2583 }
2584 });
2585 let server = match server {
2586 Some(server) => server,
2587 None => continue,
2588 };
2589
2590 buffer_handle.update(cx, |buffer, cx| {
2591 buffer.set_completion_triggers(
2592 server.server_id(),
2593 server
2594 .capabilities()
2595 .completion_provider
2596 .as_ref()
2597 .and_then(|provider| {
2598 provider
2599 .trigger_characters
2600 .as_ref()
2601 .map(|characters| characters.iter().cloned().collect())
2602 })
2603 .unwrap_or_default(),
2604 cx,
2605 );
2606 });
2607 }
2608 }
2609
2610 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2611 buffer.update(cx, |buffer, cx| {
2612 let Some(language) = buffer.language() else {
2613 return;
2614 };
2615 let path = ProjectPath {
2616 worktree_id: old_file.worktree_id(cx),
2617 path: old_file.path.clone(),
2618 };
2619 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2620 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2621 buffer.set_completion_triggers(server_id, Default::default(), cx);
2622 }
2623 });
2624 }
2625
2626 fn update_buffer_diagnostics(
2627 &mut self,
2628 buffer: &Entity<Buffer>,
2629 server_id: LanguageServerId,
2630 registration_id: Option<Option<SharedString>>,
2631 result_id: Option<SharedString>,
2632 version: Option<i32>,
2633 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2634 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2635 cx: &mut Context<LspStore>,
2636 ) -> Result<()> {
2637 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2638 Ordering::Equal
2639 .then_with(|| b.is_primary.cmp(&a.is_primary))
2640 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2641 .then_with(|| a.severity.cmp(&b.severity))
2642 .then_with(|| a.message.cmp(&b.message))
2643 }
2644
2645 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2646 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2647 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2648
2649 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2650 Ordering::Equal
2651 .then_with(|| a.range.start.cmp(&b.range.start))
2652 .then_with(|| b.range.end.cmp(&a.range.end))
2653 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2654 });
2655
2656 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2657
2658 let edits_since_save = std::cell::LazyCell::new(|| {
2659 let saved_version = buffer.read(cx).saved_version();
2660 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2661 });
2662
2663 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2664
2665 for (new_diagnostic, entry) in diagnostics {
2666 let start;
2667 let end;
2668 if new_diagnostic && entry.diagnostic.is_disk_based {
2669 // Some diagnostics are based on files on disk instead of buffers'
2670 // current contents. Adjust these diagnostics' ranges to reflect
2671 // any unsaved edits.
2672 // Do not alter the reused ones though, as their coordinates were stored as anchors
2673 // and were properly adjusted on reuse.
2674 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2675 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2676 } else {
2677 start = entry.range.start;
2678 end = entry.range.end;
2679 }
2680
2681 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2682 ..snapshot.clip_point_utf16(end, Bias::Right);
2683
2684 // Expand empty ranges by one codepoint
2685 if range.start == range.end {
2686 // This will be go to the next boundary when being clipped
2687 range.end.column += 1;
2688 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2689 if range.start == range.end && range.end.column > 0 {
2690 range.start.column -= 1;
2691 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2692 }
2693 }
2694
2695 sanitized_diagnostics.push(DiagnosticEntry {
2696 range,
2697 diagnostic: entry.diagnostic,
2698 });
2699 }
2700 drop(edits_since_save);
2701
2702 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2703 buffer.update(cx, |buffer, cx| {
2704 if let Some(registration_id) = registration_id {
2705 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2706 self.buffer_pull_diagnostics_result_ids
2707 .entry(server_id)
2708 .or_default()
2709 .entry(registration_id)
2710 .or_default()
2711 .insert(abs_path, result_id);
2712 }
2713 }
2714
2715 buffer.update_diagnostics(server_id, set, cx)
2716 });
2717
2718 Ok(())
2719 }
2720
2721 fn register_language_server_for_invisible_worktree(
2722 &mut self,
2723 worktree: &Entity<Worktree>,
2724 language_server_id: LanguageServerId,
2725 cx: &mut App,
2726 ) {
2727 let worktree = worktree.read(cx);
2728 let worktree_id = worktree.id();
2729 debug_assert!(!worktree.is_visible());
2730 let Some(mut origin_seed) = self
2731 .language_server_ids
2732 .iter()
2733 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2734 else {
2735 return;
2736 };
2737 origin_seed.worktree_id = worktree_id;
2738 self.language_server_ids
2739 .entry(origin_seed)
2740 .or_insert_with(|| UnifiedLanguageServer {
2741 id: language_server_id,
2742 project_roots: Default::default(),
2743 });
2744 }
2745
2746 fn register_buffer_with_language_servers(
2747 &mut self,
2748 buffer_handle: &Entity<Buffer>,
2749 only_register_servers: HashSet<LanguageServerSelector>,
2750 cx: &mut Context<LspStore>,
2751 ) {
2752 let buffer = buffer_handle.read(cx);
2753 let buffer_id = buffer.remote_id();
2754
2755 let Some(file) = File::from_dyn(buffer.file()) else {
2756 return;
2757 };
2758 if !file.is_local() {
2759 return;
2760 }
2761
2762 let abs_path = file.abs_path(cx);
2763 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2764 return;
2765 };
2766 let initial_snapshot = buffer.text_snapshot();
2767 let worktree_id = file.worktree_id(cx);
2768
2769 let Some(language) = buffer.language().cloned() else {
2770 return;
2771 };
2772 let path: Arc<RelPath> = file
2773 .path()
2774 .parent()
2775 .map(Arc::from)
2776 .unwrap_or_else(|| file.path().clone());
2777 let Some(worktree) = self
2778 .worktree_store
2779 .read(cx)
2780 .worktree_for_id(worktree_id, cx)
2781 else {
2782 return;
2783 };
2784 let language_name = language.name();
2785 let (reused, delegate, servers) = self
2786 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2787 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2788 .unwrap_or_else(|| {
2789 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2790 let delegate: Arc<dyn ManifestDelegate> =
2791 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2792
2793 let servers = self
2794 .lsp_tree
2795 .walk(
2796 ProjectPath { worktree_id, path },
2797 language.name(),
2798 language.manifest(),
2799 &delegate,
2800 cx,
2801 )
2802 .collect::<Vec<_>>();
2803 (false, lsp_delegate, servers)
2804 });
2805 let servers_and_adapters = servers
2806 .into_iter()
2807 .filter_map(|server_node| {
2808 if reused && server_node.server_id().is_none() {
2809 return None;
2810 }
2811 if !only_register_servers.is_empty() {
2812 if let Some(server_id) = server_node.server_id()
2813 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2814 {
2815 return None;
2816 }
2817 if let Some(name) = server_node.name()
2818 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2819 {
2820 return None;
2821 }
2822 }
2823
2824 let server_id = server_node.server_id_or_init(|disposition| {
2825 let path = &disposition.path;
2826
2827 {
2828 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2829
2830 let server_id = self.get_or_insert_language_server(
2831 &worktree,
2832 delegate.clone(),
2833 disposition,
2834 &language_name,
2835 cx,
2836 );
2837
2838 if let Some(state) = self.language_servers.get(&server_id)
2839 && let Ok(uri) = uri
2840 {
2841 state.add_workspace_folder(uri);
2842 };
2843 server_id
2844 }
2845 })?;
2846 let server_state = self.language_servers.get(&server_id)?;
2847 if let LanguageServerState::Running {
2848 server, adapter, ..
2849 } = server_state
2850 {
2851 Some((server.clone(), adapter.clone()))
2852 } else {
2853 None
2854 }
2855 })
2856 .collect::<Vec<_>>();
2857 for (server, adapter) in servers_and_adapters {
2858 buffer_handle.update(cx, |buffer, cx| {
2859 buffer.set_completion_triggers(
2860 server.server_id(),
2861 server
2862 .capabilities()
2863 .completion_provider
2864 .as_ref()
2865 .and_then(|provider| {
2866 provider
2867 .trigger_characters
2868 .as_ref()
2869 .map(|characters| characters.iter().cloned().collect())
2870 })
2871 .unwrap_or_default(),
2872 cx,
2873 );
2874 });
2875
2876 let snapshot = LspBufferSnapshot {
2877 version: 0,
2878 snapshot: initial_snapshot.clone(),
2879 };
2880
2881 let mut registered = false;
2882 self.buffer_snapshots
2883 .entry(buffer_id)
2884 .or_default()
2885 .entry(server.server_id())
2886 .or_insert_with(|| {
2887 registered = true;
2888 server.register_buffer(
2889 uri.clone(),
2890 adapter.language_id(&language.name()),
2891 0,
2892 initial_snapshot.text(),
2893 );
2894
2895 vec![snapshot]
2896 });
2897
2898 self.buffers_opened_in_servers
2899 .entry(buffer_id)
2900 .or_default()
2901 .insert(server.server_id());
2902 if registered {
2903 cx.emit(LspStoreEvent::LanguageServerUpdate {
2904 language_server_id: server.server_id(),
2905 name: None,
2906 message: proto::update_language_server::Variant::RegisteredForBuffer(
2907 proto::RegisteredForBuffer {
2908 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2909 buffer_id: buffer_id.to_proto(),
2910 },
2911 ),
2912 });
2913 }
2914 }
2915 }
2916
2917 fn reuse_existing_language_server<'lang_name>(
2918 &self,
2919 server_tree: &LanguageServerTree,
2920 worktree: &Entity<Worktree>,
2921 language_name: &'lang_name LanguageName,
2922 cx: &mut App,
2923 ) -> Option<(
2924 Arc<LocalLspAdapterDelegate>,
2925 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2926 )> {
2927 if worktree.read(cx).is_visible() {
2928 return None;
2929 }
2930
2931 let worktree_store = self.worktree_store.read(cx);
2932 let servers = server_tree
2933 .instances
2934 .iter()
2935 .filter(|(worktree_id, _)| {
2936 worktree_store
2937 .worktree_for_id(**worktree_id, cx)
2938 .is_some_and(|worktree| worktree.read(cx).is_visible())
2939 })
2940 .flat_map(|(worktree_id, servers)| {
2941 servers
2942 .roots
2943 .iter()
2944 .flat_map(|(_, language_servers)| language_servers)
2945 .map(move |(_, (server_node, server_languages))| {
2946 (worktree_id, server_node, server_languages)
2947 })
2948 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2949 .map(|(worktree_id, server_node, _)| {
2950 (
2951 *worktree_id,
2952 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2953 )
2954 })
2955 })
2956 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2957 acc.entry(worktree_id)
2958 .or_insert_with(Vec::new)
2959 .push(server_node);
2960 acc
2961 })
2962 .into_values()
2963 .max_by_key(|servers| servers.len())?;
2964
2965 let worktree_id = worktree.read(cx).id();
2966 let apply = move |tree: &mut LanguageServerTree| {
2967 for server_node in &servers {
2968 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2969 }
2970 servers
2971 };
2972
2973 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2974 Some((delegate, apply))
2975 }
2976
2977 pub(crate) fn unregister_old_buffer_from_language_servers(
2978 &mut self,
2979 buffer: &Entity<Buffer>,
2980 old_file: &File,
2981 cx: &mut App,
2982 ) {
2983 let old_path = match old_file.as_local() {
2984 Some(local) => local.abs_path(cx),
2985 None => return,
2986 };
2987
2988 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2989 debug_panic!("{old_path:?} is not parseable as an URI");
2990 return;
2991 };
2992 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2993 }
2994
2995 pub(crate) fn unregister_buffer_from_language_servers(
2996 &mut self,
2997 buffer: &Entity<Buffer>,
2998 file_url: &lsp::Uri,
2999 cx: &mut App,
3000 ) {
3001 buffer.update(cx, |buffer, cx| {
3002 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3003
3004 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3005 if snapshots
3006 .as_mut()
3007 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3008 {
3009 language_server.unregister_buffer(file_url.clone());
3010 }
3011 }
3012 });
3013 }
3014
3015 fn buffer_snapshot_for_lsp_version(
3016 &mut self,
3017 buffer: &Entity<Buffer>,
3018 server_id: LanguageServerId,
3019 version: Option<i32>,
3020 cx: &App,
3021 ) -> Result<TextBufferSnapshot> {
3022 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3023
3024 if let Some(version) = version {
3025 let buffer_id = buffer.read(cx).remote_id();
3026 let snapshots = if let Some(snapshots) = self
3027 .buffer_snapshots
3028 .get_mut(&buffer_id)
3029 .and_then(|m| m.get_mut(&server_id))
3030 {
3031 snapshots
3032 } else if version == 0 {
3033 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3034 // We detect this case and treat it as if the version was `None`.
3035 return Ok(buffer.read(cx).text_snapshot());
3036 } else {
3037 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3038 };
3039
3040 let found_snapshot = snapshots
3041 .binary_search_by_key(&version, |e| e.version)
3042 .map(|ix| snapshots[ix].snapshot.clone())
3043 .map_err(|_| {
3044 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3045 })?;
3046
3047 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3048 Ok(found_snapshot)
3049 } else {
3050 Ok((buffer.read(cx)).text_snapshot())
3051 }
3052 }
3053
3054 async fn get_server_code_actions_from_action_kinds(
3055 lsp_store: &WeakEntity<LspStore>,
3056 language_server_id: LanguageServerId,
3057 code_action_kinds: Vec<lsp::CodeActionKind>,
3058 buffer: &Entity<Buffer>,
3059 cx: &mut AsyncApp,
3060 ) -> Result<Vec<CodeAction>> {
3061 let actions = lsp_store
3062 .update(cx, move |this, cx| {
3063 let request = GetCodeActions {
3064 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3065 kinds: Some(code_action_kinds),
3066 };
3067 let server = LanguageServerToQuery::Other(language_server_id);
3068 this.request_lsp(buffer.clone(), server, request, cx)
3069 })?
3070 .await?;
3071 Ok(actions)
3072 }
3073
3074 pub async fn execute_code_actions_on_server(
3075 lsp_store: &WeakEntity<LspStore>,
3076 language_server: &Arc<LanguageServer>,
3077 actions: Vec<CodeAction>,
3078 push_to_history: bool,
3079 project_transaction: &mut ProjectTransaction,
3080 cx: &mut AsyncApp,
3081 ) -> anyhow::Result<()> {
3082 let request_timeout = cx.update(|app| {
3083 ProjectSettings::get_global(app)
3084 .global_lsp_settings
3085 .get_request_timeout()
3086 });
3087
3088 for mut action in actions {
3089 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3090 .await
3091 .context("resolving a formatting code action")?;
3092
3093 if let Some(edit) = action.lsp_action.edit() {
3094 if edit.changes.is_none() && edit.document_changes.is_none() {
3095 continue;
3096 }
3097
3098 let new = Self::deserialize_workspace_edit(
3099 lsp_store.upgrade().context("project dropped")?,
3100 edit.clone(),
3101 push_to_history,
3102 language_server.clone(),
3103 cx,
3104 )
3105 .await?;
3106 project_transaction.0.extend(new.0);
3107 }
3108
3109 let Some(command) = action.lsp_action.command() else {
3110 continue;
3111 };
3112
3113 let server_capabilities = language_server.capabilities();
3114 let available_commands = server_capabilities
3115 .execute_command_provider
3116 .as_ref()
3117 .map(|options| options.commands.as_slice())
3118 .unwrap_or_default();
3119 if !available_commands.contains(&command.command) {
3120 log::warn!(
3121 "Cannot execute a command {} not listed in the language server capabilities",
3122 command.command
3123 );
3124 continue;
3125 }
3126
3127 lsp_store.update(cx, |lsp_store, _| {
3128 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3129 mode.last_workspace_edits_by_language_server
3130 .remove(&language_server.server_id());
3131 }
3132 })?;
3133
3134 language_server
3135 .request::<lsp::request::ExecuteCommand>(
3136 lsp::ExecuteCommandParams {
3137 command: command.command.clone(),
3138 arguments: command.arguments.clone().unwrap_or_default(),
3139 ..Default::default()
3140 },
3141 request_timeout,
3142 )
3143 .await
3144 .into_response()
3145 .context("execute command")?;
3146
3147 lsp_store.update(cx, |this, _| {
3148 if let LspStoreMode::Local(mode) = &mut this.mode {
3149 project_transaction.0.extend(
3150 mode.last_workspace_edits_by_language_server
3151 .remove(&language_server.server_id())
3152 .unwrap_or_default()
3153 .0,
3154 )
3155 }
3156 })?;
3157 }
3158 Ok(())
3159 }
3160
3161 pub async fn deserialize_text_edits(
3162 this: Entity<LspStore>,
3163 buffer_to_edit: Entity<Buffer>,
3164 edits: Vec<lsp::TextEdit>,
3165 push_to_history: bool,
3166 _: Arc<CachedLspAdapter>,
3167 language_server: Arc<LanguageServer>,
3168 cx: &mut AsyncApp,
3169 ) -> Result<Option<Transaction>> {
3170 let edits = this
3171 .update(cx, |this, cx| {
3172 this.as_local_mut().unwrap().edits_from_lsp(
3173 &buffer_to_edit,
3174 edits,
3175 language_server.server_id(),
3176 None,
3177 cx,
3178 )
3179 })
3180 .await?;
3181
3182 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3183 buffer.finalize_last_transaction();
3184 buffer.start_transaction();
3185 for (range, text) in edits {
3186 buffer.edit([(range, text)], None, cx);
3187 }
3188
3189 if buffer.end_transaction(cx).is_some() {
3190 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3191 if !push_to_history {
3192 buffer.forget_transaction(transaction.id);
3193 }
3194 Some(transaction)
3195 } else {
3196 None
3197 }
3198 });
3199
3200 Ok(transaction)
3201 }
3202
3203 #[allow(clippy::type_complexity)]
3204 pub fn edits_from_lsp(
3205 &mut self,
3206 buffer: &Entity<Buffer>,
3207 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3208 server_id: LanguageServerId,
3209 version: Option<i32>,
3210 cx: &mut Context<LspStore>,
3211 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3212 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3213 cx.background_spawn(async move {
3214 let snapshot = snapshot?;
3215 let mut lsp_edits = lsp_edits
3216 .into_iter()
3217 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3218 .collect::<Vec<_>>();
3219
3220 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3221
3222 let mut lsp_edits = lsp_edits.into_iter().peekable();
3223 let mut edits = Vec::new();
3224 while let Some((range, mut new_text)) = lsp_edits.next() {
3225 // Clip invalid ranges provided by the language server.
3226 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3227 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3228
3229 // Combine any LSP edits that are adjacent.
3230 //
3231 // Also, combine LSP edits that are separated from each other by only
3232 // a newline. This is important because for some code actions,
3233 // Rust-analyzer rewrites the entire buffer via a series of edits that
3234 // are separated by unchanged newline characters.
3235 //
3236 // In order for the diffing logic below to work properly, any edits that
3237 // cancel each other out must be combined into one.
3238 while let Some((next_range, next_text)) = lsp_edits.peek() {
3239 if next_range.start.0 > range.end {
3240 if next_range.start.0.row > range.end.row + 1
3241 || next_range.start.0.column > 0
3242 || snapshot.clip_point_utf16(
3243 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3244 Bias::Left,
3245 ) > range.end
3246 {
3247 break;
3248 }
3249 new_text.push('\n');
3250 }
3251 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3252 new_text.push_str(next_text);
3253 lsp_edits.next();
3254 }
3255
3256 // For multiline edits, perform a diff of the old and new text so that
3257 // we can identify the changes more precisely, preserving the locations
3258 // of any anchors positioned in the unchanged regions.
3259 if range.end.row > range.start.row {
3260 let offset = range.start.to_offset(&snapshot);
3261 let old_text = snapshot.text_for_range(range).collect::<String>();
3262 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3263 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3264 (
3265 snapshot.anchor_after(offset + range.start)
3266 ..snapshot.anchor_before(offset + range.end),
3267 replacement,
3268 )
3269 }));
3270 } else if range.end == range.start {
3271 let anchor = snapshot.anchor_after(range.start);
3272 edits.push((anchor..anchor, new_text.into()));
3273 } else {
3274 let edit_start = snapshot.anchor_after(range.start);
3275 let edit_end = snapshot.anchor_before(range.end);
3276 edits.push((edit_start..edit_end, new_text.into()));
3277 }
3278 }
3279
3280 Ok(edits)
3281 })
3282 }
3283
3284 pub(crate) async fn deserialize_workspace_edit(
3285 this: Entity<LspStore>,
3286 edit: lsp::WorkspaceEdit,
3287 push_to_history: bool,
3288 language_server: Arc<LanguageServer>,
3289 cx: &mut AsyncApp,
3290 ) -> Result<ProjectTransaction> {
3291 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3292
3293 let mut operations = Vec::new();
3294 if let Some(document_changes) = edit.document_changes {
3295 match document_changes {
3296 lsp::DocumentChanges::Edits(edits) => {
3297 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3298 }
3299 lsp::DocumentChanges::Operations(ops) => operations = ops,
3300 }
3301 } else if let Some(changes) = edit.changes {
3302 operations.extend(changes.into_iter().map(|(uri, edits)| {
3303 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3304 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3305 uri,
3306 version: None,
3307 },
3308 edits: edits.into_iter().map(Edit::Plain).collect(),
3309 })
3310 }));
3311 }
3312
3313 let mut project_transaction = ProjectTransaction::default();
3314 for operation in operations {
3315 match operation {
3316 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3317 let abs_path = op
3318 .uri
3319 .to_file_path()
3320 .map_err(|()| anyhow!("can't convert URI to path"))?;
3321
3322 if let Some(parent_path) = abs_path.parent() {
3323 fs.create_dir(parent_path).await?;
3324 }
3325 if abs_path.ends_with("/") {
3326 fs.create_dir(&abs_path).await?;
3327 } else {
3328 fs.create_file(
3329 &abs_path,
3330 op.options
3331 .map(|options| fs::CreateOptions {
3332 overwrite: options.overwrite.unwrap_or(false),
3333 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3334 })
3335 .unwrap_or_default(),
3336 )
3337 .await?;
3338 }
3339 }
3340
3341 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3342 let source_abs_path = op
3343 .old_uri
3344 .to_file_path()
3345 .map_err(|()| anyhow!("can't convert URI to path"))?;
3346 let target_abs_path = op
3347 .new_uri
3348 .to_file_path()
3349 .map_err(|()| anyhow!("can't convert URI to path"))?;
3350
3351 let options = fs::RenameOptions {
3352 overwrite: op
3353 .options
3354 .as_ref()
3355 .and_then(|options| options.overwrite)
3356 .unwrap_or(false),
3357 ignore_if_exists: op
3358 .options
3359 .as_ref()
3360 .and_then(|options| options.ignore_if_exists)
3361 .unwrap_or(false),
3362 create_parents: true,
3363 };
3364
3365 fs.rename(&source_abs_path, &target_abs_path, options)
3366 .await?;
3367 }
3368
3369 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3370 let abs_path = op
3371 .uri
3372 .to_file_path()
3373 .map_err(|()| anyhow!("can't convert URI to path"))?;
3374 let options = op
3375 .options
3376 .map(|options| fs::RemoveOptions {
3377 recursive: options.recursive.unwrap_or(false),
3378 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3379 })
3380 .unwrap_or_default();
3381 if abs_path.ends_with("/") {
3382 fs.remove_dir(&abs_path, options).await?;
3383 } else {
3384 fs.remove_file(&abs_path, options).await?;
3385 }
3386 }
3387
3388 lsp::DocumentChangeOperation::Edit(op) => {
3389 let buffer_to_edit = this
3390 .update(cx, |this, cx| {
3391 this.open_local_buffer_via_lsp(
3392 op.text_document.uri.clone(),
3393 language_server.server_id(),
3394 cx,
3395 )
3396 })
3397 .await?;
3398
3399 let edits = this
3400 .update(cx, |this, cx| {
3401 let path = buffer_to_edit.read(cx).project_path(cx);
3402 let active_entry = this.active_entry;
3403 let is_active_entry = path.is_some_and(|project_path| {
3404 this.worktree_store
3405 .read(cx)
3406 .entry_for_path(&project_path, cx)
3407 .is_some_and(|entry| Some(entry.id) == active_entry)
3408 });
3409 let local = this.as_local_mut().unwrap();
3410
3411 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3412 for edit in op.edits {
3413 match edit {
3414 Edit::Plain(edit) => {
3415 if !edits.contains(&edit) {
3416 edits.push(edit)
3417 }
3418 }
3419 Edit::Annotated(edit) => {
3420 if !edits.contains(&edit.text_edit) {
3421 edits.push(edit.text_edit)
3422 }
3423 }
3424 Edit::Snippet(edit) => {
3425 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3426 else {
3427 continue;
3428 };
3429
3430 if is_active_entry {
3431 snippet_edits.push((edit.range, snippet));
3432 } else {
3433 // Since this buffer is not focused, apply a normal edit.
3434 let new_edit = TextEdit {
3435 range: edit.range,
3436 new_text: snippet.text,
3437 };
3438 if !edits.contains(&new_edit) {
3439 edits.push(new_edit);
3440 }
3441 }
3442 }
3443 }
3444 }
3445 if !snippet_edits.is_empty() {
3446 let buffer_id = buffer_to_edit.read(cx).remote_id();
3447 let version = if let Some(buffer_version) = op.text_document.version
3448 {
3449 local
3450 .buffer_snapshot_for_lsp_version(
3451 &buffer_to_edit,
3452 language_server.server_id(),
3453 Some(buffer_version),
3454 cx,
3455 )
3456 .ok()
3457 .map(|snapshot| snapshot.version)
3458 } else {
3459 Some(buffer_to_edit.read(cx).saved_version().clone())
3460 };
3461
3462 let most_recent_edit =
3463 version.and_then(|version| version.most_recent());
3464 // Check if the edit that triggered that edit has been made by this participant.
3465
3466 if let Some(most_recent_edit) = most_recent_edit {
3467 cx.emit(LspStoreEvent::SnippetEdit {
3468 buffer_id,
3469 edits: snippet_edits,
3470 most_recent_edit,
3471 });
3472 }
3473 }
3474
3475 local.edits_from_lsp(
3476 &buffer_to_edit,
3477 edits,
3478 language_server.server_id(),
3479 op.text_document.version,
3480 cx,
3481 )
3482 })
3483 .await?;
3484
3485 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3486 buffer.finalize_last_transaction();
3487 buffer.start_transaction();
3488 for (range, text) in edits {
3489 buffer.edit([(range, text)], None, cx);
3490 }
3491
3492 buffer.end_transaction(cx).and_then(|transaction_id| {
3493 if push_to_history {
3494 buffer.finalize_last_transaction();
3495 buffer.get_transaction(transaction_id).cloned()
3496 } else {
3497 buffer.forget_transaction(transaction_id)
3498 }
3499 })
3500 });
3501 if let Some(transaction) = transaction {
3502 project_transaction.0.insert(buffer_to_edit, transaction);
3503 }
3504 }
3505 }
3506 }
3507
3508 Ok(project_transaction)
3509 }
3510
3511 async fn on_lsp_workspace_edit(
3512 this: WeakEntity<LspStore>,
3513 params: lsp::ApplyWorkspaceEditParams,
3514 server_id: LanguageServerId,
3515 cx: &mut AsyncApp,
3516 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3517 let this = this.upgrade().context("project project closed")?;
3518 let language_server = this
3519 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3520 .context("language server not found")?;
3521 let transaction = Self::deserialize_workspace_edit(
3522 this.clone(),
3523 params.edit,
3524 true,
3525 language_server.clone(),
3526 cx,
3527 )
3528 .await
3529 .log_err();
3530 this.update(cx, |this, cx| {
3531 if let Some(transaction) = transaction {
3532 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3533
3534 this.as_local_mut()
3535 .unwrap()
3536 .last_workspace_edits_by_language_server
3537 .insert(server_id, transaction);
3538 }
3539 });
3540 Ok(lsp::ApplyWorkspaceEditResponse {
3541 applied: true,
3542 failed_change: None,
3543 failure_reason: None,
3544 })
3545 }
3546
3547 fn remove_worktree(
3548 &mut self,
3549 id_to_remove: WorktreeId,
3550 cx: &mut Context<LspStore>,
3551 ) -> Vec<LanguageServerId> {
3552 self.restricted_worktrees_tasks.remove(&id_to_remove);
3553 self.diagnostics.remove(&id_to_remove);
3554 self.prettier_store.update(cx, |prettier_store, cx| {
3555 prettier_store.remove_worktree(id_to_remove, cx);
3556 });
3557
3558 let mut servers_to_remove = BTreeSet::default();
3559 let mut servers_to_preserve = HashSet::default();
3560 for (seed, state) in &self.language_server_ids {
3561 if seed.worktree_id == id_to_remove {
3562 servers_to_remove.insert(state.id);
3563 } else {
3564 servers_to_preserve.insert(state.id);
3565 }
3566 }
3567 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3568 self.language_server_ids
3569 .retain(|_, state| !servers_to_remove.contains(&state.id));
3570 for server_id_to_remove in &servers_to_remove {
3571 self.language_server_watched_paths
3572 .remove(server_id_to_remove);
3573 self.language_server_paths_watched_for_rename
3574 .remove(server_id_to_remove);
3575 self.last_workspace_edits_by_language_server
3576 .remove(server_id_to_remove);
3577 self.language_servers.remove(server_id_to_remove);
3578 self.buffer_pull_diagnostics_result_ids
3579 .remove(server_id_to_remove);
3580 self.workspace_pull_diagnostics_result_ids
3581 .remove(server_id_to_remove);
3582 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3583 buffer_servers.remove(server_id_to_remove);
3584 }
3585 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3586 }
3587 servers_to_remove.into_iter().collect()
3588 }
3589
3590 fn rebuild_watched_paths_inner<'a>(
3591 &'a self,
3592 language_server_id: LanguageServerId,
3593 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3594 cx: &mut Context<LspStore>,
3595 ) -> LanguageServerWatchedPathsBuilder {
3596 let worktrees = self
3597 .worktree_store
3598 .read(cx)
3599 .worktrees()
3600 .filter_map(|worktree| {
3601 self.language_servers_for_worktree(worktree.read(cx).id())
3602 .find(|server| server.server_id() == language_server_id)
3603 .map(|_| worktree)
3604 })
3605 .collect::<Vec<_>>();
3606
3607 let mut worktree_globs = HashMap::default();
3608 let mut abs_globs = HashMap::default();
3609 log::trace!(
3610 "Processing new watcher paths for language server with id {}",
3611 language_server_id
3612 );
3613
3614 for watcher in watchers {
3615 if let Some((worktree, literal_prefix, pattern)) =
3616 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3617 {
3618 worktree.update(cx, |worktree, _| {
3619 if let Some((tree, glob)) =
3620 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3621 {
3622 tree.add_path_prefix_to_scan(literal_prefix);
3623 worktree_globs
3624 .entry(tree.id())
3625 .or_insert_with(GlobSetBuilder::new)
3626 .add(glob);
3627 }
3628 });
3629 } else {
3630 let (path, pattern) = match &watcher.glob_pattern {
3631 lsp::GlobPattern::String(s) => {
3632 let watcher_path = SanitizedPath::new(s);
3633 let path = glob_literal_prefix(watcher_path.as_path());
3634 let pattern = watcher_path
3635 .as_path()
3636 .strip_prefix(&path)
3637 .map(|p| p.to_string_lossy().into_owned())
3638 .unwrap_or_else(|e| {
3639 debug_panic!(
3640 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3641 s,
3642 path.display(),
3643 e
3644 );
3645 watcher_path.as_path().to_string_lossy().into_owned()
3646 });
3647 (path, pattern)
3648 }
3649 lsp::GlobPattern::Relative(rp) => {
3650 let Ok(mut base_uri) = match &rp.base_uri {
3651 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3652 lsp::OneOf::Right(base_uri) => base_uri,
3653 }
3654 .to_file_path() else {
3655 continue;
3656 };
3657
3658 let path = glob_literal_prefix(Path::new(&rp.pattern));
3659 let pattern = Path::new(&rp.pattern)
3660 .strip_prefix(&path)
3661 .map(|p| p.to_string_lossy().into_owned())
3662 .unwrap_or_else(|e| {
3663 debug_panic!(
3664 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3665 rp.pattern,
3666 path.display(),
3667 e
3668 );
3669 rp.pattern.clone()
3670 });
3671 base_uri.push(path);
3672 (base_uri, pattern)
3673 }
3674 };
3675
3676 if let Some(glob) = Glob::new(&pattern).log_err() {
3677 if !path
3678 .components()
3679 .any(|c| matches!(c, path::Component::Normal(_)))
3680 {
3681 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3682 // rather than adding a new watcher for `/`.
3683 for worktree in &worktrees {
3684 worktree_globs
3685 .entry(worktree.read(cx).id())
3686 .or_insert_with(GlobSetBuilder::new)
3687 .add(glob.clone());
3688 }
3689 } else {
3690 abs_globs
3691 .entry(path.into())
3692 .or_insert_with(GlobSetBuilder::new)
3693 .add(glob);
3694 }
3695 }
3696 }
3697 }
3698
3699 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3700 for (worktree_id, builder) in worktree_globs {
3701 if let Ok(globset) = builder.build() {
3702 watch_builder.watch_worktree(worktree_id, globset);
3703 }
3704 }
3705 for (abs_path, builder) in abs_globs {
3706 if let Ok(globset) = builder.build() {
3707 watch_builder.watch_abs_path(abs_path, globset);
3708 }
3709 }
3710 watch_builder
3711 }
3712
3713 fn worktree_and_path_for_file_watcher(
3714 worktrees: &[Entity<Worktree>],
3715 watcher: &FileSystemWatcher,
3716 cx: &App,
3717 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3718 worktrees.iter().find_map(|worktree| {
3719 let tree = worktree.read(cx);
3720 let worktree_root_path = tree.abs_path();
3721 let path_style = tree.path_style();
3722 match &watcher.glob_pattern {
3723 lsp::GlobPattern::String(s) => {
3724 let watcher_path = SanitizedPath::new(s);
3725 let relative = watcher_path
3726 .as_path()
3727 .strip_prefix(&worktree_root_path)
3728 .ok()?;
3729 let literal_prefix = glob_literal_prefix(relative);
3730 Some((
3731 worktree.clone(),
3732 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3733 relative.to_string_lossy().into_owned(),
3734 ))
3735 }
3736 lsp::GlobPattern::Relative(rp) => {
3737 let base_uri = match &rp.base_uri {
3738 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3739 lsp::OneOf::Right(base_uri) => base_uri,
3740 }
3741 .to_file_path()
3742 .ok()?;
3743 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3744 let mut literal_prefix = relative.to_owned();
3745 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3746 Some((
3747 worktree.clone(),
3748 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3749 rp.pattern.clone(),
3750 ))
3751 }
3752 }
3753 })
3754 }
3755
3756 fn rebuild_watched_paths(
3757 &mut self,
3758 language_server_id: LanguageServerId,
3759 cx: &mut Context<LspStore>,
3760 ) {
3761 let Some(registrations) = self
3762 .language_server_dynamic_registrations
3763 .get(&language_server_id)
3764 else {
3765 return;
3766 };
3767
3768 let watch_builder = self.rebuild_watched_paths_inner(
3769 language_server_id,
3770 registrations.did_change_watched_files.values().flatten(),
3771 cx,
3772 );
3773 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3774 self.language_server_watched_paths
3775 .insert(language_server_id, watcher);
3776
3777 cx.notify();
3778 }
3779
3780 fn on_lsp_did_change_watched_files(
3781 &mut self,
3782 language_server_id: LanguageServerId,
3783 registration_id: &str,
3784 params: DidChangeWatchedFilesRegistrationOptions,
3785 cx: &mut Context<LspStore>,
3786 ) {
3787 let registrations = self
3788 .language_server_dynamic_registrations
3789 .entry(language_server_id)
3790 .or_default();
3791
3792 registrations
3793 .did_change_watched_files
3794 .insert(registration_id.to_string(), params.watchers);
3795
3796 self.rebuild_watched_paths(language_server_id, cx);
3797 }
3798
3799 fn on_lsp_unregister_did_change_watched_files(
3800 &mut self,
3801 language_server_id: LanguageServerId,
3802 registration_id: &str,
3803 cx: &mut Context<LspStore>,
3804 ) {
3805 let registrations = self
3806 .language_server_dynamic_registrations
3807 .entry(language_server_id)
3808 .or_default();
3809
3810 if registrations
3811 .did_change_watched_files
3812 .remove(registration_id)
3813 .is_some()
3814 {
3815 log::info!(
3816 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3817 language_server_id,
3818 registration_id
3819 );
3820 } else {
3821 log::warn!(
3822 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3823 language_server_id,
3824 registration_id
3825 );
3826 }
3827
3828 self.rebuild_watched_paths(language_server_id, cx);
3829 }
3830
3831 async fn initialization_options_for_adapter(
3832 adapter: Arc<dyn LspAdapter>,
3833 delegate: &Arc<dyn LspAdapterDelegate>,
3834 cx: &mut AsyncApp,
3835 ) -> Result<Option<serde_json::Value>> {
3836 let Some(mut initialization_config) =
3837 adapter.clone().initialization_options(delegate, cx).await?
3838 else {
3839 return Ok(None);
3840 };
3841
3842 for other_adapter in delegate.registered_lsp_adapters() {
3843 if other_adapter.name() == adapter.name() {
3844 continue;
3845 }
3846 if let Ok(Some(target_config)) = other_adapter
3847 .clone()
3848 .additional_initialization_options(adapter.name(), delegate)
3849 .await
3850 {
3851 merge_json_value_into(target_config.clone(), &mut initialization_config);
3852 }
3853 }
3854
3855 Ok(Some(initialization_config))
3856 }
3857
3858 async fn workspace_configuration_for_adapter(
3859 adapter: Arc<dyn LspAdapter>,
3860 delegate: &Arc<dyn LspAdapterDelegate>,
3861 toolchain: Option<Toolchain>,
3862 requested_uri: Option<Uri>,
3863 cx: &mut AsyncApp,
3864 ) -> Result<serde_json::Value> {
3865 let mut workspace_config = adapter
3866 .clone()
3867 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3868 .await?;
3869
3870 for other_adapter in delegate.registered_lsp_adapters() {
3871 if other_adapter.name() == adapter.name() {
3872 continue;
3873 }
3874 if let Ok(Some(target_config)) = other_adapter
3875 .clone()
3876 .additional_workspace_configuration(adapter.name(), delegate, cx)
3877 .await
3878 {
3879 merge_json_value_into(target_config.clone(), &mut workspace_config);
3880 }
3881 }
3882
3883 Ok(workspace_config)
3884 }
3885
3886 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3887 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3888 Some(server.clone())
3889 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3890 Some(Arc::clone(server))
3891 } else {
3892 None
3893 }
3894 }
3895}
3896
3897fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3898 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3899 cx.emit(LspStoreEvent::LanguageServerUpdate {
3900 language_server_id: server.server_id(),
3901 name: Some(server.name()),
3902 message: proto::update_language_server::Variant::MetadataUpdated(
3903 proto::ServerMetadataUpdated {
3904 capabilities: Some(capabilities),
3905 binary: Some(proto::LanguageServerBinaryInfo {
3906 path: server.binary().path.to_string_lossy().into_owned(),
3907 arguments: server
3908 .binary()
3909 .arguments
3910 .iter()
3911 .map(|arg| arg.to_string_lossy().into_owned())
3912 .collect(),
3913 }),
3914 configuration: serde_json::to_string(server.configuration()).ok(),
3915 workspace_folders: server
3916 .workspace_folders()
3917 .iter()
3918 .map(|uri| uri.to_string())
3919 .collect(),
3920 },
3921 ),
3922 });
3923 }
3924}
3925
3926#[derive(Debug)]
3927pub struct FormattableBuffer {
3928 handle: Entity<Buffer>,
3929 abs_path: Option<PathBuf>,
3930 env: Option<HashMap<String, String>>,
3931 ranges: Option<Vec<Range<Anchor>>>,
3932}
3933
3934pub struct RemoteLspStore {
3935 upstream_client: Option<AnyProtoClient>,
3936 upstream_project_id: u64,
3937}
3938
3939pub(crate) enum LspStoreMode {
3940 Local(LocalLspStore), // ssh host and collab host
3941 Remote(RemoteLspStore), // collab guest
3942}
3943
3944impl LspStoreMode {
3945 fn is_local(&self) -> bool {
3946 matches!(self, LspStoreMode::Local(_))
3947 }
3948}
3949
3950pub struct LspStore {
3951 mode: LspStoreMode,
3952 last_formatting_failure: Option<String>,
3953 downstream_client: Option<(AnyProtoClient, u64)>,
3954 nonce: u128,
3955 buffer_store: Entity<BufferStore>,
3956 worktree_store: Entity<WorktreeStore>,
3957 pub languages: Arc<LanguageRegistry>,
3958 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3959 active_entry: Option<ProjectEntryId>,
3960 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3961 _maintain_buffer_languages: Task<()>,
3962 diagnostic_summaries:
3963 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3964 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3965 semantic_token_config: SemanticTokenConfig,
3966 lsp_data: HashMap<BufferId, BufferLspData>,
3967 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3968 next_hint_id: Arc<AtomicUsize>,
3969}
3970
3971#[derive(Debug)]
3972pub struct BufferLspData {
3973 buffer_version: Global,
3974 document_colors: Option<DocumentColorData>,
3975 code_lens: Option<CodeLensData>,
3976 semantic_tokens: Option<SemanticTokensData>,
3977 folding_ranges: Option<FoldingRangeData>,
3978 document_symbols: Option<DocumentSymbolsData>,
3979 inlay_hints: BufferInlayHints,
3980 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3981 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3982}
3983
3984#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3985struct LspKey {
3986 request_type: TypeId,
3987 server_queried: Option<LanguageServerId>,
3988}
3989
3990impl BufferLspData {
3991 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3992 Self {
3993 buffer_version: buffer.read(cx).version(),
3994 document_colors: None,
3995 code_lens: None,
3996 semantic_tokens: None,
3997 folding_ranges: None,
3998 document_symbols: None,
3999 inlay_hints: BufferInlayHints::new(buffer, cx),
4000 lsp_requests: HashMap::default(),
4001 chunk_lsp_requests: HashMap::default(),
4002 }
4003 }
4004
4005 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4006 if let Some(document_colors) = &mut self.document_colors {
4007 document_colors.remove_server_data(for_server);
4008 }
4009
4010 if let Some(code_lens) = &mut self.code_lens {
4011 code_lens.remove_server_data(for_server);
4012 }
4013
4014 self.inlay_hints.remove_server_data(for_server);
4015
4016 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4017 semantic_tokens.remove_server_data(for_server);
4018 }
4019
4020 if let Some(folding_ranges) = &mut self.folding_ranges {
4021 folding_ranges.ranges.remove(&for_server);
4022 }
4023
4024 if let Some(document_symbols) = &mut self.document_symbols {
4025 document_symbols.remove_server_data(for_server);
4026 }
4027 }
4028
4029 #[cfg(any(test, feature = "test-support"))]
4030 pub fn inlay_hints(&self) -> &BufferInlayHints {
4031 &self.inlay_hints
4032 }
4033}
4034
4035#[derive(Debug)]
4036pub enum LspStoreEvent {
4037 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4038 LanguageServerRemoved(LanguageServerId),
4039 LanguageServerUpdate {
4040 language_server_id: LanguageServerId,
4041 name: Option<LanguageServerName>,
4042 message: proto::update_language_server::Variant,
4043 },
4044 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4045 LanguageServerPrompt(LanguageServerPromptRequest),
4046 LanguageDetected {
4047 buffer: Entity<Buffer>,
4048 new_language: Option<Arc<Language>>,
4049 },
4050 Notification(String),
4051 RefreshInlayHints {
4052 server_id: LanguageServerId,
4053 request_id: Option<usize>,
4054 },
4055 RefreshSemanticTokens {
4056 server_id: LanguageServerId,
4057 request_id: Option<usize>,
4058 },
4059 RefreshCodeLens,
4060 DiagnosticsUpdated {
4061 server_id: LanguageServerId,
4062 paths: Vec<ProjectPath>,
4063 },
4064 DiskBasedDiagnosticsStarted {
4065 language_server_id: LanguageServerId,
4066 },
4067 DiskBasedDiagnosticsFinished {
4068 language_server_id: LanguageServerId,
4069 },
4070 SnippetEdit {
4071 buffer_id: BufferId,
4072 edits: Vec<(lsp::Range, Snippet)>,
4073 most_recent_edit: clock::Lamport,
4074 },
4075 WorkspaceEditApplied(ProjectTransaction),
4076}
4077
4078#[derive(Clone, Debug, Serialize)]
4079pub struct LanguageServerStatus {
4080 pub name: LanguageServerName,
4081 pub server_version: Option<SharedString>,
4082 pub server_readable_version: Option<SharedString>,
4083 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4084 pub has_pending_diagnostic_updates: bool,
4085 pub progress_tokens: HashSet<ProgressToken>,
4086 pub worktree: Option<WorktreeId>,
4087 pub binary: Option<LanguageServerBinary>,
4088 pub configuration: Option<Value>,
4089 pub workspace_folders: BTreeSet<Uri>,
4090 pub process_id: Option<u32>,
4091}
4092
4093#[derive(Clone, Debug)]
4094struct CoreSymbol {
4095 pub language_server_name: LanguageServerName,
4096 pub source_worktree_id: WorktreeId,
4097 pub source_language_server_id: LanguageServerId,
4098 pub path: SymbolLocation,
4099 pub name: String,
4100 pub kind: lsp::SymbolKind,
4101 pub range: Range<Unclipped<PointUtf16>>,
4102 pub container_name: Option<String>,
4103}
4104
4105#[derive(Clone, Debug, PartialEq, Eq)]
4106pub enum SymbolLocation {
4107 InProject(ProjectPath),
4108 OutsideProject {
4109 abs_path: Arc<Path>,
4110 signature: [u8; 32],
4111 },
4112}
4113
4114impl SymbolLocation {
4115 fn file_name(&self) -> Option<&str> {
4116 match self {
4117 Self::InProject(path) => path.path.file_name(),
4118 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4119 }
4120 }
4121}
4122
4123impl LspStore {
4124 pub fn init(client: &AnyProtoClient) {
4125 client.add_entity_request_handler(Self::handle_lsp_query);
4126 client.add_entity_message_handler(Self::handle_lsp_query_response);
4127 client.add_entity_request_handler(Self::handle_restart_language_servers);
4128 client.add_entity_request_handler(Self::handle_stop_language_servers);
4129 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4130 client.add_entity_message_handler(Self::handle_start_language_server);
4131 client.add_entity_message_handler(Self::handle_update_language_server);
4132 client.add_entity_message_handler(Self::handle_language_server_log);
4133 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4134 client.add_entity_request_handler(Self::handle_format_buffers);
4135 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4136 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4137 client.add_entity_request_handler(Self::handle_apply_code_action);
4138 client.add_entity_request_handler(Self::handle_get_project_symbols);
4139 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4140 client.add_entity_request_handler(Self::handle_get_color_presentation);
4141 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4142 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4143 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4144 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4145 client.add_entity_request_handler(Self::handle_on_type_formatting);
4146 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4147 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4148 client.add_entity_request_handler(Self::handle_rename_project_entry);
4149 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4150 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4151 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4152 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4153 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4154 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4155 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4156
4157 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4158 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4159 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4160 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4161 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4162 client.add_entity_request_handler(
4163 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4164 );
4165 client.add_entity_request_handler(
4166 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4167 );
4168 client.add_entity_request_handler(
4169 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4170 );
4171 }
4172
4173 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4174 match &self.mode {
4175 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4176 _ => None,
4177 }
4178 }
4179
4180 pub fn as_local(&self) -> Option<&LocalLspStore> {
4181 match &self.mode {
4182 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4183 _ => None,
4184 }
4185 }
4186
4187 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4188 match &mut self.mode {
4189 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4190 _ => None,
4191 }
4192 }
4193
4194 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4195 match &self.mode {
4196 LspStoreMode::Remote(RemoteLspStore {
4197 upstream_client: Some(upstream_client),
4198 upstream_project_id,
4199 ..
4200 }) => Some((upstream_client.clone(), *upstream_project_id)),
4201
4202 LspStoreMode::Remote(RemoteLspStore {
4203 upstream_client: None,
4204 ..
4205 }) => None,
4206 LspStoreMode::Local(_) => None,
4207 }
4208 }
4209
4210 pub fn new_local(
4211 buffer_store: Entity<BufferStore>,
4212 worktree_store: Entity<WorktreeStore>,
4213 prettier_store: Entity<PrettierStore>,
4214 toolchain_store: Entity<LocalToolchainStore>,
4215 environment: Entity<ProjectEnvironment>,
4216 manifest_tree: Entity<ManifestTree>,
4217 languages: Arc<LanguageRegistry>,
4218 http_client: Arc<dyn HttpClient>,
4219 fs: Arc<dyn Fs>,
4220 cx: &mut Context<Self>,
4221 ) -> Self {
4222 let yarn = YarnPathStore::new(fs.clone(), cx);
4223 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4224 .detach();
4225 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4226 .detach();
4227 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4228 .detach();
4229 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4230 .detach();
4231 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4232 .detach();
4233 subscribe_to_binary_statuses(&languages, cx).detach();
4234
4235 let _maintain_workspace_config = {
4236 let (sender, receiver) = watch::channel();
4237 (Self::maintain_workspace_config(receiver, cx), sender)
4238 };
4239
4240 Self {
4241 mode: LspStoreMode::Local(LocalLspStore {
4242 weak: cx.weak_entity(),
4243 worktree_store: worktree_store.clone(),
4244
4245 supplementary_language_servers: Default::default(),
4246 languages: languages.clone(),
4247 language_server_ids: Default::default(),
4248 language_servers: Default::default(),
4249 last_workspace_edits_by_language_server: Default::default(),
4250 language_server_watched_paths: Default::default(),
4251 language_server_paths_watched_for_rename: Default::default(),
4252 language_server_dynamic_registrations: Default::default(),
4253 buffers_being_formatted: Default::default(),
4254 buffers_to_refresh_hash_set: HashSet::default(),
4255 buffers_to_refresh_queue: VecDeque::new(),
4256 _background_diagnostics_worker: Task::ready(()).shared(),
4257 buffer_snapshots: Default::default(),
4258 prettier_store,
4259 environment,
4260 http_client,
4261 fs,
4262 yarn,
4263 next_diagnostic_group_id: Default::default(),
4264 diagnostics: Default::default(),
4265 _subscription: cx.on_app_quit(|this, _| {
4266 this.as_local_mut()
4267 .unwrap()
4268 .shutdown_language_servers_on_quit()
4269 }),
4270 lsp_tree: LanguageServerTree::new(
4271 manifest_tree,
4272 languages.clone(),
4273 toolchain_store.clone(),
4274 ),
4275 toolchain_store,
4276 registered_buffers: HashMap::default(),
4277 buffers_opened_in_servers: HashMap::default(),
4278 buffer_pull_diagnostics_result_ids: HashMap::default(),
4279 workspace_pull_diagnostics_result_ids: HashMap::default(),
4280 restricted_worktrees_tasks: HashMap::default(),
4281 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4282 .manifest_file_names(),
4283 }),
4284 last_formatting_failure: None,
4285 downstream_client: None,
4286 buffer_store,
4287 worktree_store,
4288 languages: languages.clone(),
4289 language_server_statuses: Default::default(),
4290 nonce: StdRng::from_os_rng().random(),
4291 diagnostic_summaries: HashMap::default(),
4292 lsp_server_capabilities: HashMap::default(),
4293 semantic_token_config: SemanticTokenConfig::new(cx),
4294 lsp_data: HashMap::default(),
4295 buffer_reload_tasks: HashMap::default(),
4296 next_hint_id: Arc::default(),
4297 active_entry: None,
4298 _maintain_workspace_config,
4299 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4300 }
4301 }
4302
4303 fn send_lsp_proto_request<R: LspCommand>(
4304 &self,
4305 buffer: Entity<Buffer>,
4306 client: AnyProtoClient,
4307 upstream_project_id: u64,
4308 request: R,
4309 cx: &mut Context<LspStore>,
4310 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4311 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4312 return Task::ready(Ok(R::Response::default()));
4313 }
4314 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4315 cx.spawn(async move |this, cx| {
4316 let response = client.request(message).await?;
4317 let this = this.upgrade().context("project dropped")?;
4318 request
4319 .response_from_proto(response, this, buffer, cx.clone())
4320 .await
4321 })
4322 }
4323
4324 pub(super) fn new_remote(
4325 buffer_store: Entity<BufferStore>,
4326 worktree_store: Entity<WorktreeStore>,
4327 languages: Arc<LanguageRegistry>,
4328 upstream_client: AnyProtoClient,
4329 project_id: u64,
4330 cx: &mut Context<Self>,
4331 ) -> Self {
4332 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4333 .detach();
4334 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4335 .detach();
4336 subscribe_to_binary_statuses(&languages, cx).detach();
4337 let _maintain_workspace_config = {
4338 let (sender, receiver) = watch::channel();
4339 (Self::maintain_workspace_config(receiver, cx), sender)
4340 };
4341 Self {
4342 mode: LspStoreMode::Remote(RemoteLspStore {
4343 upstream_client: Some(upstream_client),
4344 upstream_project_id: project_id,
4345 }),
4346 downstream_client: None,
4347 last_formatting_failure: None,
4348 buffer_store,
4349 worktree_store,
4350 languages: languages.clone(),
4351 language_server_statuses: Default::default(),
4352 nonce: StdRng::from_os_rng().random(),
4353 diagnostic_summaries: HashMap::default(),
4354 lsp_server_capabilities: HashMap::default(),
4355 semantic_token_config: SemanticTokenConfig::new(cx),
4356 next_hint_id: Arc::default(),
4357 lsp_data: HashMap::default(),
4358 buffer_reload_tasks: HashMap::default(),
4359 active_entry: None,
4360
4361 _maintain_workspace_config,
4362 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4363 }
4364 }
4365
4366 fn on_buffer_store_event(
4367 &mut self,
4368 _: Entity<BufferStore>,
4369 event: &BufferStoreEvent,
4370 cx: &mut Context<Self>,
4371 ) {
4372 match event {
4373 BufferStoreEvent::BufferAdded(buffer) => {
4374 self.on_buffer_added(buffer, cx).log_err();
4375 }
4376 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4377 let buffer_id = buffer.read(cx).remote_id();
4378 if let Some(local) = self.as_local_mut()
4379 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4380 {
4381 local.reset_buffer(buffer, old_file, cx);
4382
4383 if local.registered_buffers.contains_key(&buffer_id) {
4384 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4385 }
4386 }
4387
4388 self.detect_language_for_buffer(buffer, cx);
4389 if let Some(local) = self.as_local_mut() {
4390 local.initialize_buffer(buffer, cx);
4391 if local.registered_buffers.contains_key(&buffer_id) {
4392 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4393 }
4394 }
4395 }
4396 _ => {}
4397 }
4398 }
4399
4400 fn on_worktree_store_event(
4401 &mut self,
4402 _: Entity<WorktreeStore>,
4403 event: &WorktreeStoreEvent,
4404 cx: &mut Context<Self>,
4405 ) {
4406 match event {
4407 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4408 if !worktree.read(cx).is_local() {
4409 return;
4410 }
4411 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4412 worktree::Event::UpdatedEntries(changes) => {
4413 this.update_local_worktree_language_servers(&worktree, changes, cx);
4414 }
4415 worktree::Event::UpdatedGitRepositories(_)
4416 | worktree::Event::DeletedEntry(_)
4417 | worktree::Event::Deleted => {}
4418 })
4419 .detach()
4420 }
4421 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4422 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4423 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4424 }
4425 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4426 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4427 }
4428 WorktreeStoreEvent::WorktreeReleased(..)
4429 | WorktreeStoreEvent::WorktreeOrderChanged
4430 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4431 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4432 }
4433 }
4434
4435 fn on_prettier_store_event(
4436 &mut self,
4437 _: Entity<PrettierStore>,
4438 event: &PrettierStoreEvent,
4439 cx: &mut Context<Self>,
4440 ) {
4441 match event {
4442 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4443 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4444 }
4445 PrettierStoreEvent::LanguageServerAdded {
4446 new_server_id,
4447 name,
4448 prettier_server,
4449 } => {
4450 self.register_supplementary_language_server(
4451 *new_server_id,
4452 name.clone(),
4453 prettier_server.clone(),
4454 cx,
4455 );
4456 }
4457 }
4458 }
4459
4460 fn on_toolchain_store_event(
4461 &mut self,
4462 _: Entity<LocalToolchainStore>,
4463 event: &ToolchainStoreEvent,
4464 _: &mut Context<Self>,
4465 ) {
4466 if let ToolchainStoreEvent::ToolchainActivated = event {
4467 self.request_workspace_config_refresh()
4468 }
4469 }
4470
4471 fn request_workspace_config_refresh(&mut self) {
4472 *self._maintain_workspace_config.1.borrow_mut() = ();
4473 }
4474
4475 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4476 self.as_local().map(|local| local.prettier_store.clone())
4477 }
4478
4479 fn on_buffer_event(
4480 &mut self,
4481 buffer: Entity<Buffer>,
4482 event: &language::BufferEvent,
4483 cx: &mut Context<Self>,
4484 ) {
4485 match event {
4486 language::BufferEvent::Edited { .. } => {
4487 self.on_buffer_edited(buffer, cx);
4488 }
4489
4490 language::BufferEvent::Saved => {
4491 self.on_buffer_saved(buffer, cx);
4492 }
4493
4494 language::BufferEvent::Reloaded => {
4495 self.on_buffer_reloaded(buffer, cx);
4496 }
4497
4498 _ => {}
4499 }
4500 }
4501
4502 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4503 buffer
4504 .read(cx)
4505 .set_language_registry(self.languages.clone());
4506
4507 cx.subscribe(buffer, |this, buffer, event, cx| {
4508 this.on_buffer_event(buffer, event, cx);
4509 })
4510 .detach();
4511
4512 self.parse_modeline(buffer, cx);
4513 self.detect_language_for_buffer(buffer, cx);
4514 if let Some(local) = self.as_local_mut() {
4515 local.initialize_buffer(buffer, cx);
4516 }
4517
4518 Ok(())
4519 }
4520
4521 pub fn refresh_background_diagnostics_for_buffers(
4522 &mut self,
4523 buffers: HashSet<BufferId>,
4524 cx: &mut Context<Self>,
4525 ) -> Shared<Task<()>> {
4526 let Some(local) = self.as_local_mut() else {
4527 return Task::ready(()).shared();
4528 };
4529 for buffer in buffers {
4530 if local.buffers_to_refresh_hash_set.insert(buffer) {
4531 local.buffers_to_refresh_queue.push_back(buffer);
4532 if local.buffers_to_refresh_queue.len() == 1 {
4533 local._background_diagnostics_worker =
4534 Self::background_diagnostics_worker(cx).shared();
4535 }
4536 }
4537 }
4538
4539 local._background_diagnostics_worker.clone()
4540 }
4541
4542 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4543 let buffer_store = self.buffer_store.clone();
4544 let local = self.as_local_mut()?;
4545 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4546 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4547 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4548 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4549 }
4550 }
4551 None
4552 }
4553
4554 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4555 cx.spawn(async move |this, cx| {
4556 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4557 task.await.log_err();
4558 }
4559 })
4560 }
4561
4562 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4563 if self.parse_modeline(&buffer, cx) {
4564 self.detect_language_for_buffer(&buffer, cx);
4565 }
4566
4567 let buffer_id = buffer.read(cx).remote_id();
4568 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4569 self.buffer_reload_tasks.insert(buffer_id, task);
4570 }
4571
4572 pub(crate) fn register_buffer_with_language_servers(
4573 &mut self,
4574 buffer: &Entity<Buffer>,
4575 only_register_servers: HashSet<LanguageServerSelector>,
4576 ignore_refcounts: bool,
4577 cx: &mut Context<Self>,
4578 ) -> OpenLspBufferHandle {
4579 let buffer_id = buffer.read(cx).remote_id();
4580 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4581 if let Some(local) = self.as_local_mut() {
4582 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4583 if !ignore_refcounts {
4584 *refcount += 1;
4585 }
4586
4587 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4588 // 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
4589 // 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
4590 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4591 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4592 return handle;
4593 };
4594 if !file.is_local() {
4595 return handle;
4596 }
4597
4598 if ignore_refcounts || *refcount == 1 {
4599 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4600 }
4601 if !ignore_refcounts {
4602 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4603 let refcount = {
4604 let local = lsp_store.as_local_mut().unwrap();
4605 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4606 debug_panic!("bad refcounting");
4607 return;
4608 };
4609
4610 *refcount -= 1;
4611 *refcount
4612 };
4613 if refcount == 0 {
4614 lsp_store.lsp_data.remove(&buffer_id);
4615 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4616 let local = lsp_store.as_local_mut().unwrap();
4617 local.registered_buffers.remove(&buffer_id);
4618
4619 local.buffers_opened_in_servers.remove(&buffer_id);
4620 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4621 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4622
4623 let buffer_abs_path = file.abs_path(cx);
4624 for (_, buffer_pull_diagnostics_result_ids) in
4625 &mut local.buffer_pull_diagnostics_result_ids
4626 {
4627 buffer_pull_diagnostics_result_ids.retain(
4628 |_, buffer_result_ids| {
4629 buffer_result_ids.remove(&buffer_abs_path);
4630 !buffer_result_ids.is_empty()
4631 },
4632 );
4633 }
4634
4635 let diagnostic_updates = local
4636 .language_servers
4637 .keys()
4638 .cloned()
4639 .map(|server_id| DocumentDiagnosticsUpdate {
4640 diagnostics: DocumentDiagnostics {
4641 document_abs_path: buffer_abs_path.clone(),
4642 version: None,
4643 diagnostics: Vec::new(),
4644 },
4645 result_id: None,
4646 registration_id: None,
4647 server_id,
4648 disk_based_sources: Cow::Borrowed(&[]),
4649 })
4650 .collect::<Vec<_>>();
4651
4652 lsp_store
4653 .merge_diagnostic_entries(
4654 diagnostic_updates,
4655 |_, diagnostic, _| {
4656 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4657 },
4658 cx,
4659 )
4660 .context("Clearing diagnostics for the closed buffer")
4661 .log_err();
4662 }
4663 }
4664 })
4665 .detach();
4666 }
4667 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4668 let buffer_id = buffer.read(cx).remote_id().to_proto();
4669 cx.background_spawn(async move {
4670 upstream_client
4671 .request(proto::RegisterBufferWithLanguageServers {
4672 project_id: upstream_project_id,
4673 buffer_id,
4674 only_servers: only_register_servers
4675 .into_iter()
4676 .map(|selector| {
4677 let selector = match selector {
4678 LanguageServerSelector::Id(language_server_id) => {
4679 proto::language_server_selector::Selector::ServerId(
4680 language_server_id.to_proto(),
4681 )
4682 }
4683 LanguageServerSelector::Name(language_server_name) => {
4684 proto::language_server_selector::Selector::Name(
4685 language_server_name.to_string(),
4686 )
4687 }
4688 };
4689 proto::LanguageServerSelector {
4690 selector: Some(selector),
4691 }
4692 })
4693 .collect(),
4694 })
4695 .await
4696 })
4697 .detach();
4698 } else {
4699 // Our remote connection got closed
4700 }
4701 handle
4702 }
4703
4704 fn maintain_buffer_languages(
4705 languages: Arc<LanguageRegistry>,
4706 cx: &mut Context<Self>,
4707 ) -> Task<()> {
4708 let mut subscription = languages.subscribe();
4709 let mut prev_reload_count = languages.reload_count();
4710 cx.spawn(async move |this, cx| {
4711 while let Some(()) = subscription.next().await {
4712 if let Some(this) = this.upgrade() {
4713 // If the language registry has been reloaded, then remove and
4714 // re-assign the languages on all open buffers.
4715 let reload_count = languages.reload_count();
4716 if reload_count > prev_reload_count {
4717 prev_reload_count = reload_count;
4718 this.update(cx, |this, cx| {
4719 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4720 for buffer in buffer_store.buffers() {
4721 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4722 {
4723 buffer.update(cx, |buffer, cx| {
4724 buffer.set_language_async(None, cx)
4725 });
4726 if let Some(local) = this.as_local_mut() {
4727 local.reset_buffer(&buffer, &f, cx);
4728
4729 if local
4730 .registered_buffers
4731 .contains_key(&buffer.read(cx).remote_id())
4732 && let Some(file_url) =
4733 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4734 {
4735 local.unregister_buffer_from_language_servers(
4736 &buffer, &file_url, cx,
4737 );
4738 }
4739 }
4740 }
4741 }
4742 });
4743 });
4744 }
4745
4746 this.update(cx, |this, cx| {
4747 let mut plain_text_buffers = Vec::new();
4748 let mut buffers_with_unknown_injections = Vec::new();
4749 for handle in this.buffer_store.read(cx).buffers() {
4750 let buffer = handle.read(cx);
4751 if buffer.language().is_none()
4752 || buffer.language() == Some(&*language::PLAIN_TEXT)
4753 {
4754 plain_text_buffers.push(handle);
4755 } else if buffer.contains_unknown_injections() {
4756 buffers_with_unknown_injections.push(handle);
4757 }
4758 }
4759
4760 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4761 // and reused later in the invisible worktrees.
4762 plain_text_buffers.sort_by_key(|buffer| {
4763 Reverse(
4764 File::from_dyn(buffer.read(cx).file())
4765 .map(|file| file.worktree.read(cx).is_visible()),
4766 )
4767 });
4768
4769 for buffer in plain_text_buffers {
4770 this.detect_language_for_buffer(&buffer, cx);
4771 if let Some(local) = this.as_local_mut() {
4772 local.initialize_buffer(&buffer, cx);
4773 if local
4774 .registered_buffers
4775 .contains_key(&buffer.read(cx).remote_id())
4776 {
4777 local.register_buffer_with_language_servers(
4778 &buffer,
4779 HashSet::default(),
4780 cx,
4781 );
4782 }
4783 }
4784 }
4785
4786 for buffer in buffers_with_unknown_injections {
4787 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4788 }
4789 });
4790 }
4791 }
4792 })
4793 }
4794
4795 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4796 let buffer = buffer_handle.read(cx);
4797 let content = buffer.as_rope();
4798
4799 let modeline_settings = {
4800 let settings_store = cx.global::<SettingsStore>();
4801 let modeline_lines = settings_store
4802 .raw_user_settings()
4803 .and_then(|s| s.content.modeline_lines)
4804 .or(settings_store.raw_default_settings().modeline_lines)
4805 .unwrap_or(5);
4806
4807 const MAX_MODELINE_BYTES: usize = 1024;
4808
4809 let first_bytes =
4810 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4811 let mut first_lines = Vec::new();
4812 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4813 for _ in 0..modeline_lines {
4814 if let Some(line) = lines.next() {
4815 first_lines.push(line.to_string());
4816 } else {
4817 break;
4818 }
4819 }
4820 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4821
4822 let last_start =
4823 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4824 let mut last_lines = Vec::new();
4825 let mut lines = content
4826 .reversed_chunks_in_range(last_start..content.len())
4827 .lines();
4828 for _ in 0..modeline_lines {
4829 if let Some(line) = lines.next() {
4830 last_lines.push(line.to_string());
4831 } else {
4832 break;
4833 }
4834 }
4835 let last_lines_ref: Vec<_> =
4836 last_lines.iter().rev().map(|line| line.as_str()).collect();
4837 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4838 };
4839
4840 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4841
4842 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4843 }
4844
4845 fn detect_language_for_buffer(
4846 &mut self,
4847 buffer_handle: &Entity<Buffer>,
4848 cx: &mut Context<Self>,
4849 ) -> Option<language::AvailableLanguage> {
4850 // If the buffer has a language, set it and start the language server if we haven't already.
4851 let buffer = buffer_handle.read(cx);
4852 let file = buffer.file()?;
4853 let content = buffer.as_rope();
4854 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4855
4856 let available_language = if let Some(ModelineSettings {
4857 mode: Some(mode_name),
4858 ..
4859 }) = modeline_settings
4860 {
4861 self.languages
4862 .available_language_for_modeline_name(mode_name)
4863 } else {
4864 self.languages.language_for_file(file, Some(content), cx)
4865 };
4866 if let Some(available_language) = &available_language {
4867 if let Some(Ok(Ok(new_language))) = self
4868 .languages
4869 .load_language(available_language)
4870 .now_or_never()
4871 {
4872 self.set_language_for_buffer(buffer_handle, new_language, cx);
4873 }
4874 } else {
4875 cx.emit(LspStoreEvent::LanguageDetected {
4876 buffer: buffer_handle.clone(),
4877 new_language: None,
4878 });
4879 }
4880
4881 available_language
4882 }
4883
4884 pub(crate) fn set_language_for_buffer(
4885 &mut self,
4886 buffer_entity: &Entity<Buffer>,
4887 new_language: Arc<Language>,
4888 cx: &mut Context<Self>,
4889 ) {
4890 let buffer = buffer_entity.read(cx);
4891 let buffer_file = buffer.file().cloned();
4892 let buffer_id = buffer.remote_id();
4893 if let Some(local_store) = self.as_local_mut()
4894 && local_store.registered_buffers.contains_key(&buffer_id)
4895 && let Some(abs_path) =
4896 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4897 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4898 {
4899 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4900 }
4901 buffer_entity.update(cx, |buffer, cx| {
4902 if buffer
4903 .language()
4904 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4905 {
4906 buffer.set_language_async(Some(new_language.clone()), cx);
4907 }
4908 });
4909
4910 let settings = LanguageSettings::resolve(
4911 Some(&buffer_entity.read(cx)),
4912 Some(&new_language.name()),
4913 cx,
4914 )
4915 .into_owned();
4916 let buffer_file = File::from_dyn(buffer_file.as_ref());
4917
4918 let worktree_id = if let Some(file) = buffer_file {
4919 let worktree = file.worktree.clone();
4920
4921 if let Some(local) = self.as_local_mut()
4922 && local.registered_buffers.contains_key(&buffer_id)
4923 {
4924 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4925 }
4926 Some(worktree.read(cx).id())
4927 } else {
4928 None
4929 };
4930
4931 if settings.prettier.allowed
4932 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4933 {
4934 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4935 if let Some(prettier_store) = prettier_store {
4936 prettier_store.update(cx, |prettier_store, cx| {
4937 prettier_store.install_default_prettier(
4938 worktree_id,
4939 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4940 cx,
4941 )
4942 })
4943 }
4944 }
4945
4946 cx.emit(LspStoreEvent::LanguageDetected {
4947 buffer: buffer_entity.clone(),
4948 new_language: Some(new_language),
4949 })
4950 }
4951
4952 pub fn buffer_store(&self) -> Entity<BufferStore> {
4953 self.buffer_store.clone()
4954 }
4955
4956 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4957 self.active_entry = active_entry;
4958 }
4959
4960 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4961 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4962 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4963 {
4964 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4965 summaries
4966 .iter()
4967 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4968 });
4969 if let Some(summary) = summaries.next() {
4970 client
4971 .send(proto::UpdateDiagnosticSummary {
4972 project_id: downstream_project_id,
4973 worktree_id: worktree.id().to_proto(),
4974 summary: Some(summary),
4975 more_summaries: summaries.collect(),
4976 })
4977 .log_err();
4978 }
4979 }
4980 }
4981
4982 fn is_capable_for_proto_request<R>(
4983 &self,
4984 buffer: &Entity<Buffer>,
4985 request: &R,
4986 cx: &App,
4987 ) -> bool
4988 where
4989 R: LspCommand,
4990 {
4991 self.check_if_capable_for_proto_request(
4992 buffer,
4993 |capabilities| {
4994 request.check_capabilities(AdapterServerCapabilities {
4995 server_capabilities: capabilities.clone(),
4996 code_action_kinds: None,
4997 })
4998 },
4999 cx,
5000 )
5001 }
5002
5003 fn check_if_capable_for_proto_request<F>(
5004 &self,
5005 buffer: &Entity<Buffer>,
5006 check: F,
5007 cx: &App,
5008 ) -> bool
5009 where
5010 F: FnMut(&lsp::ServerCapabilities) -> bool,
5011 {
5012 let Some(language) = buffer.read(cx).language().cloned() else {
5013 return false;
5014 };
5015 let registered_language_servers = self
5016 .languages
5017 .lsp_adapters(&language.name())
5018 .into_iter()
5019 .map(|lsp_adapter| lsp_adapter.name())
5020 .collect::<HashSet<_>>();
5021 self.language_server_statuses
5022 .iter()
5023 .filter_map(|(server_id, server_status)| {
5024 // Include servers that are either registered for this language OR
5025 // available to be loaded (for SSH remote mode where adapters like
5026 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5027 // but only loaded on the server side)
5028 let is_relevant = registered_language_servers.contains(&server_status.name)
5029 || self.languages.is_lsp_adapter_available(&server_status.name);
5030 is_relevant.then_some(server_id)
5031 })
5032 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
5033 .any(check)
5034 }
5035
5036 fn all_capable_for_proto_request<F>(
5037 &self,
5038 buffer: &Entity<Buffer>,
5039 mut check: F,
5040 cx: &App,
5041 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5042 where
5043 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5044 {
5045 let Some(language) = buffer.read(cx).language().cloned() else {
5046 return Vec::default();
5047 };
5048 let registered_language_servers = self
5049 .languages
5050 .lsp_adapters(&language.name())
5051 .into_iter()
5052 .map(|lsp_adapter| lsp_adapter.name())
5053 .collect::<HashSet<_>>();
5054 self.language_server_statuses
5055 .iter()
5056 .filter_map(|(server_id, server_status)| {
5057 // Include servers that are either registered for this language OR
5058 // available to be loaded (for SSH remote mode where adapters like
5059 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5060 // but only loaded on the server side)
5061 let is_relevant = registered_language_servers.contains(&server_status.name)
5062 || self.languages.is_lsp_adapter_available(&server_status.name);
5063 is_relevant.then_some((server_id, &server_status.name))
5064 })
5065 .filter_map(|(server_id, server_name)| {
5066 self.lsp_server_capabilities
5067 .get(server_id)
5068 .map(|c| (server_id, server_name, c))
5069 })
5070 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5071 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5072 .collect()
5073 }
5074
5075 pub fn request_lsp<R>(
5076 &mut self,
5077 buffer: Entity<Buffer>,
5078 server: LanguageServerToQuery,
5079 request: R,
5080 cx: &mut Context<Self>,
5081 ) -> Task<Result<R::Response>>
5082 where
5083 R: LspCommand,
5084 <R::LspRequest as lsp::request::Request>::Result: Send,
5085 <R::LspRequest as lsp::request::Request>::Params: Send,
5086 {
5087 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5088 return self.send_lsp_proto_request(
5089 buffer,
5090 upstream_client,
5091 upstream_project_id,
5092 request,
5093 cx,
5094 );
5095 }
5096
5097 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5098 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5099 local
5100 .language_servers_for_buffer(buffer, cx)
5101 .find(|(_, server)| {
5102 request.check_capabilities(server.adapter_server_capabilities())
5103 })
5104 .map(|(_, server)| server.clone())
5105 }),
5106 LanguageServerToQuery::Other(id) => self
5107 .language_server_for_local_buffer(buffer, id, cx)
5108 .and_then(|(_, server)| {
5109 request
5110 .check_capabilities(server.adapter_server_capabilities())
5111 .then(|| Arc::clone(server))
5112 }),
5113 }) else {
5114 return Task::ready(Ok(Default::default()));
5115 };
5116
5117 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5118
5119 let Some(file) = file else {
5120 return Task::ready(Ok(Default::default()));
5121 };
5122
5123 let lsp_params = match request.to_lsp_params_or_response(
5124 &file.abs_path(cx),
5125 buffer.read(cx),
5126 &language_server,
5127 cx,
5128 ) {
5129 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5130 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5131 Err(err) => {
5132 let message = format!(
5133 "{} via {} failed: {}",
5134 request.display_name(),
5135 language_server.name(),
5136 err
5137 );
5138 // rust-analyzer likes to error with this when its still loading up
5139 if !message.ends_with("content modified") {
5140 log::warn!("{message}");
5141 }
5142 return Task::ready(Err(anyhow!(message)));
5143 }
5144 };
5145
5146 let status = request.status();
5147 let request_timeout = ProjectSettings::get_global(cx)
5148 .global_lsp_settings
5149 .get_request_timeout();
5150
5151 cx.spawn(async move |this, cx| {
5152 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5153
5154 let id = lsp_request.id();
5155 let _cleanup = if status.is_some() {
5156 cx.update(|cx| {
5157 this.update(cx, |this, cx| {
5158 this.on_lsp_work_start(
5159 language_server.server_id(),
5160 ProgressToken::Number(id),
5161 LanguageServerProgress {
5162 is_disk_based_diagnostics_progress: false,
5163 is_cancellable: false,
5164 title: None,
5165 message: status.clone(),
5166 percentage: None,
5167 last_update_at: cx.background_executor().now(),
5168 },
5169 cx,
5170 );
5171 })
5172 })
5173 .log_err();
5174
5175 Some(defer(|| {
5176 cx.update(|cx| {
5177 this.update(cx, |this, cx| {
5178 this.on_lsp_work_end(
5179 language_server.server_id(),
5180 ProgressToken::Number(id),
5181 cx,
5182 );
5183 })
5184 })
5185 .log_err();
5186 }))
5187 } else {
5188 None
5189 };
5190
5191 let result = lsp_request.await.into_response();
5192
5193 let response = result.map_err(|err| {
5194 let message = format!(
5195 "{} via {} failed: {}",
5196 request.display_name(),
5197 language_server.name(),
5198 err
5199 );
5200 // rust-analyzer likes to error with this when its still loading up
5201 if !message.ends_with("content modified") {
5202 log::warn!("{message}");
5203 }
5204 anyhow::anyhow!(message)
5205 })?;
5206
5207 request
5208 .response_from_lsp(
5209 response,
5210 this.upgrade().context("no app context")?,
5211 buffer,
5212 language_server.server_id(),
5213 cx.clone(),
5214 )
5215 .await
5216 })
5217 }
5218
5219 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5220 let mut language_formatters_to_check = Vec::new();
5221 for buffer in self.buffer_store.read(cx).buffers() {
5222 let buffer = buffer.read(cx);
5223 let settings = LanguageSettings::for_buffer(buffer, cx);
5224 if buffer.language().is_some() {
5225 let buffer_file = File::from_dyn(buffer.file());
5226 language_formatters_to_check.push((
5227 buffer_file.map(|f| f.worktree_id(cx)),
5228 settings.into_owned(),
5229 ));
5230 }
5231 }
5232
5233 self.request_workspace_config_refresh();
5234
5235 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5236 prettier_store.update(cx, |prettier_store, cx| {
5237 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5238 })
5239 }
5240
5241 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5242 .global_lsp_settings
5243 .semantic_token_rules
5244 .clone();
5245 self.semantic_token_config
5246 .update_rules(new_semantic_token_rules);
5247 // Always clear cached stylizers so that changes to language-specific
5248 // semantic token rules (e.g. from extension install/uninstall) are
5249 // picked up. Stylizers are recreated lazily, so this is cheap.
5250 self.semantic_token_config.clear_stylizers();
5251
5252 let new_global_semantic_tokens_mode =
5253 all_language_settings(None, cx).defaults.semantic_tokens;
5254 if self
5255 .semantic_token_config
5256 .update_global_mode(new_global_semantic_tokens_mode)
5257 {
5258 self.restart_all_language_servers(cx);
5259 }
5260
5261 cx.notify();
5262 }
5263
5264 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5265 let buffer_store = self.buffer_store.clone();
5266 let Some(local) = self.as_local_mut() else {
5267 return;
5268 };
5269 let mut adapters = BTreeMap::default();
5270 let get_adapter = {
5271 let languages = local.languages.clone();
5272 let environment = local.environment.clone();
5273 let weak = local.weak.clone();
5274 let worktree_store = local.worktree_store.clone();
5275 let http_client = local.http_client.clone();
5276 let fs = local.fs.clone();
5277 move |worktree_id, cx: &mut App| {
5278 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5279 Some(LocalLspAdapterDelegate::new(
5280 languages.clone(),
5281 &environment,
5282 weak.clone(),
5283 &worktree,
5284 http_client.clone(),
5285 fs.clone(),
5286 cx,
5287 ))
5288 }
5289 };
5290
5291 let mut messages_to_report = Vec::new();
5292 let (new_tree, to_stop) = {
5293 let mut rebase = local.lsp_tree.rebase();
5294 let buffers = buffer_store
5295 .read(cx)
5296 .buffers()
5297 .filter_map(|buffer| {
5298 let raw_buffer = buffer.read(cx);
5299 if !local
5300 .registered_buffers
5301 .contains_key(&raw_buffer.remote_id())
5302 {
5303 return None;
5304 }
5305 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5306 let language = raw_buffer.language().cloned()?;
5307 Some((file, language, raw_buffer.remote_id()))
5308 })
5309 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5310 for (file, language, buffer_id) in buffers {
5311 let worktree_id = file.worktree_id(cx);
5312 let Some(worktree) = local
5313 .worktree_store
5314 .read(cx)
5315 .worktree_for_id(worktree_id, cx)
5316 else {
5317 continue;
5318 };
5319
5320 if let Some((_, apply)) = local.reuse_existing_language_server(
5321 rebase.server_tree(),
5322 &worktree,
5323 &language.name(),
5324 cx,
5325 ) {
5326 (apply)(rebase.server_tree());
5327 } else if let Some(lsp_delegate) = adapters
5328 .entry(worktree_id)
5329 .or_insert_with(|| get_adapter(worktree_id, cx))
5330 .clone()
5331 {
5332 let delegate =
5333 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5334 let path = file
5335 .path()
5336 .parent()
5337 .map(Arc::from)
5338 .unwrap_or_else(|| file.path().clone());
5339 let worktree_path = ProjectPath { worktree_id, path };
5340 let abs_path = file.abs_path(cx);
5341 let nodes = rebase
5342 .walk(
5343 worktree_path,
5344 language.name(),
5345 language.manifest(),
5346 delegate.clone(),
5347 cx,
5348 )
5349 .collect::<Vec<_>>();
5350 for node in nodes {
5351 let server_id = node.server_id_or_init(|disposition| {
5352 let path = &disposition.path;
5353 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5354 let key = LanguageServerSeed {
5355 worktree_id,
5356 name: disposition.server_name.clone(),
5357 settings: LanguageServerSeedSettings {
5358 binary: disposition.settings.binary.clone(),
5359 initialization_options: disposition
5360 .settings
5361 .initialization_options
5362 .clone(),
5363 },
5364 toolchain: local.toolchain_store.read(cx).active_toolchain(
5365 path.worktree_id,
5366 &path.path,
5367 language.name(),
5368 ),
5369 };
5370 local.language_server_ids.remove(&key);
5371
5372 let server_id = local.get_or_insert_language_server(
5373 &worktree,
5374 lsp_delegate.clone(),
5375 disposition,
5376 &language.name(),
5377 cx,
5378 );
5379 if let Some(state) = local.language_servers.get(&server_id)
5380 && let Ok(uri) = uri
5381 {
5382 state.add_workspace_folder(uri);
5383 };
5384 server_id
5385 });
5386
5387 if let Some(language_server_id) = server_id {
5388 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5389 language_server_id,
5390 name: node.name(),
5391 message:
5392 proto::update_language_server::Variant::RegisteredForBuffer(
5393 proto::RegisteredForBuffer {
5394 buffer_abs_path: abs_path
5395 .to_string_lossy()
5396 .into_owned(),
5397 buffer_id: buffer_id.to_proto(),
5398 },
5399 ),
5400 });
5401 }
5402 }
5403 } else {
5404 continue;
5405 }
5406 }
5407 rebase.finish()
5408 };
5409 for message in messages_to_report {
5410 cx.emit(message);
5411 }
5412 local.lsp_tree = new_tree;
5413 for (id, _) in to_stop {
5414 self.stop_local_language_server(id, cx).detach();
5415 }
5416 }
5417
5418 pub fn apply_code_action(
5419 &self,
5420 buffer_handle: Entity<Buffer>,
5421 mut action: CodeAction,
5422 push_to_history: bool,
5423 cx: &mut Context<Self>,
5424 ) -> Task<Result<ProjectTransaction>> {
5425 if let Some((upstream_client, project_id)) = self.upstream_client() {
5426 let request = proto::ApplyCodeAction {
5427 project_id,
5428 buffer_id: buffer_handle.read(cx).remote_id().into(),
5429 action: Some(Self::serialize_code_action(&action)),
5430 };
5431 let buffer_store = self.buffer_store();
5432 cx.spawn(async move |_, cx| {
5433 let response = upstream_client
5434 .request(request)
5435 .await?
5436 .transaction
5437 .context("missing transaction")?;
5438
5439 buffer_store
5440 .update(cx, |buffer_store, cx| {
5441 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5442 })
5443 .await
5444 })
5445 } else if self.mode.is_local() {
5446 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5447 let request_timeout = ProjectSettings::get_global(cx)
5448 .global_lsp_settings
5449 .get_request_timeout();
5450 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5451 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5452 }) else {
5453 return Task::ready(Ok(ProjectTransaction::default()));
5454 };
5455
5456 cx.spawn(async move |this, cx| {
5457 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5458 .await
5459 .context("resolving a code action")?;
5460 if let Some(edit) = action.lsp_action.edit()
5461 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5462 return LocalLspStore::deserialize_workspace_edit(
5463 this.upgrade().context("no app present")?,
5464 edit.clone(),
5465 push_to_history,
5466
5467 lang_server.clone(),
5468 cx,
5469 )
5470 .await;
5471 }
5472
5473 let Some(command) = action.lsp_action.command() else {
5474 return Ok(ProjectTransaction::default())
5475 };
5476
5477 let server_capabilities = lang_server.capabilities();
5478 let available_commands = server_capabilities
5479 .execute_command_provider
5480 .as_ref()
5481 .map(|options| options.commands.as_slice())
5482 .unwrap_or_default();
5483
5484 if !available_commands.contains(&command.command) {
5485 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5486 return Ok(ProjectTransaction::default())
5487 }
5488
5489 let request_timeout = cx.update(|app|
5490 ProjectSettings::get_global(app)
5491 .global_lsp_settings
5492 .get_request_timeout()
5493 );
5494
5495 this.update(cx, |this, _| {
5496 this.as_local_mut()
5497 .unwrap()
5498 .last_workspace_edits_by_language_server
5499 .remove(&lang_server.server_id());
5500 })?;
5501
5502 let _result = lang_server
5503 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5504 command: command.command.clone(),
5505 arguments: command.arguments.clone().unwrap_or_default(),
5506 ..lsp::ExecuteCommandParams::default()
5507 }, request_timeout)
5508 .await.into_response()
5509 .context("execute command")?;
5510
5511 return this.update(cx, |this, _| {
5512 this.as_local_mut()
5513 .unwrap()
5514 .last_workspace_edits_by_language_server
5515 .remove(&lang_server.server_id())
5516 .unwrap_or_default()
5517 });
5518 })
5519 } else {
5520 Task::ready(Err(anyhow!("no upstream client and not local")))
5521 }
5522 }
5523
5524 pub fn apply_code_action_kind(
5525 &mut self,
5526 buffers: HashSet<Entity<Buffer>>,
5527 kind: CodeActionKind,
5528 push_to_history: bool,
5529 cx: &mut Context<Self>,
5530 ) -> Task<anyhow::Result<ProjectTransaction>> {
5531 if self.as_local().is_some() {
5532 cx.spawn(async move |lsp_store, cx| {
5533 let buffers = buffers.into_iter().collect::<Vec<_>>();
5534 let result = LocalLspStore::execute_code_action_kind_locally(
5535 lsp_store.clone(),
5536 buffers,
5537 kind,
5538 push_to_history,
5539 cx,
5540 )
5541 .await;
5542 lsp_store.update(cx, |lsp_store, _| {
5543 lsp_store.update_last_formatting_failure(&result);
5544 })?;
5545 result
5546 })
5547 } else if let Some((client, project_id)) = self.upstream_client() {
5548 let buffer_store = self.buffer_store();
5549 cx.spawn(async move |lsp_store, cx| {
5550 let result = client
5551 .request(proto::ApplyCodeActionKind {
5552 project_id,
5553 kind: kind.as_str().to_owned(),
5554 buffer_ids: buffers
5555 .iter()
5556 .map(|buffer| {
5557 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5558 })
5559 .collect(),
5560 })
5561 .await
5562 .and_then(|result| result.transaction.context("missing transaction"));
5563 lsp_store.update(cx, |lsp_store, _| {
5564 lsp_store.update_last_formatting_failure(&result);
5565 })?;
5566
5567 let transaction_response = result?;
5568 buffer_store
5569 .update(cx, |buffer_store, cx| {
5570 buffer_store.deserialize_project_transaction(
5571 transaction_response,
5572 push_to_history,
5573 cx,
5574 )
5575 })
5576 .await
5577 })
5578 } else {
5579 Task::ready(Ok(ProjectTransaction::default()))
5580 }
5581 }
5582
5583 pub fn resolved_hint(
5584 &mut self,
5585 buffer_id: BufferId,
5586 id: InlayId,
5587 cx: &mut Context<Self>,
5588 ) -> Option<ResolvedHint> {
5589 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5590
5591 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5592 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5593 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5594 let (server_id, resolve_data) = match &hint.resolve_state {
5595 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5596 ResolveState::Resolving => {
5597 return Some(ResolvedHint::Resolving(
5598 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5599 ));
5600 }
5601 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5602 };
5603
5604 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5605 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5606 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5607 id,
5608 cx.spawn(async move |lsp_store, cx| {
5609 let resolved_hint = resolve_task.await;
5610 lsp_store
5611 .update(cx, |lsp_store, _| {
5612 if let Some(old_inlay_hint) = lsp_store
5613 .lsp_data
5614 .get_mut(&buffer_id)
5615 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5616 {
5617 match resolved_hint {
5618 Ok(resolved_hint) => {
5619 *old_inlay_hint = resolved_hint;
5620 }
5621 Err(e) => {
5622 old_inlay_hint.resolve_state =
5623 ResolveState::CanResolve(server_id, resolve_data);
5624 log::error!("Inlay hint resolve failed: {e:#}");
5625 }
5626 }
5627 }
5628 })
5629 .ok();
5630 })
5631 .shared(),
5632 );
5633 debug_assert!(
5634 previous_task.is_none(),
5635 "Did not change hint's resolve state after spawning its resolve"
5636 );
5637 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5638 None
5639 }
5640
5641 pub(crate) fn linked_edits(
5642 &mut self,
5643 buffer: &Entity<Buffer>,
5644 position: Anchor,
5645 cx: &mut Context<Self>,
5646 ) -> Task<Result<Vec<Range<Anchor>>>> {
5647 let snapshot = buffer.read(cx).snapshot();
5648 let scope = snapshot.language_scope_at(position);
5649 let Some(server_id) = self
5650 .as_local()
5651 .and_then(|local| {
5652 buffer.update(cx, |buffer, cx| {
5653 local
5654 .language_servers_for_buffer(buffer, cx)
5655 .filter(|(_, server)| {
5656 LinkedEditingRange::check_server_capabilities(server.capabilities())
5657 })
5658 .filter(|(adapter, _)| {
5659 scope
5660 .as_ref()
5661 .map(|scope| scope.language_allowed(&adapter.name))
5662 .unwrap_or(true)
5663 })
5664 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5665 .next()
5666 })
5667 })
5668 .or_else(|| {
5669 self.upstream_client()
5670 .is_some()
5671 .then_some(LanguageServerToQuery::FirstCapable)
5672 })
5673 .filter(|_| {
5674 maybe!({
5675 buffer.read(cx).language_at(position)?;
5676 Some(
5677 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5678 .linked_edits,
5679 )
5680 }) == Some(true)
5681 })
5682 else {
5683 return Task::ready(Ok(Vec::new()));
5684 };
5685
5686 self.request_lsp(
5687 buffer.clone(),
5688 server_id,
5689 LinkedEditingRange { position },
5690 cx,
5691 )
5692 }
5693
5694 fn apply_on_type_formatting(
5695 &mut self,
5696 buffer: Entity<Buffer>,
5697 position: Anchor,
5698 trigger: String,
5699 cx: &mut Context<Self>,
5700 ) -> Task<Result<Option<Transaction>>> {
5701 if let Some((client, project_id)) = self.upstream_client() {
5702 if !self.check_if_capable_for_proto_request(
5703 &buffer,
5704 |capabilities| {
5705 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5706 },
5707 cx,
5708 ) {
5709 return Task::ready(Ok(None));
5710 }
5711 let request = proto::OnTypeFormatting {
5712 project_id,
5713 buffer_id: buffer.read(cx).remote_id().into(),
5714 position: Some(serialize_anchor(&position)),
5715 trigger,
5716 version: serialize_version(&buffer.read(cx).version()),
5717 };
5718 cx.background_spawn(async move {
5719 client
5720 .request(request)
5721 .await?
5722 .transaction
5723 .map(language::proto::deserialize_transaction)
5724 .transpose()
5725 })
5726 } else if let Some(local) = self.as_local_mut() {
5727 let buffer_id = buffer.read(cx).remote_id();
5728 local.buffers_being_formatted.insert(buffer_id);
5729 cx.spawn(async move |this, cx| {
5730 let _cleanup = defer({
5731 let this = this.clone();
5732 let mut cx = cx.clone();
5733 move || {
5734 this.update(&mut cx, |this, _| {
5735 if let Some(local) = this.as_local_mut() {
5736 local.buffers_being_formatted.remove(&buffer_id);
5737 }
5738 })
5739 .ok();
5740 }
5741 });
5742
5743 buffer
5744 .update(cx, |buffer, _| {
5745 buffer.wait_for_edits(Some(position.timestamp()))
5746 })
5747 .await?;
5748 this.update(cx, |this, cx| {
5749 let position = position.to_point_utf16(buffer.read(cx));
5750 this.on_type_format(buffer, position, trigger, false, cx)
5751 })?
5752 .await
5753 })
5754 } else {
5755 Task::ready(Err(anyhow!("No upstream client or local language server")))
5756 }
5757 }
5758
5759 pub fn on_type_format<T: ToPointUtf16>(
5760 &mut self,
5761 buffer: Entity<Buffer>,
5762 position: T,
5763 trigger: String,
5764 push_to_history: bool,
5765 cx: &mut Context<Self>,
5766 ) -> Task<Result<Option<Transaction>>> {
5767 let position = position.to_point_utf16(buffer.read(cx));
5768 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5769 }
5770
5771 fn on_type_format_impl(
5772 &mut self,
5773 buffer: Entity<Buffer>,
5774 position: PointUtf16,
5775 trigger: String,
5776 push_to_history: bool,
5777 cx: &mut Context<Self>,
5778 ) -> Task<Result<Option<Transaction>>> {
5779 let options = buffer.update(cx, |buffer, cx| {
5780 lsp_command::lsp_formatting_options(
5781 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5782 )
5783 });
5784
5785 cx.spawn(async move |this, cx| {
5786 if let Some(waiter) =
5787 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5788 {
5789 waiter.await?;
5790 }
5791 cx.update(|cx| {
5792 this.update(cx, |this, cx| {
5793 this.request_lsp(
5794 buffer.clone(),
5795 LanguageServerToQuery::FirstCapable,
5796 OnTypeFormatting {
5797 position,
5798 trigger,
5799 options,
5800 push_to_history,
5801 },
5802 cx,
5803 )
5804 })
5805 })?
5806 .await
5807 })
5808 }
5809
5810 pub fn definitions(
5811 &mut self,
5812 buffer: &Entity<Buffer>,
5813 position: PointUtf16,
5814 cx: &mut Context<Self>,
5815 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5816 if let Some((upstream_client, project_id)) = self.upstream_client() {
5817 let request = GetDefinitions { position };
5818 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5819 return Task::ready(Ok(None));
5820 }
5821
5822 let request_timeout = ProjectSettings::get_global(cx)
5823 .global_lsp_settings
5824 .get_request_timeout();
5825
5826 let request_task = upstream_client.request_lsp(
5827 project_id,
5828 None,
5829 request_timeout,
5830 cx.background_executor().clone(),
5831 request.to_proto(project_id, buffer.read(cx)),
5832 );
5833 let buffer = buffer.clone();
5834 cx.spawn(async move |weak_lsp_store, cx| {
5835 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5836 return Ok(None);
5837 };
5838 let Some(responses) = request_task.await? else {
5839 return Ok(None);
5840 };
5841 let actions = join_all(responses.payload.into_iter().map(|response| {
5842 GetDefinitions { position }.response_from_proto(
5843 response.response,
5844 lsp_store.clone(),
5845 buffer.clone(),
5846 cx.clone(),
5847 )
5848 }))
5849 .await;
5850
5851 Ok(Some(
5852 actions
5853 .into_iter()
5854 .collect::<Result<Vec<Vec<_>>>>()?
5855 .into_iter()
5856 .flatten()
5857 .dedup()
5858 .collect(),
5859 ))
5860 })
5861 } else {
5862 let definitions_task = self.request_multiple_lsp_locally(
5863 buffer,
5864 Some(position),
5865 GetDefinitions { position },
5866 cx,
5867 );
5868 cx.background_spawn(async move {
5869 Ok(Some(
5870 definitions_task
5871 .await
5872 .into_iter()
5873 .flat_map(|(_, definitions)| definitions)
5874 .dedup()
5875 .collect(),
5876 ))
5877 })
5878 }
5879 }
5880
5881 pub fn declarations(
5882 &mut self,
5883 buffer: &Entity<Buffer>,
5884 position: PointUtf16,
5885 cx: &mut Context<Self>,
5886 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5887 if let Some((upstream_client, project_id)) = self.upstream_client() {
5888 let request = GetDeclarations { position };
5889 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5890 return Task::ready(Ok(None));
5891 }
5892 let request_timeout = ProjectSettings::get_global(cx)
5893 .global_lsp_settings
5894 .get_request_timeout();
5895 let request_task = upstream_client.request_lsp(
5896 project_id,
5897 None,
5898 request_timeout,
5899 cx.background_executor().clone(),
5900 request.to_proto(project_id, buffer.read(cx)),
5901 );
5902 let buffer = buffer.clone();
5903 cx.spawn(async move |weak_lsp_store, cx| {
5904 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5905 return Ok(None);
5906 };
5907 let Some(responses) = request_task.await? else {
5908 return Ok(None);
5909 };
5910 let actions = join_all(responses.payload.into_iter().map(|response| {
5911 GetDeclarations { position }.response_from_proto(
5912 response.response,
5913 lsp_store.clone(),
5914 buffer.clone(),
5915 cx.clone(),
5916 )
5917 }))
5918 .await;
5919
5920 Ok(Some(
5921 actions
5922 .into_iter()
5923 .collect::<Result<Vec<Vec<_>>>>()?
5924 .into_iter()
5925 .flatten()
5926 .dedup()
5927 .collect(),
5928 ))
5929 })
5930 } else {
5931 let declarations_task = self.request_multiple_lsp_locally(
5932 buffer,
5933 Some(position),
5934 GetDeclarations { position },
5935 cx,
5936 );
5937 cx.background_spawn(async move {
5938 Ok(Some(
5939 declarations_task
5940 .await
5941 .into_iter()
5942 .flat_map(|(_, declarations)| declarations)
5943 .dedup()
5944 .collect(),
5945 ))
5946 })
5947 }
5948 }
5949
5950 pub fn type_definitions(
5951 &mut self,
5952 buffer: &Entity<Buffer>,
5953 position: PointUtf16,
5954 cx: &mut Context<Self>,
5955 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5956 if let Some((upstream_client, project_id)) = self.upstream_client() {
5957 let request = GetTypeDefinitions { position };
5958 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5959 return Task::ready(Ok(None));
5960 }
5961 let request_timeout = ProjectSettings::get_global(cx)
5962 .global_lsp_settings
5963 .get_request_timeout();
5964 let request_task = upstream_client.request_lsp(
5965 project_id,
5966 None,
5967 request_timeout,
5968 cx.background_executor().clone(),
5969 request.to_proto(project_id, buffer.read(cx)),
5970 );
5971 let buffer = buffer.clone();
5972 cx.spawn(async move |weak_lsp_store, cx| {
5973 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5974 return Ok(None);
5975 };
5976 let Some(responses) = request_task.await? else {
5977 return Ok(None);
5978 };
5979 let actions = join_all(responses.payload.into_iter().map(|response| {
5980 GetTypeDefinitions { position }.response_from_proto(
5981 response.response,
5982 lsp_store.clone(),
5983 buffer.clone(),
5984 cx.clone(),
5985 )
5986 }))
5987 .await;
5988
5989 Ok(Some(
5990 actions
5991 .into_iter()
5992 .collect::<Result<Vec<Vec<_>>>>()?
5993 .into_iter()
5994 .flatten()
5995 .dedup()
5996 .collect(),
5997 ))
5998 })
5999 } else {
6000 let type_definitions_task = self.request_multiple_lsp_locally(
6001 buffer,
6002 Some(position),
6003 GetTypeDefinitions { position },
6004 cx,
6005 );
6006 cx.background_spawn(async move {
6007 Ok(Some(
6008 type_definitions_task
6009 .await
6010 .into_iter()
6011 .flat_map(|(_, type_definitions)| type_definitions)
6012 .dedup()
6013 .collect(),
6014 ))
6015 })
6016 }
6017 }
6018
6019 pub fn implementations(
6020 &mut self,
6021 buffer: &Entity<Buffer>,
6022 position: PointUtf16,
6023 cx: &mut Context<Self>,
6024 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6025 if let Some((upstream_client, project_id)) = self.upstream_client() {
6026 let request = GetImplementations { position };
6027 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6028 return Task::ready(Ok(None));
6029 }
6030
6031 let request_timeout = ProjectSettings::get_global(cx)
6032 .global_lsp_settings
6033 .get_request_timeout();
6034 let request_task = upstream_client.request_lsp(
6035 project_id,
6036 None,
6037 request_timeout,
6038 cx.background_executor().clone(),
6039 request.to_proto(project_id, buffer.read(cx)),
6040 );
6041 let buffer = buffer.clone();
6042 cx.spawn(async move |weak_lsp_store, cx| {
6043 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6044 return Ok(None);
6045 };
6046 let Some(responses) = request_task.await? else {
6047 return Ok(None);
6048 };
6049 let actions = join_all(responses.payload.into_iter().map(|response| {
6050 GetImplementations { position }.response_from_proto(
6051 response.response,
6052 lsp_store.clone(),
6053 buffer.clone(),
6054 cx.clone(),
6055 )
6056 }))
6057 .await;
6058
6059 Ok(Some(
6060 actions
6061 .into_iter()
6062 .collect::<Result<Vec<Vec<_>>>>()?
6063 .into_iter()
6064 .flatten()
6065 .dedup()
6066 .collect(),
6067 ))
6068 })
6069 } else {
6070 let implementations_task = self.request_multiple_lsp_locally(
6071 buffer,
6072 Some(position),
6073 GetImplementations { position },
6074 cx,
6075 );
6076 cx.background_spawn(async move {
6077 Ok(Some(
6078 implementations_task
6079 .await
6080 .into_iter()
6081 .flat_map(|(_, implementations)| implementations)
6082 .dedup()
6083 .collect(),
6084 ))
6085 })
6086 }
6087 }
6088
6089 pub fn references(
6090 &mut self,
6091 buffer: &Entity<Buffer>,
6092 position: PointUtf16,
6093 cx: &mut Context<Self>,
6094 ) -> Task<Result<Option<Vec<Location>>>> {
6095 if let Some((upstream_client, project_id)) = self.upstream_client() {
6096 let request = GetReferences { position };
6097 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6098 return Task::ready(Ok(None));
6099 }
6100
6101 let request_timeout = ProjectSettings::get_global(cx)
6102 .global_lsp_settings
6103 .get_request_timeout();
6104 let request_task = upstream_client.request_lsp(
6105 project_id,
6106 None,
6107 request_timeout,
6108 cx.background_executor().clone(),
6109 request.to_proto(project_id, buffer.read(cx)),
6110 );
6111 let buffer = buffer.clone();
6112 cx.spawn(async move |weak_lsp_store, cx| {
6113 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6114 return Ok(None);
6115 };
6116 let Some(responses) = request_task.await? else {
6117 return Ok(None);
6118 };
6119
6120 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6121 GetReferences { position }.response_from_proto(
6122 lsp_response.response,
6123 lsp_store.clone(),
6124 buffer.clone(),
6125 cx.clone(),
6126 )
6127 }))
6128 .await
6129 .into_iter()
6130 .collect::<Result<Vec<Vec<_>>>>()?
6131 .into_iter()
6132 .flatten()
6133 .dedup()
6134 .collect();
6135 Ok(Some(locations))
6136 })
6137 } else {
6138 let references_task = self.request_multiple_lsp_locally(
6139 buffer,
6140 Some(position),
6141 GetReferences { position },
6142 cx,
6143 );
6144 cx.background_spawn(async move {
6145 Ok(Some(
6146 references_task
6147 .await
6148 .into_iter()
6149 .flat_map(|(_, references)| references)
6150 .dedup()
6151 .collect(),
6152 ))
6153 })
6154 }
6155 }
6156
6157 pub fn code_actions(
6158 &mut self,
6159 buffer: &Entity<Buffer>,
6160 range: Range<Anchor>,
6161 kinds: Option<Vec<CodeActionKind>>,
6162 cx: &mut Context<Self>,
6163 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6164 if let Some((upstream_client, project_id)) = self.upstream_client() {
6165 let request = GetCodeActions {
6166 range: range.clone(),
6167 kinds: kinds.clone(),
6168 };
6169 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6170 return Task::ready(Ok(None));
6171 }
6172 let request_timeout = ProjectSettings::get_global(cx)
6173 .global_lsp_settings
6174 .get_request_timeout();
6175 let request_task = upstream_client.request_lsp(
6176 project_id,
6177 None,
6178 request_timeout,
6179 cx.background_executor().clone(),
6180 request.to_proto(project_id, buffer.read(cx)),
6181 );
6182 let buffer = buffer.clone();
6183 cx.spawn(async move |weak_lsp_store, cx| {
6184 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6185 return Ok(None);
6186 };
6187 let Some(responses) = request_task.await? else {
6188 return Ok(None);
6189 };
6190 let actions = join_all(responses.payload.into_iter().map(|response| {
6191 GetCodeActions {
6192 range: range.clone(),
6193 kinds: kinds.clone(),
6194 }
6195 .response_from_proto(
6196 response.response,
6197 lsp_store.clone(),
6198 buffer.clone(),
6199 cx.clone(),
6200 )
6201 }))
6202 .await;
6203
6204 Ok(Some(
6205 actions
6206 .into_iter()
6207 .collect::<Result<Vec<Vec<_>>>>()?
6208 .into_iter()
6209 .flatten()
6210 .collect(),
6211 ))
6212 })
6213 } else {
6214 let all_actions_task = self.request_multiple_lsp_locally(
6215 buffer,
6216 Some(range.start),
6217 GetCodeActions { range, kinds },
6218 cx,
6219 );
6220 cx.background_spawn(async move {
6221 Ok(Some(
6222 all_actions_task
6223 .await
6224 .into_iter()
6225 .flat_map(|(_, actions)| actions)
6226 .collect(),
6227 ))
6228 })
6229 }
6230 }
6231
6232 #[inline(never)]
6233 pub fn completions(
6234 &self,
6235 buffer: &Entity<Buffer>,
6236 position: PointUtf16,
6237 context: CompletionContext,
6238 cx: &mut Context<Self>,
6239 ) -> Task<Result<Vec<CompletionResponse>>> {
6240 let language_registry = self.languages.clone();
6241
6242 if let Some((upstream_client, project_id)) = self.upstream_client() {
6243 let snapshot = buffer.read(cx).snapshot();
6244 let offset = position.to_offset(&snapshot);
6245 let scope = snapshot.language_scope_at(offset);
6246 let capable_lsps = self.all_capable_for_proto_request(
6247 buffer,
6248 |server_name, capabilities| {
6249 capabilities.completion_provider.is_some()
6250 && scope
6251 .as_ref()
6252 .map(|scope| scope.language_allowed(server_name))
6253 .unwrap_or(true)
6254 },
6255 cx,
6256 );
6257 if capable_lsps.is_empty() {
6258 return Task::ready(Ok(Vec::new()));
6259 }
6260
6261 let language = buffer.read(cx).language().cloned();
6262
6263 let buffer = buffer.clone();
6264
6265 cx.spawn(async move |this, cx| {
6266 let requests = join_all(
6267 capable_lsps
6268 .into_iter()
6269 .map(|(id, server_name)| {
6270 let request = GetCompletions {
6271 position,
6272 context: context.clone(),
6273 server_id: Some(id),
6274 };
6275 let buffer = buffer.clone();
6276 let language = language.clone();
6277 let lsp_adapter = language.as_ref().and_then(|language| {
6278 let adapters = language_registry.lsp_adapters(&language.name());
6279 adapters
6280 .iter()
6281 .find(|adapter| adapter.name() == server_name)
6282 .or_else(|| adapters.first())
6283 .cloned()
6284 });
6285 let upstream_client = upstream_client.clone();
6286 let response = this
6287 .update(cx, |this, cx| {
6288 this.send_lsp_proto_request(
6289 buffer,
6290 upstream_client,
6291 project_id,
6292 request,
6293 cx,
6294 )
6295 })
6296 .log_err();
6297 async move {
6298 let response = response?.await.log_err()?;
6299
6300 let completions = populate_labels_for_completions(
6301 response.completions,
6302 language,
6303 lsp_adapter,
6304 )
6305 .await;
6306
6307 Some(CompletionResponse {
6308 completions,
6309 display_options: CompletionDisplayOptions::default(),
6310 is_incomplete: response.is_incomplete,
6311 })
6312 }
6313 })
6314 .collect::<Vec<_>>(),
6315 );
6316 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6317 })
6318 } else if let Some(local) = self.as_local() {
6319 let snapshot = buffer.read(cx).snapshot();
6320 let offset = position.to_offset(&snapshot);
6321 let scope = snapshot.language_scope_at(offset);
6322 let language = snapshot.language().cloned();
6323 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6324 .completions
6325 .clone();
6326 if !completion_settings.lsp {
6327 return Task::ready(Ok(Vec::new()));
6328 }
6329
6330 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6331 local
6332 .language_servers_for_buffer(buffer, cx)
6333 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6334 .filter(|(adapter, _)| {
6335 scope
6336 .as_ref()
6337 .map(|scope| scope.language_allowed(&adapter.name))
6338 .unwrap_or(true)
6339 })
6340 .map(|(_, server)| server.server_id())
6341 .collect()
6342 });
6343
6344 let buffer = buffer.clone();
6345 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6346 let lsp_timeout = if lsp_timeout > 0 {
6347 Some(Duration::from_millis(lsp_timeout))
6348 } else {
6349 None
6350 };
6351 cx.spawn(async move |this, cx| {
6352 let mut tasks = Vec::with_capacity(server_ids.len());
6353 this.update(cx, |lsp_store, cx| {
6354 for server_id in server_ids {
6355 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6356 let lsp_timeout = lsp_timeout
6357 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6358 let mut timeout = cx.background_spawn(async move {
6359 match lsp_timeout {
6360 Some(lsp_timeout) => {
6361 lsp_timeout.await;
6362 true
6363 },
6364 None => false,
6365 }
6366 }).fuse();
6367 let mut lsp_request = lsp_store.request_lsp(
6368 buffer.clone(),
6369 LanguageServerToQuery::Other(server_id),
6370 GetCompletions {
6371 position,
6372 context: context.clone(),
6373 server_id: Some(server_id),
6374 },
6375 cx,
6376 ).fuse();
6377 let new_task = cx.background_spawn(async move {
6378 select_biased! {
6379 response = lsp_request => anyhow::Ok(Some(response?)),
6380 timeout_happened = timeout => {
6381 if timeout_happened {
6382 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6383 Ok(None)
6384 } else {
6385 let completions = lsp_request.await?;
6386 Ok(Some(completions))
6387 }
6388 },
6389 }
6390 });
6391 tasks.push((lsp_adapter, new_task));
6392 }
6393 })?;
6394
6395 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6396 let completion_response = task.await.ok()??;
6397 let completions = populate_labels_for_completions(
6398 completion_response.completions,
6399 language.clone(),
6400 lsp_adapter,
6401 )
6402 .await;
6403 Some(CompletionResponse {
6404 completions,
6405 display_options: CompletionDisplayOptions::default(),
6406 is_incomplete: completion_response.is_incomplete,
6407 })
6408 });
6409
6410 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6411
6412 Ok(responses.into_iter().flatten().collect())
6413 })
6414 } else {
6415 Task::ready(Err(anyhow!("No upstream client or local language server")))
6416 }
6417 }
6418
6419 pub fn resolve_completions(
6420 &self,
6421 buffer: Entity<Buffer>,
6422 completion_indices: Vec<usize>,
6423 completions: Rc<RefCell<Box<[Completion]>>>,
6424 cx: &mut Context<Self>,
6425 ) -> Task<Result<bool>> {
6426 let client = self.upstream_client();
6427 let buffer_id = buffer.read(cx).remote_id();
6428 let buffer_snapshot = buffer.read(cx).snapshot();
6429
6430 if !self.check_if_capable_for_proto_request(
6431 &buffer,
6432 GetCompletions::can_resolve_completions,
6433 cx,
6434 ) {
6435 return Task::ready(Ok(false));
6436 }
6437 cx.spawn(async move |lsp_store, cx| {
6438 let request_timeout = cx.update(|app| {
6439 ProjectSettings::get_global(app)
6440 .global_lsp_settings
6441 .get_request_timeout()
6442 });
6443
6444 let mut did_resolve = false;
6445 if let Some((client, project_id)) = client {
6446 for completion_index in completion_indices {
6447 let server_id = {
6448 let completion = &completions.borrow()[completion_index];
6449 completion.source.server_id()
6450 };
6451 if let Some(server_id) = server_id {
6452 if Self::resolve_completion_remote(
6453 project_id,
6454 server_id,
6455 buffer_id,
6456 completions.clone(),
6457 completion_index,
6458 client.clone(),
6459 )
6460 .await
6461 .log_err()
6462 .is_some()
6463 {
6464 did_resolve = true;
6465 }
6466 } else {
6467 resolve_word_completion(
6468 &buffer_snapshot,
6469 &mut completions.borrow_mut()[completion_index],
6470 );
6471 }
6472 }
6473 } else {
6474 for completion_index in completion_indices {
6475 let server_id = {
6476 let completion = &completions.borrow()[completion_index];
6477 completion.source.server_id()
6478 };
6479 if let Some(server_id) = server_id {
6480 let server_and_adapter = lsp_store
6481 .read_with(cx, |lsp_store, _| {
6482 let server = lsp_store.language_server_for_id(server_id)?;
6483 let adapter =
6484 lsp_store.language_server_adapter_for_id(server.server_id())?;
6485 Some((server, adapter))
6486 })
6487 .ok()
6488 .flatten();
6489 let Some((server, adapter)) = server_and_adapter else {
6490 continue;
6491 };
6492
6493 let resolved = Self::resolve_completion_local(
6494 server,
6495 completions.clone(),
6496 completion_index,
6497 request_timeout,
6498 )
6499 .await
6500 .log_err()
6501 .is_some();
6502 if resolved {
6503 Self::regenerate_completion_labels(
6504 adapter,
6505 &buffer_snapshot,
6506 completions.clone(),
6507 completion_index,
6508 )
6509 .await
6510 .log_err();
6511 did_resolve = true;
6512 }
6513 } else {
6514 resolve_word_completion(
6515 &buffer_snapshot,
6516 &mut completions.borrow_mut()[completion_index],
6517 );
6518 }
6519 }
6520 }
6521
6522 Ok(did_resolve)
6523 })
6524 }
6525
6526 async fn resolve_completion_local(
6527 server: Arc<lsp::LanguageServer>,
6528 completions: Rc<RefCell<Box<[Completion]>>>,
6529 completion_index: usize,
6530 request_timeout: Duration,
6531 ) -> Result<()> {
6532 let server_id = server.server_id();
6533 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6534 return Ok(());
6535 }
6536
6537 let request = {
6538 let completion = &completions.borrow()[completion_index];
6539 match &completion.source {
6540 CompletionSource::Lsp {
6541 lsp_completion,
6542 resolved,
6543 server_id: completion_server_id,
6544 ..
6545 } => {
6546 if *resolved {
6547 return Ok(());
6548 }
6549 anyhow::ensure!(
6550 server_id == *completion_server_id,
6551 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6552 );
6553 server.request::<lsp::request::ResolveCompletionItem>(
6554 *lsp_completion.clone(),
6555 request_timeout,
6556 )
6557 }
6558 CompletionSource::BufferWord { .. }
6559 | CompletionSource::Dap { .. }
6560 | CompletionSource::Custom => {
6561 return Ok(());
6562 }
6563 }
6564 };
6565 let resolved_completion = request
6566 .await
6567 .into_response()
6568 .context("resolve completion")?;
6569
6570 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6571 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6572
6573 let mut completions = completions.borrow_mut();
6574 let completion = &mut completions[completion_index];
6575 if let CompletionSource::Lsp {
6576 lsp_completion,
6577 resolved,
6578 server_id: completion_server_id,
6579 ..
6580 } = &mut completion.source
6581 {
6582 if *resolved {
6583 return Ok(());
6584 }
6585 anyhow::ensure!(
6586 server_id == *completion_server_id,
6587 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6588 );
6589 **lsp_completion = resolved_completion;
6590 *resolved = true;
6591 }
6592 Ok(())
6593 }
6594
6595 async fn regenerate_completion_labels(
6596 adapter: Arc<CachedLspAdapter>,
6597 snapshot: &BufferSnapshot,
6598 completions: Rc<RefCell<Box<[Completion]>>>,
6599 completion_index: usize,
6600 ) -> Result<()> {
6601 let completion_item = completions.borrow()[completion_index]
6602 .source
6603 .lsp_completion(true)
6604 .map(Cow::into_owned);
6605 if let Some(lsp_documentation) = completion_item
6606 .as_ref()
6607 .and_then(|completion_item| completion_item.documentation.clone())
6608 {
6609 let mut completions = completions.borrow_mut();
6610 let completion = &mut completions[completion_index];
6611 completion.documentation = Some(lsp_documentation.into());
6612 } else {
6613 let mut completions = completions.borrow_mut();
6614 let completion = &mut completions[completion_index];
6615 completion.documentation = Some(CompletionDocumentation::Undocumented);
6616 }
6617
6618 let mut new_label = match completion_item {
6619 Some(completion_item) => {
6620 // Some language servers always return `detail` lazily via resolve, regardless of
6621 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6622 // See: https://github.com/yioneko/vtsls/issues/213
6623 let language = snapshot.language();
6624 match language {
6625 Some(language) => {
6626 adapter
6627 .labels_for_completions(
6628 std::slice::from_ref(&completion_item),
6629 language,
6630 )
6631 .await?
6632 }
6633 None => Vec::new(),
6634 }
6635 .pop()
6636 .flatten()
6637 .unwrap_or_else(|| {
6638 CodeLabel::fallback_for_completion(
6639 &completion_item,
6640 language.map(|language| language.as_ref()),
6641 )
6642 })
6643 }
6644 None => CodeLabel::plain(
6645 completions.borrow()[completion_index].new_text.clone(),
6646 None,
6647 ),
6648 };
6649 ensure_uniform_list_compatible_label(&mut new_label);
6650
6651 let mut completions = completions.borrow_mut();
6652 let completion = &mut completions[completion_index];
6653 if completion.label.filter_text() == new_label.filter_text() {
6654 completion.label = new_label;
6655 } else {
6656 log::error!(
6657 "Resolved completion changed display label from {} to {}. \
6658 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6659 completion.label.text(),
6660 new_label.text(),
6661 completion.label.filter_text(),
6662 new_label.filter_text()
6663 );
6664 }
6665
6666 Ok(())
6667 }
6668
6669 async fn resolve_completion_remote(
6670 project_id: u64,
6671 server_id: LanguageServerId,
6672 buffer_id: BufferId,
6673 completions: Rc<RefCell<Box<[Completion]>>>,
6674 completion_index: usize,
6675 client: AnyProtoClient,
6676 ) -> Result<()> {
6677 let lsp_completion = {
6678 let completion = &completions.borrow()[completion_index];
6679 match &completion.source {
6680 CompletionSource::Lsp {
6681 lsp_completion,
6682 resolved,
6683 server_id: completion_server_id,
6684 ..
6685 } => {
6686 anyhow::ensure!(
6687 server_id == *completion_server_id,
6688 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6689 );
6690 if *resolved {
6691 return Ok(());
6692 }
6693 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6694 }
6695 CompletionSource::Custom
6696 | CompletionSource::Dap { .. }
6697 | CompletionSource::BufferWord { .. } => {
6698 return Ok(());
6699 }
6700 }
6701 };
6702 let request = proto::ResolveCompletionDocumentation {
6703 project_id,
6704 language_server_id: server_id.0 as u64,
6705 lsp_completion,
6706 buffer_id: buffer_id.into(),
6707 };
6708
6709 let response = client
6710 .request(request)
6711 .await
6712 .context("completion documentation resolve proto request")?;
6713 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6714
6715 let documentation = if response.documentation.is_empty() {
6716 CompletionDocumentation::Undocumented
6717 } else if response.documentation_is_markdown {
6718 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6719 } else if response.documentation.lines().count() <= 1 {
6720 CompletionDocumentation::SingleLine(response.documentation.into())
6721 } else {
6722 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6723 };
6724
6725 let mut completions = completions.borrow_mut();
6726 let completion = &mut completions[completion_index];
6727 completion.documentation = Some(documentation);
6728 if let CompletionSource::Lsp {
6729 insert_range,
6730 lsp_completion,
6731 resolved,
6732 server_id: completion_server_id,
6733 lsp_defaults: _,
6734 } = &mut completion.source
6735 {
6736 let completion_insert_range = response
6737 .old_insert_start
6738 .and_then(deserialize_anchor)
6739 .zip(response.old_insert_end.and_then(deserialize_anchor));
6740 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6741
6742 if *resolved {
6743 return Ok(());
6744 }
6745 anyhow::ensure!(
6746 server_id == *completion_server_id,
6747 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6748 );
6749 **lsp_completion = resolved_lsp_completion;
6750 *resolved = true;
6751 }
6752
6753 let replace_range = response
6754 .old_replace_start
6755 .and_then(deserialize_anchor)
6756 .zip(response.old_replace_end.and_then(deserialize_anchor));
6757 if let Some((old_replace_start, old_replace_end)) = replace_range
6758 && !response.new_text.is_empty()
6759 {
6760 completion.new_text = response.new_text;
6761 completion.replace_range = old_replace_start..old_replace_end;
6762 }
6763
6764 Ok(())
6765 }
6766
6767 pub fn apply_additional_edits_for_completion(
6768 &self,
6769 buffer_handle: Entity<Buffer>,
6770 completions: Rc<RefCell<Box<[Completion]>>>,
6771 completion_index: usize,
6772 push_to_history: bool,
6773 all_commit_ranges: Vec<Range<language::Anchor>>,
6774 cx: &mut Context<Self>,
6775 ) -> Task<Result<Option<Transaction>>> {
6776 if let Some((client, project_id)) = self.upstream_client() {
6777 let buffer = buffer_handle.read(cx);
6778 let buffer_id = buffer.remote_id();
6779 cx.spawn(async move |_, cx| {
6780 let request = {
6781 let completion = completions.borrow()[completion_index].clone();
6782 proto::ApplyCompletionAdditionalEdits {
6783 project_id,
6784 buffer_id: buffer_id.into(),
6785 completion: Some(Self::serialize_completion(&CoreCompletion {
6786 replace_range: completion.replace_range,
6787 new_text: completion.new_text,
6788 source: completion.source,
6789 })),
6790 all_commit_ranges: all_commit_ranges
6791 .iter()
6792 .cloned()
6793 .map(language::proto::serialize_anchor_range)
6794 .collect(),
6795 }
6796 };
6797
6798 let Some(transaction) = client.request(request).await?.transaction else {
6799 return Ok(None);
6800 };
6801
6802 let transaction = language::proto::deserialize_transaction(transaction)?;
6803 buffer_handle
6804 .update(cx, |buffer, _| {
6805 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6806 })
6807 .await?;
6808 if push_to_history {
6809 buffer_handle.update(cx, |buffer, _| {
6810 buffer.push_transaction(transaction.clone(), Instant::now());
6811 buffer.finalize_last_transaction();
6812 });
6813 }
6814 Ok(Some(transaction))
6815 })
6816 } else {
6817 let request_timeout = ProjectSettings::get_global(cx)
6818 .global_lsp_settings
6819 .get_request_timeout();
6820
6821 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6822 let completion = &completions.borrow()[completion_index];
6823 let server_id = completion.source.server_id()?;
6824 Some(
6825 self.language_server_for_local_buffer(buffer, server_id, cx)?
6826 .1
6827 .clone(),
6828 )
6829 }) else {
6830 return Task::ready(Ok(None));
6831 };
6832
6833 cx.spawn(async move |this, cx| {
6834 Self::resolve_completion_local(
6835 server.clone(),
6836 completions.clone(),
6837 completion_index,
6838 request_timeout,
6839 )
6840 .await
6841 .context("resolving completion")?;
6842 let completion = completions.borrow()[completion_index].clone();
6843 let additional_text_edits = completion
6844 .source
6845 .lsp_completion(true)
6846 .as_ref()
6847 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6848 if let Some(edits) = additional_text_edits {
6849 let edits = this
6850 .update(cx, |this, cx| {
6851 this.as_local_mut().unwrap().edits_from_lsp(
6852 &buffer_handle,
6853 edits,
6854 server.server_id(),
6855 None,
6856 cx,
6857 )
6858 })?
6859 .await?;
6860
6861 buffer_handle.update(cx, |buffer, cx| {
6862 buffer.finalize_last_transaction();
6863 buffer.start_transaction();
6864
6865 for (range, text) in edits {
6866 let primary = &completion.replace_range;
6867
6868 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6869 // and the primary completion is just an insertion (empty range), then this is likely
6870 // an auto-import scenario and should not be considered overlapping
6871 // https://github.com/zed-industries/zed/issues/26136
6872 let is_file_start_auto_import = {
6873 let snapshot = buffer.snapshot();
6874 let primary_start_point = primary.start.to_point(&snapshot);
6875 let range_start_point = range.start.to_point(&snapshot);
6876
6877 let result = primary_start_point.row == 0
6878 && primary_start_point.column == 0
6879 && range_start_point.row == 0
6880 && range_start_point.column == 0;
6881
6882 result
6883 };
6884
6885 let has_overlap = if is_file_start_auto_import {
6886 false
6887 } else {
6888 all_commit_ranges.iter().any(|commit_range| {
6889 let start_within =
6890 commit_range.start.cmp(&range.start, buffer).is_le()
6891 && commit_range.end.cmp(&range.start, buffer).is_ge();
6892 let end_within =
6893 range.start.cmp(&commit_range.end, buffer).is_le()
6894 && range.end.cmp(&commit_range.end, buffer).is_ge();
6895 start_within || end_within
6896 })
6897 };
6898
6899 //Skip additional edits which overlap with the primary completion edit
6900 //https://github.com/zed-industries/zed/pull/1871
6901 if !has_overlap {
6902 buffer.edit([(range, text)], None, cx);
6903 }
6904 }
6905
6906 let transaction = if buffer.end_transaction(cx).is_some() {
6907 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6908 if !push_to_history {
6909 buffer.forget_transaction(transaction.id);
6910 }
6911 Some(transaction)
6912 } else {
6913 None
6914 };
6915 Ok(transaction)
6916 })
6917 } else {
6918 Ok(None)
6919 }
6920 })
6921 }
6922 }
6923
6924 pub fn pull_diagnostics(
6925 &mut self,
6926 buffer: Entity<Buffer>,
6927 cx: &mut Context<Self>,
6928 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6929 let buffer_id = buffer.read(cx).remote_id();
6930
6931 if let Some((client, upstream_project_id)) = self.upstream_client() {
6932 let mut suitable_capabilities = None;
6933 // Are we capable for proto request?
6934 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6935 &buffer,
6936 |capabilities| {
6937 if let Some(caps) = &capabilities.diagnostic_provider {
6938 suitable_capabilities = Some(caps.clone());
6939 true
6940 } else {
6941 false
6942 }
6943 },
6944 cx,
6945 );
6946 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6947 let Some(dynamic_caps) = suitable_capabilities else {
6948 return Task::ready(Ok(None));
6949 };
6950 assert!(any_server_has_diagnostics_provider);
6951
6952 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6953 let request = GetDocumentDiagnostics {
6954 previous_result_id: None,
6955 identifier,
6956 registration_id: None,
6957 };
6958 let request_timeout = ProjectSettings::get_global(cx)
6959 .global_lsp_settings
6960 .get_request_timeout();
6961 let request_task = client.request_lsp(
6962 upstream_project_id,
6963 None,
6964 request_timeout,
6965 cx.background_executor().clone(),
6966 request.to_proto(upstream_project_id, buffer.read(cx)),
6967 );
6968 cx.background_spawn(async move {
6969 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6970 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6971 // Do not attempt to further process the dummy responses here.
6972 let _response = request_task.await?;
6973 Ok(None)
6974 })
6975 } else {
6976 let servers = buffer.update(cx, |buffer, cx| {
6977 self.running_language_servers_for_local_buffer(buffer, cx)
6978 .map(|(_, server)| server.clone())
6979 .collect::<Vec<_>>()
6980 });
6981
6982 let pull_diagnostics = servers
6983 .into_iter()
6984 .flat_map(|server| {
6985 let result = maybe!({
6986 let local = self.as_local()?;
6987 let server_id = server.server_id();
6988 let providers_with_identifiers = local
6989 .language_server_dynamic_registrations
6990 .get(&server_id)
6991 .into_iter()
6992 .flat_map(|registrations| registrations.diagnostics.clone())
6993 .collect::<Vec<_>>();
6994 Some(
6995 providers_with_identifiers
6996 .into_iter()
6997 .map(|(registration_id, dynamic_caps)| {
6998 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6999 let registration_id = registration_id.map(SharedString::from);
7000 let result_id = self.result_id_for_buffer_pull(
7001 server_id,
7002 buffer_id,
7003 ®istration_id,
7004 cx,
7005 );
7006 self.request_lsp(
7007 buffer.clone(),
7008 LanguageServerToQuery::Other(server_id),
7009 GetDocumentDiagnostics {
7010 previous_result_id: result_id,
7011 registration_id,
7012 identifier,
7013 },
7014 cx,
7015 )
7016 })
7017 .collect::<Vec<_>>(),
7018 )
7019 });
7020
7021 result.unwrap_or_default()
7022 })
7023 .collect::<Vec<_>>();
7024
7025 cx.background_spawn(async move {
7026 let mut responses = Vec::new();
7027 for diagnostics in join_all(pull_diagnostics).await {
7028 responses.extend(diagnostics?);
7029 }
7030 Ok(Some(responses))
7031 })
7032 }
7033 }
7034
7035 pub fn applicable_inlay_chunks(
7036 &mut self,
7037 buffer: &Entity<Buffer>,
7038 ranges: &[Range<text::Anchor>],
7039 cx: &mut Context<Self>,
7040 ) -> Vec<Range<BufferRow>> {
7041 let buffer_snapshot = buffer.read(cx).snapshot();
7042 let ranges = ranges
7043 .iter()
7044 .map(|range| range.to_point(&buffer_snapshot))
7045 .collect::<Vec<_>>();
7046
7047 self.latest_lsp_data(buffer, cx)
7048 .inlay_hints
7049 .applicable_chunks(ranges.as_slice())
7050 .map(|chunk| chunk.row_range())
7051 .collect()
7052 }
7053
7054 pub fn invalidate_inlay_hints<'a>(
7055 &'a mut self,
7056 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7057 ) {
7058 for buffer_id in for_buffers {
7059 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7060 lsp_data.inlay_hints.clear();
7061 }
7062 }
7063 }
7064
7065 pub fn inlay_hints(
7066 &mut self,
7067 invalidate: InvalidationStrategy,
7068 buffer: Entity<Buffer>,
7069 ranges: Vec<Range<text::Anchor>>,
7070 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7071 cx: &mut Context<Self>,
7072 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7073 let next_hint_id = self.next_hint_id.clone();
7074 let lsp_data = self.latest_lsp_data(&buffer, cx);
7075 let query_version = lsp_data.buffer_version.clone();
7076 let mut lsp_refresh_requested = false;
7077 let for_server = if let InvalidationStrategy::RefreshRequested {
7078 server_id,
7079 request_id,
7080 } = invalidate
7081 {
7082 let invalidated = lsp_data
7083 .inlay_hints
7084 .invalidate_for_server_refresh(server_id, request_id);
7085 lsp_refresh_requested = invalidated;
7086 Some(server_id)
7087 } else {
7088 None
7089 };
7090 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7091 let known_chunks = known_chunks
7092 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7093 .map(|(_, known_chunks)| known_chunks)
7094 .unwrap_or_default();
7095
7096 let buffer_snapshot = buffer.read(cx).snapshot();
7097 let ranges = ranges
7098 .iter()
7099 .map(|range| range.to_point(&buffer_snapshot))
7100 .collect::<Vec<_>>();
7101
7102 let mut hint_fetch_tasks = Vec::new();
7103 let mut cached_inlay_hints = None;
7104 let mut ranges_to_query = None;
7105 let applicable_chunks = existing_inlay_hints
7106 .applicable_chunks(ranges.as_slice())
7107 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7108 .collect::<Vec<_>>();
7109 if applicable_chunks.is_empty() {
7110 return HashMap::default();
7111 }
7112
7113 for row_chunk in applicable_chunks {
7114 match (
7115 existing_inlay_hints
7116 .cached_hints(&row_chunk)
7117 .filter(|_| !lsp_refresh_requested)
7118 .cloned(),
7119 existing_inlay_hints
7120 .fetched_hints(&row_chunk)
7121 .as_ref()
7122 .filter(|_| !lsp_refresh_requested)
7123 .cloned(),
7124 ) {
7125 (None, None) => {
7126 let chunk_range = row_chunk.anchor_range();
7127 ranges_to_query
7128 .get_or_insert_with(Vec::new)
7129 .push((row_chunk, chunk_range));
7130 }
7131 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7132 (Some(cached_hints), None) => {
7133 for (server_id, cached_hints) in cached_hints {
7134 if for_server.is_none_or(|for_server| for_server == server_id) {
7135 cached_inlay_hints
7136 .get_or_insert_with(HashMap::default)
7137 .entry(row_chunk.row_range())
7138 .or_insert_with(HashMap::default)
7139 .entry(server_id)
7140 .or_insert_with(Vec::new)
7141 .extend(cached_hints);
7142 }
7143 }
7144 }
7145 (Some(cached_hints), Some(fetched_hints)) => {
7146 hint_fetch_tasks.push((row_chunk, fetched_hints));
7147 for (server_id, cached_hints) in cached_hints {
7148 if for_server.is_none_or(|for_server| for_server == server_id) {
7149 cached_inlay_hints
7150 .get_or_insert_with(HashMap::default)
7151 .entry(row_chunk.row_range())
7152 .or_insert_with(HashMap::default)
7153 .entry(server_id)
7154 .or_insert_with(Vec::new)
7155 .extend(cached_hints);
7156 }
7157 }
7158 }
7159 }
7160 }
7161
7162 if hint_fetch_tasks.is_empty()
7163 && ranges_to_query
7164 .as_ref()
7165 .is_none_or(|ranges| ranges.is_empty())
7166 && let Some(cached_inlay_hints) = cached_inlay_hints
7167 {
7168 cached_inlay_hints
7169 .into_iter()
7170 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7171 .collect()
7172 } else {
7173 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7174 // When a server refresh was requested, other servers' cached hints
7175 // are unaffected by the refresh and must be included in the result.
7176 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7177 // removes all visible hints but only adds back the requesting
7178 // server's new hints, permanently losing other servers' hints.
7179 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7180 lsp_data
7181 .inlay_hints
7182 .cached_hints(&chunk)
7183 .cloned()
7184 .unwrap_or_default()
7185 } else {
7186 HashMap::default()
7187 };
7188
7189 let next_hint_id = next_hint_id.clone();
7190 let buffer = buffer.clone();
7191 let query_version = query_version.clone();
7192 let new_inlay_hints = cx
7193 .spawn(async move |lsp_store, cx| {
7194 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7195 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7196 })?;
7197 new_fetch_task
7198 .await
7199 .and_then(|new_hints_by_server| {
7200 lsp_store.update(cx, |lsp_store, cx| {
7201 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7202 let update_cache = lsp_data.buffer_version == query_version;
7203 if new_hints_by_server.is_empty() {
7204 if update_cache {
7205 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7206 }
7207 other_servers_cached
7208 } else {
7209 let mut result = other_servers_cached;
7210 for (server_id, new_hints) in new_hints_by_server {
7211 let new_hints = new_hints
7212 .into_iter()
7213 .map(|new_hint| {
7214 (
7215 InlayId::Hint(next_hint_id.fetch_add(
7216 1,
7217 atomic::Ordering::AcqRel,
7218 )),
7219 new_hint,
7220 )
7221 })
7222 .collect::<Vec<_>>();
7223 if update_cache {
7224 lsp_data.inlay_hints.insert_new_hints(
7225 chunk,
7226 server_id,
7227 new_hints.clone(),
7228 );
7229 }
7230 result.insert(server_id, new_hints);
7231 }
7232 result
7233 }
7234 })
7235 })
7236 .map_err(Arc::new)
7237 })
7238 .shared();
7239
7240 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7241 *fetch_task = Some(new_inlay_hints.clone());
7242 hint_fetch_tasks.push((chunk, new_inlay_hints));
7243 }
7244
7245 cached_inlay_hints
7246 .unwrap_or_default()
7247 .into_iter()
7248 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7249 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7250 (
7251 chunk.row_range(),
7252 cx.spawn(async move |_, _| {
7253 hints_fetch.await.map_err(|e| {
7254 if e.error_code() != ErrorCode::Internal {
7255 anyhow!(e.error_code())
7256 } else {
7257 anyhow!("{e:#}")
7258 }
7259 })
7260 }),
7261 )
7262 }))
7263 .collect()
7264 }
7265 }
7266
7267 fn fetch_inlay_hints(
7268 &mut self,
7269 for_server: Option<LanguageServerId>,
7270 buffer: &Entity<Buffer>,
7271 range: Range<Anchor>,
7272 cx: &mut Context<Self>,
7273 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7274 let request = InlayHints {
7275 range: range.clone(),
7276 };
7277 if let Some((upstream_client, project_id)) = self.upstream_client() {
7278 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7279 return Task::ready(Ok(HashMap::default()));
7280 }
7281 let request_timeout = ProjectSettings::get_global(cx)
7282 .global_lsp_settings
7283 .get_request_timeout();
7284 let request_task = upstream_client.request_lsp(
7285 project_id,
7286 for_server.map(|id| id.to_proto()),
7287 request_timeout,
7288 cx.background_executor().clone(),
7289 request.to_proto(project_id, buffer.read(cx)),
7290 );
7291 let buffer = buffer.clone();
7292 cx.spawn(async move |weak_lsp_store, cx| {
7293 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7294 return Ok(HashMap::default());
7295 };
7296 let Some(responses) = request_task.await? else {
7297 return Ok(HashMap::default());
7298 };
7299
7300 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7301 let lsp_store = lsp_store.clone();
7302 let buffer = buffer.clone();
7303 let cx = cx.clone();
7304 let request = request.clone();
7305 async move {
7306 (
7307 LanguageServerId::from_proto(response.server_id),
7308 request
7309 .response_from_proto(response.response, lsp_store, buffer, cx)
7310 .await,
7311 )
7312 }
7313 }))
7314 .await;
7315
7316 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7317 let mut has_errors = false;
7318 let inlay_hints = inlay_hints
7319 .into_iter()
7320 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7321 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7322 Err(e) => {
7323 has_errors = true;
7324 log::error!("{e:#}");
7325 None
7326 }
7327 })
7328 .map(|(server_id, mut new_hints)| {
7329 new_hints.retain(|hint| {
7330 hint.position.is_valid(&buffer_snapshot)
7331 && range.start.is_valid(&buffer_snapshot)
7332 && range.end.is_valid(&buffer_snapshot)
7333 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7334 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7335 });
7336 (server_id, new_hints)
7337 })
7338 .collect::<HashMap<_, _>>();
7339 anyhow::ensure!(
7340 !has_errors || !inlay_hints.is_empty(),
7341 "Failed to fetch inlay hints"
7342 );
7343 Ok(inlay_hints)
7344 })
7345 } else {
7346 let inlay_hints_task = match for_server {
7347 Some(server_id) => {
7348 let server_task = self.request_lsp(
7349 buffer.clone(),
7350 LanguageServerToQuery::Other(server_id),
7351 request,
7352 cx,
7353 );
7354 cx.background_spawn(async move {
7355 let mut responses = Vec::new();
7356 match server_task.await {
7357 Ok(response) => responses.push((server_id, response)),
7358 // rust-analyzer likes to error with this when its still loading up
7359 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7360 Err(e) => log::error!(
7361 "Error handling response for inlay hints request: {e:#}"
7362 ),
7363 }
7364 responses
7365 })
7366 }
7367 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7368 };
7369 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7370 cx.background_spawn(async move {
7371 Ok(inlay_hints_task
7372 .await
7373 .into_iter()
7374 .map(|(server_id, mut new_hints)| {
7375 new_hints.retain(|hint| {
7376 hint.position.is_valid(&buffer_snapshot)
7377 && range.start.is_valid(&buffer_snapshot)
7378 && range.end.is_valid(&buffer_snapshot)
7379 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7380 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7381 });
7382 (server_id, new_hints)
7383 })
7384 .collect())
7385 })
7386 }
7387 }
7388
7389 fn diagnostic_registration_exists(
7390 &self,
7391 server_id: LanguageServerId,
7392 registration_id: &Option<SharedString>,
7393 ) -> bool {
7394 let Some(local) = self.as_local() else {
7395 return false;
7396 };
7397 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7398 else {
7399 return false;
7400 };
7401 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7402 registrations.diagnostics.contains_key(®istration_key)
7403 }
7404
7405 pub fn pull_diagnostics_for_buffer(
7406 &mut self,
7407 buffer: Entity<Buffer>,
7408 cx: &mut Context<Self>,
7409 ) -> Task<anyhow::Result<()>> {
7410 let diagnostics = self.pull_diagnostics(buffer, cx);
7411 cx.spawn(async move |lsp_store, cx| {
7412 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7413 return Ok(());
7414 };
7415 lsp_store.update(cx, |lsp_store, cx| {
7416 if lsp_store.as_local().is_none() {
7417 return;
7418 }
7419
7420 let mut unchanged_buffers = HashMap::default();
7421 let server_diagnostics_updates = diagnostics
7422 .into_iter()
7423 .filter_map(|diagnostics_set| match diagnostics_set {
7424 LspPullDiagnostics::Response {
7425 server_id,
7426 uri,
7427 diagnostics,
7428 registration_id,
7429 } => Some((server_id, uri, diagnostics, registration_id)),
7430 LspPullDiagnostics::Default => None,
7431 })
7432 .filter(|(server_id, _, _, registration_id)| {
7433 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7434 })
7435 .fold(
7436 HashMap::default(),
7437 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7438 let (result_id, diagnostics) = match diagnostics {
7439 PulledDiagnostics::Unchanged { result_id } => {
7440 unchanged_buffers
7441 .entry(new_registration_id.clone())
7442 .or_insert_with(HashSet::default)
7443 .insert(uri.clone());
7444 (Some(result_id), Vec::new())
7445 }
7446 PulledDiagnostics::Changed {
7447 result_id,
7448 diagnostics,
7449 } => (result_id, diagnostics),
7450 };
7451 let disk_based_sources = Cow::Owned(
7452 lsp_store
7453 .language_server_adapter_for_id(server_id)
7454 .as_ref()
7455 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7456 .unwrap_or(&[])
7457 .to_vec(),
7458 );
7459 acc.entry(server_id)
7460 .or_insert_with(HashMap::default)
7461 .entry(new_registration_id.clone())
7462 .or_insert_with(Vec::new)
7463 .push(DocumentDiagnosticsUpdate {
7464 server_id,
7465 diagnostics: lsp::PublishDiagnosticsParams {
7466 uri,
7467 diagnostics,
7468 version: None,
7469 },
7470 result_id: result_id.map(SharedString::new),
7471 disk_based_sources,
7472 registration_id: new_registration_id,
7473 });
7474 acc
7475 },
7476 );
7477
7478 for diagnostic_updates in server_diagnostics_updates.into_values() {
7479 for (registration_id, diagnostic_updates) in diagnostic_updates {
7480 lsp_store
7481 .merge_lsp_diagnostics(
7482 DiagnosticSourceKind::Pulled,
7483 diagnostic_updates,
7484 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7485 DiagnosticSourceKind::Pulled => {
7486 old_diagnostic.registration_id != registration_id
7487 || unchanged_buffers
7488 .get(&old_diagnostic.registration_id)
7489 .is_some_and(|unchanged_buffers| {
7490 unchanged_buffers.contains(&document_uri)
7491 })
7492 }
7493 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7494 true
7495 }
7496 },
7497 cx,
7498 )
7499 .log_err();
7500 }
7501 }
7502 })
7503 })
7504 }
7505
7506 pub fn signature_help<T: ToPointUtf16>(
7507 &mut self,
7508 buffer: &Entity<Buffer>,
7509 position: T,
7510 cx: &mut Context<Self>,
7511 ) -> Task<Option<Vec<SignatureHelp>>> {
7512 let position = position.to_point_utf16(buffer.read(cx));
7513
7514 if let Some((client, upstream_project_id)) = self.upstream_client() {
7515 let request = GetSignatureHelp { position };
7516 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7517 return Task::ready(None);
7518 }
7519 let request_timeout = ProjectSettings::get_global(cx)
7520 .global_lsp_settings
7521 .get_request_timeout();
7522 let request_task = client.request_lsp(
7523 upstream_project_id,
7524 None,
7525 request_timeout,
7526 cx.background_executor().clone(),
7527 request.to_proto(upstream_project_id, buffer.read(cx)),
7528 );
7529 let buffer = buffer.clone();
7530 cx.spawn(async move |weak_lsp_store, cx| {
7531 let lsp_store = weak_lsp_store.upgrade()?;
7532 let signatures = join_all(
7533 request_task
7534 .await
7535 .log_err()
7536 .flatten()
7537 .map(|response| response.payload)
7538 .unwrap_or_default()
7539 .into_iter()
7540 .map(|response| {
7541 let response = GetSignatureHelp { position }.response_from_proto(
7542 response.response,
7543 lsp_store.clone(),
7544 buffer.clone(),
7545 cx.clone(),
7546 );
7547 async move { response.await.log_err().flatten() }
7548 }),
7549 )
7550 .await
7551 .into_iter()
7552 .flatten()
7553 .collect();
7554 Some(signatures)
7555 })
7556 } else {
7557 let all_actions_task = self.request_multiple_lsp_locally(
7558 buffer,
7559 Some(position),
7560 GetSignatureHelp { position },
7561 cx,
7562 );
7563 cx.background_spawn(async move {
7564 Some(
7565 all_actions_task
7566 .await
7567 .into_iter()
7568 .flat_map(|(_, actions)| actions)
7569 .collect::<Vec<_>>(),
7570 )
7571 })
7572 }
7573 }
7574
7575 pub fn hover(
7576 &mut self,
7577 buffer: &Entity<Buffer>,
7578 position: PointUtf16,
7579 cx: &mut Context<Self>,
7580 ) -> Task<Option<Vec<Hover>>> {
7581 if let Some((client, upstream_project_id)) = self.upstream_client() {
7582 let request = GetHover { position };
7583 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7584 return Task::ready(None);
7585 }
7586 let request_timeout = ProjectSettings::get_global(cx)
7587 .global_lsp_settings
7588 .get_request_timeout();
7589 let request_task = client.request_lsp(
7590 upstream_project_id,
7591 None,
7592 request_timeout,
7593 cx.background_executor().clone(),
7594 request.to_proto(upstream_project_id, buffer.read(cx)),
7595 );
7596 let buffer = buffer.clone();
7597 cx.spawn(async move |weak_lsp_store, cx| {
7598 let lsp_store = weak_lsp_store.upgrade()?;
7599 let hovers = join_all(
7600 request_task
7601 .await
7602 .log_err()
7603 .flatten()
7604 .map(|response| response.payload)
7605 .unwrap_or_default()
7606 .into_iter()
7607 .map(|response| {
7608 let response = GetHover { position }.response_from_proto(
7609 response.response,
7610 lsp_store.clone(),
7611 buffer.clone(),
7612 cx.clone(),
7613 );
7614 async move {
7615 response
7616 .await
7617 .log_err()
7618 .flatten()
7619 .and_then(remove_empty_hover_blocks)
7620 }
7621 }),
7622 )
7623 .await
7624 .into_iter()
7625 .flatten()
7626 .collect();
7627 Some(hovers)
7628 })
7629 } else {
7630 let all_actions_task = self.request_multiple_lsp_locally(
7631 buffer,
7632 Some(position),
7633 GetHover { position },
7634 cx,
7635 );
7636 cx.background_spawn(async move {
7637 Some(
7638 all_actions_task
7639 .await
7640 .into_iter()
7641 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7642 .collect::<Vec<Hover>>(),
7643 )
7644 })
7645 }
7646 }
7647
7648 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7649 let language_registry = self.languages.clone();
7650
7651 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7652 let request = upstream_client.request(proto::GetProjectSymbols {
7653 project_id: *project_id,
7654 query: query.to_string(),
7655 });
7656 cx.foreground_executor().spawn(async move {
7657 let response = request.await?;
7658 let mut symbols = Vec::new();
7659 let core_symbols = response
7660 .symbols
7661 .into_iter()
7662 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7663 .collect::<Vec<_>>();
7664 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7665 .await;
7666 Ok(symbols)
7667 })
7668 } else if let Some(local) = self.as_local() {
7669 struct WorkspaceSymbolsResult {
7670 server_id: LanguageServerId,
7671 lsp_adapter: Arc<CachedLspAdapter>,
7672 worktree: WeakEntity<Worktree>,
7673 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7674 }
7675
7676 let mut requests = Vec::new();
7677 let mut requested_servers = BTreeSet::new();
7678 let request_timeout = ProjectSettings::get_global(cx)
7679 .global_lsp_settings
7680 .get_request_timeout();
7681
7682 for (seed, state) in local.language_server_ids.iter() {
7683 let Some(worktree_handle) = self
7684 .worktree_store
7685 .read(cx)
7686 .worktree_for_id(seed.worktree_id, cx)
7687 else {
7688 continue;
7689 };
7690
7691 let worktree = worktree_handle.read(cx);
7692 if !worktree.is_visible() {
7693 continue;
7694 }
7695
7696 if !requested_servers.insert(state.id) {
7697 continue;
7698 }
7699
7700 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7701 Some(LanguageServerState::Running {
7702 adapter, server, ..
7703 }) => (adapter.clone(), server),
7704
7705 _ => continue,
7706 };
7707
7708 let supports_workspace_symbol_request =
7709 match server.capabilities().workspace_symbol_provider {
7710 Some(OneOf::Left(supported)) => supported,
7711 Some(OneOf::Right(_)) => true,
7712 None => false,
7713 };
7714
7715 if !supports_workspace_symbol_request {
7716 continue;
7717 }
7718
7719 let worktree_handle = worktree_handle.clone();
7720 let server_id = server.server_id();
7721 requests.push(
7722 server
7723 .request::<lsp::request::WorkspaceSymbolRequest>(
7724 lsp::WorkspaceSymbolParams {
7725 query: query.to_string(),
7726 ..Default::default()
7727 },
7728 request_timeout,
7729 )
7730 .map(move |response| {
7731 let lsp_symbols = response
7732 .into_response()
7733 .context("workspace symbols request")
7734 .log_err()
7735 .flatten()
7736 .map(|symbol_response| match symbol_response {
7737 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7738 flat_responses
7739 .into_iter()
7740 .map(|lsp_symbol| {
7741 (
7742 lsp_symbol.name,
7743 lsp_symbol.kind,
7744 lsp_symbol.location,
7745 lsp_symbol.container_name,
7746 )
7747 })
7748 .collect::<Vec<_>>()
7749 }
7750 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7751 nested_responses
7752 .into_iter()
7753 .filter_map(|lsp_symbol| {
7754 let location = match lsp_symbol.location {
7755 OneOf::Left(location) => location,
7756 OneOf::Right(_) => {
7757 log::error!(
7758 "Unexpected: client capabilities \
7759 forbid symbol resolutions in \
7760 workspace.symbol.resolveSupport"
7761 );
7762 return None;
7763 }
7764 };
7765 Some((
7766 lsp_symbol.name,
7767 lsp_symbol.kind,
7768 location,
7769 lsp_symbol.container_name,
7770 ))
7771 })
7772 .collect::<Vec<_>>()
7773 }
7774 })
7775 .unwrap_or_default();
7776
7777 WorkspaceSymbolsResult {
7778 server_id,
7779 lsp_adapter,
7780 worktree: worktree_handle.downgrade(),
7781 lsp_symbols,
7782 }
7783 }),
7784 );
7785 }
7786
7787 cx.spawn(async move |this, cx| {
7788 let responses = futures::future::join_all(requests).await;
7789 let this = match this.upgrade() {
7790 Some(this) => this,
7791 None => return Ok(Vec::new()),
7792 };
7793
7794 let mut symbols = Vec::new();
7795 for result in responses {
7796 let core_symbols = this.update(cx, |this, cx| {
7797 result
7798 .lsp_symbols
7799 .into_iter()
7800 .filter_map(
7801 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7802 let abs_path = symbol_location.uri.to_file_path().ok()?;
7803 let source_worktree = result.worktree.upgrade()?;
7804 let source_worktree_id = source_worktree.read(cx).id();
7805
7806 let path = if let Some((tree, rel_path)) =
7807 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7808 {
7809 let worktree_id = tree.read(cx).id();
7810 SymbolLocation::InProject(ProjectPath {
7811 worktree_id,
7812 path: rel_path,
7813 })
7814 } else {
7815 SymbolLocation::OutsideProject {
7816 signature: this.symbol_signature(&abs_path),
7817 abs_path: abs_path.into(),
7818 }
7819 };
7820
7821 Some(CoreSymbol {
7822 source_language_server_id: result.server_id,
7823 language_server_name: result.lsp_adapter.name.clone(),
7824 source_worktree_id,
7825 path,
7826 kind: symbol_kind,
7827 name: collapse_newlines(&symbol_name, "↵ "),
7828 range: range_from_lsp(symbol_location.range),
7829 container_name: container_name
7830 .map(|c| collapse_newlines(&c, "↵ ")),
7831 })
7832 },
7833 )
7834 .collect::<Vec<_>>()
7835 });
7836
7837 populate_labels_for_symbols(
7838 core_symbols,
7839 &language_registry,
7840 Some(result.lsp_adapter),
7841 &mut symbols,
7842 )
7843 .await;
7844 }
7845
7846 Ok(symbols)
7847 })
7848 } else {
7849 Task::ready(Err(anyhow!("No upstream client or local language server")))
7850 }
7851 }
7852
7853 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7854 let mut summary = DiagnosticSummary::default();
7855 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7856 summary.error_count += path_summary.error_count;
7857 summary.warning_count += path_summary.warning_count;
7858 }
7859 summary
7860 }
7861
7862 /// Returns the diagnostic summary for a specific project path.
7863 pub fn diagnostic_summary_for_path(
7864 &self,
7865 project_path: &ProjectPath,
7866 _: &App,
7867 ) -> DiagnosticSummary {
7868 if let Some(summaries) = self
7869 .diagnostic_summaries
7870 .get(&project_path.worktree_id)
7871 .and_then(|map| map.get(&project_path.path))
7872 {
7873 let (error_count, warning_count) = summaries.iter().fold(
7874 (0, 0),
7875 |(error_count, warning_count), (_language_server_id, summary)| {
7876 (
7877 error_count + summary.error_count,
7878 warning_count + summary.warning_count,
7879 )
7880 },
7881 );
7882
7883 DiagnosticSummary {
7884 error_count,
7885 warning_count,
7886 }
7887 } else {
7888 DiagnosticSummary::default()
7889 }
7890 }
7891
7892 pub fn diagnostic_summaries<'a>(
7893 &'a self,
7894 include_ignored: bool,
7895 cx: &'a App,
7896 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7897 self.worktree_store
7898 .read(cx)
7899 .visible_worktrees(cx)
7900 .filter_map(|worktree| {
7901 let worktree = worktree.read(cx);
7902 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7903 })
7904 .flat_map(move |(worktree, summaries)| {
7905 let worktree_id = worktree.id();
7906 summaries
7907 .iter()
7908 .filter(move |(path, _)| {
7909 include_ignored
7910 || worktree
7911 .entry_for_path(path.as_ref())
7912 .is_some_and(|entry| !entry.is_ignored)
7913 })
7914 .flat_map(move |(path, summaries)| {
7915 summaries.iter().map(move |(server_id, summary)| {
7916 (
7917 ProjectPath {
7918 worktree_id,
7919 path: path.clone(),
7920 },
7921 *server_id,
7922 *summary,
7923 )
7924 })
7925 })
7926 })
7927 }
7928
7929 pub fn on_buffer_edited(
7930 &mut self,
7931 buffer: Entity<Buffer>,
7932 cx: &mut Context<Self>,
7933 ) -> Option<()> {
7934 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7935 Some(
7936 self.as_local()?
7937 .language_servers_for_buffer(buffer, cx)
7938 .map(|i| i.1.clone())
7939 .collect(),
7940 )
7941 })?;
7942
7943 let buffer = buffer.read(cx);
7944 let file = File::from_dyn(buffer.file())?;
7945 let abs_path = file.as_local()?.abs_path(cx);
7946 let uri = lsp::Uri::from_file_path(&abs_path)
7947 .ok()
7948 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7949 .log_err()?;
7950 let next_snapshot = buffer.text_snapshot();
7951 for language_server in language_servers {
7952 let language_server = language_server.clone();
7953
7954 let buffer_snapshots = self
7955 .as_local_mut()?
7956 .buffer_snapshots
7957 .get_mut(&buffer.remote_id())
7958 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7959 let previous_snapshot = buffer_snapshots.last()?;
7960
7961 let build_incremental_change = || {
7962 buffer
7963 .edits_since::<Dimensions<PointUtf16, usize>>(
7964 previous_snapshot.snapshot.version(),
7965 )
7966 .map(|edit| {
7967 let edit_start = edit.new.start.0;
7968 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7969 let new_text = next_snapshot
7970 .text_for_range(edit.new.start.1..edit.new.end.1)
7971 .collect();
7972 lsp::TextDocumentContentChangeEvent {
7973 range: Some(lsp::Range::new(
7974 point_to_lsp(edit_start),
7975 point_to_lsp(edit_end),
7976 )),
7977 range_length: None,
7978 text: new_text,
7979 }
7980 })
7981 .collect()
7982 };
7983
7984 let document_sync_kind = language_server
7985 .capabilities()
7986 .text_document_sync
7987 .as_ref()
7988 .and_then(|sync| match sync {
7989 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7990 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7991 });
7992
7993 let content_changes: Vec<_> = match document_sync_kind {
7994 Some(lsp::TextDocumentSyncKind::FULL) => {
7995 vec![lsp::TextDocumentContentChangeEvent {
7996 range: None,
7997 range_length: None,
7998 text: next_snapshot.text(),
7999 }]
8000 }
8001 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8002 _ => {
8003 #[cfg(any(test, feature = "test-support"))]
8004 {
8005 build_incremental_change()
8006 }
8007
8008 #[cfg(not(any(test, feature = "test-support")))]
8009 {
8010 continue;
8011 }
8012 }
8013 };
8014
8015 let next_version = previous_snapshot.version + 1;
8016 buffer_snapshots.push(LspBufferSnapshot {
8017 version: next_version,
8018 snapshot: next_snapshot.clone(),
8019 });
8020
8021 language_server
8022 .notify::<lsp::notification::DidChangeTextDocument>(
8023 lsp::DidChangeTextDocumentParams {
8024 text_document: lsp::VersionedTextDocumentIdentifier::new(
8025 uri.clone(),
8026 next_version,
8027 ),
8028 content_changes,
8029 },
8030 )
8031 .ok();
8032 self.pull_workspace_diagnostics(language_server.server_id());
8033 }
8034
8035 None
8036 }
8037
8038 pub fn on_buffer_saved(
8039 &mut self,
8040 buffer: Entity<Buffer>,
8041 cx: &mut Context<Self>,
8042 ) -> Option<()> {
8043 let file = File::from_dyn(buffer.read(cx).file())?;
8044 let worktree_id = file.worktree_id(cx);
8045 let abs_path = file.as_local()?.abs_path(cx);
8046 let text_document = lsp::TextDocumentIdentifier {
8047 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8048 };
8049 let local = self.as_local()?;
8050
8051 for server in local.language_servers_for_worktree(worktree_id) {
8052 if let Some(include_text) = include_text(server.as_ref()) {
8053 let text = if include_text {
8054 Some(buffer.read(cx).text())
8055 } else {
8056 None
8057 };
8058 server
8059 .notify::<lsp::notification::DidSaveTextDocument>(
8060 lsp::DidSaveTextDocumentParams {
8061 text_document: text_document.clone(),
8062 text,
8063 },
8064 )
8065 .ok();
8066 }
8067 }
8068
8069 let language_servers = buffer.update(cx, |buffer, cx| {
8070 local.language_server_ids_for_buffer(buffer, cx)
8071 });
8072 for language_server_id in language_servers {
8073 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8074 }
8075
8076 None
8077 }
8078
8079 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8080 maybe!(async move {
8081 let mut refreshed_servers = HashSet::default();
8082 let servers = lsp_store
8083 .update(cx, |lsp_store, cx| {
8084 let local = lsp_store.as_local()?;
8085
8086 let servers = local
8087 .language_server_ids
8088 .iter()
8089 .filter_map(|(seed, state)| {
8090 let worktree = lsp_store
8091 .worktree_store
8092 .read(cx)
8093 .worktree_for_id(seed.worktree_id, cx);
8094 let delegate: Arc<dyn LspAdapterDelegate> =
8095 worktree.map(|worktree| {
8096 LocalLspAdapterDelegate::new(
8097 local.languages.clone(),
8098 &local.environment,
8099 cx.weak_entity(),
8100 &worktree,
8101 local.http_client.clone(),
8102 local.fs.clone(),
8103 cx,
8104 )
8105 })?;
8106 let server_id = state.id;
8107
8108 let states = local.language_servers.get(&server_id)?;
8109
8110 match states {
8111 LanguageServerState::Starting { .. } => None,
8112 LanguageServerState::Running {
8113 adapter, server, ..
8114 } => {
8115 let adapter = adapter.clone();
8116 let server = server.clone();
8117 refreshed_servers.insert(server.name());
8118 let toolchain = seed.toolchain.clone();
8119 Some(cx.spawn(async move |_, cx| {
8120 let settings =
8121 LocalLspStore::workspace_configuration_for_adapter(
8122 adapter.adapter.clone(),
8123 &delegate,
8124 toolchain,
8125 None,
8126 cx,
8127 )
8128 .await
8129 .ok()?;
8130 server
8131 .notify::<lsp::notification::DidChangeConfiguration>(
8132 lsp::DidChangeConfigurationParams { settings },
8133 )
8134 .ok()?;
8135 Some(())
8136 }))
8137 }
8138 }
8139 })
8140 .collect::<Vec<_>>();
8141
8142 Some(servers)
8143 })
8144 .ok()
8145 .flatten()?;
8146
8147 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8148 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8149 // to stop and unregister its language server wrapper.
8150 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8151 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8152 let _: Vec<Option<()>> = join_all(servers).await;
8153
8154 Some(())
8155 })
8156 .await;
8157 }
8158
8159 fn maintain_workspace_config(
8160 external_refresh_requests: watch::Receiver<()>,
8161 cx: &mut Context<Self>,
8162 ) -> Task<Result<()>> {
8163 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8164 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8165
8166 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8167 *settings_changed_tx.borrow_mut() = ();
8168 });
8169
8170 let mut joint_future =
8171 futures::stream::select(settings_changed_rx, external_refresh_requests);
8172 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8173 // - 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).
8174 // - 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.
8175 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8176 // - 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,
8177 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8178 cx.spawn(async move |this, cx| {
8179 while let Some(()) = joint_future.next().await {
8180 this.update(cx, |this, cx| {
8181 this.refresh_server_tree(cx);
8182 })
8183 .ok();
8184
8185 Self::refresh_workspace_configurations(&this, cx).await;
8186 }
8187
8188 drop(settings_observation);
8189 anyhow::Ok(())
8190 })
8191 }
8192
8193 pub fn running_language_servers_for_local_buffer<'a>(
8194 &'a self,
8195 buffer: &Buffer,
8196 cx: &mut App,
8197 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8198 let local = self.as_local();
8199 let language_server_ids = local
8200 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8201 .unwrap_or_default();
8202
8203 language_server_ids
8204 .into_iter()
8205 .filter_map(
8206 move |server_id| match local?.language_servers.get(&server_id)? {
8207 LanguageServerState::Running {
8208 adapter, server, ..
8209 } => Some((adapter, server)),
8210 _ => None,
8211 },
8212 )
8213 }
8214
8215 pub fn language_servers_for_local_buffer(
8216 &self,
8217 buffer: &Buffer,
8218 cx: &mut App,
8219 ) -> Vec<LanguageServerId> {
8220 let local = self.as_local();
8221 local
8222 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8223 .unwrap_or_default()
8224 }
8225
8226 pub fn language_server_for_local_buffer<'a>(
8227 &'a self,
8228 buffer: &'a Buffer,
8229 server_id: LanguageServerId,
8230 cx: &'a mut App,
8231 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8232 self.as_local()?
8233 .language_servers_for_buffer(buffer, cx)
8234 .find(|(_, s)| s.server_id() == server_id)
8235 }
8236
8237 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8238 self.diagnostic_summaries.remove(&id_to_remove);
8239 if let Some(local) = self.as_local_mut() {
8240 let to_remove = local.remove_worktree(id_to_remove, cx);
8241 for server in to_remove {
8242 self.language_server_statuses.remove(&server);
8243 }
8244 }
8245 }
8246
8247 fn invalidate_diagnostic_summaries_for_removed_entries(
8248 &mut self,
8249 worktree_id: WorktreeId,
8250 changes: &UpdatedEntriesSet,
8251 cx: &mut Context<Self>,
8252 ) {
8253 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8254 return;
8255 };
8256
8257 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8258 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8259 let downstream = self.downstream_client.clone();
8260
8261 for (path, _, _) in changes
8262 .iter()
8263 .filter(|(_, _, change)| *change == PathChange::Removed)
8264 {
8265 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8266 for (server_id, _) in &summaries_by_server_id {
8267 cleared_server_ids.insert(*server_id);
8268 if let Some((client, project_id)) = &downstream {
8269 client
8270 .send(proto::UpdateDiagnosticSummary {
8271 project_id: *project_id,
8272 worktree_id: worktree_id.to_proto(),
8273 summary: Some(proto::DiagnosticSummary {
8274 path: path.as_ref().to_proto(),
8275 language_server_id: server_id.0 as u64,
8276 error_count: 0,
8277 warning_count: 0,
8278 }),
8279 more_summaries: Vec::new(),
8280 })
8281 .ok();
8282 }
8283 }
8284 cleared_paths.push(ProjectPath {
8285 worktree_id,
8286 path: path.clone(),
8287 });
8288 }
8289 }
8290
8291 if !cleared_paths.is_empty() {
8292 for server_id in cleared_server_ids {
8293 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8294 server_id,
8295 paths: cleared_paths.clone(),
8296 });
8297 }
8298 }
8299 }
8300
8301 pub fn shared(
8302 &mut self,
8303 project_id: u64,
8304 downstream_client: AnyProtoClient,
8305 _: &mut Context<Self>,
8306 ) {
8307 self.downstream_client = Some((downstream_client.clone(), project_id));
8308
8309 for (server_id, status) in &self.language_server_statuses {
8310 if let Some(server) = self.language_server_for_id(*server_id) {
8311 downstream_client
8312 .send(proto::StartLanguageServer {
8313 project_id,
8314 server: Some(proto::LanguageServer {
8315 id: server_id.to_proto(),
8316 name: status.name.to_string(),
8317 worktree_id: status.worktree.map(|id| id.to_proto()),
8318 }),
8319 capabilities: serde_json::to_string(&server.capabilities())
8320 .expect("serializing server LSP capabilities"),
8321 })
8322 .log_err();
8323 }
8324 }
8325 }
8326
8327 pub fn disconnected_from_host(&mut self) {
8328 self.downstream_client.take();
8329 }
8330
8331 pub fn disconnected_from_ssh_remote(&mut self) {
8332 if let LspStoreMode::Remote(RemoteLspStore {
8333 upstream_client, ..
8334 }) = &mut self.mode
8335 {
8336 upstream_client.take();
8337 }
8338 }
8339
8340 pub(crate) fn set_language_server_statuses_from_proto(
8341 &mut self,
8342 project: WeakEntity<Project>,
8343 language_servers: Vec<proto::LanguageServer>,
8344 server_capabilities: Vec<String>,
8345 cx: &mut Context<Self>,
8346 ) {
8347 let lsp_logs = cx
8348 .try_global::<GlobalLogStore>()
8349 .map(|lsp_store| lsp_store.0.clone());
8350
8351 self.language_server_statuses = language_servers
8352 .into_iter()
8353 .zip(server_capabilities)
8354 .map(|(server, server_capabilities)| {
8355 let server_id = LanguageServerId(server.id as usize);
8356 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8357 self.lsp_server_capabilities
8358 .insert(server_id, server_capabilities);
8359 }
8360
8361 let name = LanguageServerName::from_proto(server.name);
8362 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8363
8364 if let Some(lsp_logs) = &lsp_logs {
8365 lsp_logs.update(cx, |lsp_logs, cx| {
8366 lsp_logs.add_language_server(
8367 // Only remote clients get their language servers set from proto
8368 LanguageServerKind::Remote {
8369 project: project.clone(),
8370 },
8371 server_id,
8372 Some(name.clone()),
8373 worktree,
8374 None,
8375 cx,
8376 );
8377 });
8378 }
8379
8380 (
8381 server_id,
8382 LanguageServerStatus {
8383 name,
8384 server_version: None,
8385 server_readable_version: None,
8386 pending_work: Default::default(),
8387 has_pending_diagnostic_updates: false,
8388 progress_tokens: Default::default(),
8389 worktree,
8390 binary: None,
8391 configuration: None,
8392 workspace_folders: BTreeSet::new(),
8393 process_id: None,
8394 },
8395 )
8396 })
8397 .collect();
8398 }
8399
8400 #[cfg(feature = "test-support")]
8401 pub fn update_diagnostic_entries(
8402 &mut self,
8403 server_id: LanguageServerId,
8404 abs_path: PathBuf,
8405 result_id: Option<SharedString>,
8406 version: Option<i32>,
8407 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8408 cx: &mut Context<Self>,
8409 ) -> anyhow::Result<()> {
8410 self.merge_diagnostic_entries(
8411 vec![DocumentDiagnosticsUpdate {
8412 diagnostics: DocumentDiagnostics {
8413 diagnostics,
8414 document_abs_path: abs_path,
8415 version,
8416 },
8417 result_id,
8418 server_id,
8419 disk_based_sources: Cow::Borrowed(&[]),
8420 registration_id: None,
8421 }],
8422 |_, _, _| false,
8423 cx,
8424 )?;
8425 Ok(())
8426 }
8427
8428 pub fn merge_diagnostic_entries<'a>(
8429 &mut self,
8430 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8431 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8432 cx: &mut Context<Self>,
8433 ) -> anyhow::Result<()> {
8434 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8435 let mut updated_diagnostics_paths = HashMap::default();
8436 for mut update in diagnostic_updates {
8437 let abs_path = &update.diagnostics.document_abs_path;
8438 let server_id = update.server_id;
8439 let Some((worktree, relative_path)) =
8440 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8441 else {
8442 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8443 return Ok(());
8444 };
8445
8446 let worktree_id = worktree.read(cx).id();
8447 let project_path = ProjectPath {
8448 worktree_id,
8449 path: relative_path,
8450 };
8451
8452 let document_uri = lsp::Uri::from_file_path(abs_path)
8453 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8454 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8455 let snapshot = buffer_handle.read(cx).snapshot();
8456 let buffer = buffer_handle.read(cx);
8457 let reused_diagnostics = buffer
8458 .buffer_diagnostics(Some(server_id))
8459 .iter()
8460 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8461 .map(|v| {
8462 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8463 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8464 DiagnosticEntry {
8465 range: start..end,
8466 diagnostic: v.diagnostic.clone(),
8467 }
8468 })
8469 .collect::<Vec<_>>();
8470
8471 self.as_local_mut()
8472 .context("cannot merge diagnostics on a remote LspStore")?
8473 .update_buffer_diagnostics(
8474 &buffer_handle,
8475 server_id,
8476 Some(update.registration_id),
8477 update.result_id,
8478 update.diagnostics.version,
8479 update.diagnostics.diagnostics.clone(),
8480 reused_diagnostics.clone(),
8481 cx,
8482 )?;
8483
8484 update.diagnostics.diagnostics.extend(reused_diagnostics);
8485 } else if let Some(local) = self.as_local() {
8486 let reused_diagnostics = local
8487 .diagnostics
8488 .get(&worktree_id)
8489 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8490 .and_then(|diagnostics_by_server_id| {
8491 diagnostics_by_server_id
8492 .binary_search_by_key(&server_id, |e| e.0)
8493 .ok()
8494 .map(|ix| &diagnostics_by_server_id[ix].1)
8495 })
8496 .into_iter()
8497 .flatten()
8498 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8499
8500 update
8501 .diagnostics
8502 .diagnostics
8503 .extend(reused_diagnostics.cloned());
8504 }
8505
8506 let updated = worktree.update(cx, |worktree, cx| {
8507 self.update_worktree_diagnostics(
8508 worktree.id(),
8509 server_id,
8510 project_path.path.clone(),
8511 update.diagnostics.diagnostics,
8512 cx,
8513 )
8514 })?;
8515 match updated {
8516 ControlFlow::Continue(new_summary) => {
8517 if let Some((project_id, new_summary)) = new_summary {
8518 match &mut diagnostics_summary {
8519 Some(diagnostics_summary) => {
8520 diagnostics_summary
8521 .more_summaries
8522 .push(proto::DiagnosticSummary {
8523 path: project_path.path.as_ref().to_proto(),
8524 language_server_id: server_id.0 as u64,
8525 error_count: new_summary.error_count,
8526 warning_count: new_summary.warning_count,
8527 })
8528 }
8529 None => {
8530 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8531 project_id,
8532 worktree_id: worktree_id.to_proto(),
8533 summary: Some(proto::DiagnosticSummary {
8534 path: project_path.path.as_ref().to_proto(),
8535 language_server_id: server_id.0 as u64,
8536 error_count: new_summary.error_count,
8537 warning_count: new_summary.warning_count,
8538 }),
8539 more_summaries: Vec::new(),
8540 })
8541 }
8542 }
8543 }
8544 updated_diagnostics_paths
8545 .entry(server_id)
8546 .or_insert_with(Vec::new)
8547 .push(project_path);
8548 }
8549 ControlFlow::Break(()) => {}
8550 }
8551 }
8552
8553 if let Some((diagnostics_summary, (downstream_client, _))) =
8554 diagnostics_summary.zip(self.downstream_client.as_ref())
8555 {
8556 downstream_client.send(diagnostics_summary).log_err();
8557 }
8558 for (server_id, paths) in updated_diagnostics_paths {
8559 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8560 }
8561 Ok(())
8562 }
8563
8564 fn update_worktree_diagnostics(
8565 &mut self,
8566 worktree_id: WorktreeId,
8567 server_id: LanguageServerId,
8568 path_in_worktree: Arc<RelPath>,
8569 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8570 _: &mut Context<Worktree>,
8571 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8572 let local = match &mut self.mode {
8573 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8574 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8575 };
8576
8577 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8578 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8579 let summaries_by_server_id = summaries_for_tree
8580 .entry(path_in_worktree.clone())
8581 .or_default();
8582
8583 let old_summary = summaries_by_server_id
8584 .remove(&server_id)
8585 .unwrap_or_default();
8586
8587 let new_summary = DiagnosticSummary::new(&diagnostics);
8588 if diagnostics.is_empty() {
8589 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8590 {
8591 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8592 diagnostics_by_server_id.remove(ix);
8593 }
8594 if diagnostics_by_server_id.is_empty() {
8595 diagnostics_for_tree.remove(&path_in_worktree);
8596 }
8597 }
8598 } else {
8599 summaries_by_server_id.insert(server_id, new_summary);
8600 let diagnostics_by_server_id = diagnostics_for_tree
8601 .entry(path_in_worktree.clone())
8602 .or_default();
8603 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8604 Ok(ix) => {
8605 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8606 }
8607 Err(ix) => {
8608 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8609 }
8610 }
8611 }
8612
8613 if !old_summary.is_empty() || !new_summary.is_empty() {
8614 if let Some((_, project_id)) = &self.downstream_client {
8615 Ok(ControlFlow::Continue(Some((
8616 *project_id,
8617 proto::DiagnosticSummary {
8618 path: path_in_worktree.to_proto(),
8619 language_server_id: server_id.0 as u64,
8620 error_count: new_summary.error_count as u32,
8621 warning_count: new_summary.warning_count as u32,
8622 },
8623 ))))
8624 } else {
8625 Ok(ControlFlow::Continue(None))
8626 }
8627 } else {
8628 Ok(ControlFlow::Break(()))
8629 }
8630 }
8631
8632 pub fn open_buffer_for_symbol(
8633 &mut self,
8634 symbol: &Symbol,
8635 cx: &mut Context<Self>,
8636 ) -> Task<Result<Entity<Buffer>>> {
8637 if let Some((client, project_id)) = self.upstream_client() {
8638 let request = client.request(proto::OpenBufferForSymbol {
8639 project_id,
8640 symbol: Some(Self::serialize_symbol(symbol)),
8641 });
8642 cx.spawn(async move |this, cx| {
8643 let response = request.await?;
8644 let buffer_id = BufferId::new(response.buffer_id)?;
8645 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8646 .await
8647 })
8648 } else if let Some(local) = self.as_local() {
8649 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8650 seed.worktree_id == symbol.source_worktree_id
8651 && state.id == symbol.source_language_server_id
8652 && symbol.language_server_name == seed.name
8653 });
8654 if !is_valid {
8655 return Task::ready(Err(anyhow!(
8656 "language server for worktree and language not found"
8657 )));
8658 };
8659
8660 let symbol_abs_path = match &symbol.path {
8661 SymbolLocation::InProject(project_path) => self
8662 .worktree_store
8663 .read(cx)
8664 .absolutize(&project_path, cx)
8665 .context("no such worktree"),
8666 SymbolLocation::OutsideProject {
8667 abs_path,
8668 signature: _,
8669 } => Ok(abs_path.to_path_buf()),
8670 };
8671 let symbol_abs_path = match symbol_abs_path {
8672 Ok(abs_path) => abs_path,
8673 Err(err) => return Task::ready(Err(err)),
8674 };
8675 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8676 uri
8677 } else {
8678 return Task::ready(Err(anyhow!("invalid symbol path")));
8679 };
8680
8681 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8682 } else {
8683 Task::ready(Err(anyhow!("no upstream client or local store")))
8684 }
8685 }
8686
8687 pub(crate) fn open_local_buffer_via_lsp(
8688 &mut self,
8689 abs_path: lsp::Uri,
8690 language_server_id: LanguageServerId,
8691 cx: &mut Context<Self>,
8692 ) -> Task<Result<Entity<Buffer>>> {
8693 let path_style = self.worktree_store.read(cx).path_style();
8694 cx.spawn(async move |lsp_store, cx| {
8695 // Escape percent-encoded string.
8696 let current_scheme = abs_path.scheme().to_owned();
8697 // Uri is immutable, so we can't modify the scheme
8698
8699 let abs_path = abs_path
8700 .to_file_path_ext(path_style)
8701 .map_err(|()| anyhow!("can't convert URI to path"))?;
8702 let p = abs_path.clone();
8703 let yarn_worktree = lsp_store
8704 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8705 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8706 cx.spawn(async move |this, cx| {
8707 let t = this
8708 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8709 .ok()?;
8710 t.await
8711 })
8712 }),
8713 None => Task::ready(None),
8714 })?
8715 .await;
8716 let (worktree_root_target, known_relative_path) =
8717 if let Some((zip_root, relative_path)) = yarn_worktree {
8718 (zip_root, Some(relative_path))
8719 } else {
8720 (Arc::<Path>::from(abs_path.as_path()), None)
8721 };
8722 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8723 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8724 worktree_store.find_worktree(&worktree_root_target, cx)
8725 })
8726 })?;
8727 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8728 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8729 (result.0, relative_path, None)
8730 } else {
8731 let worktree = lsp_store
8732 .update(cx, |lsp_store, cx| {
8733 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8734 worktree_store.create_worktree(&worktree_root_target, false, cx)
8735 })
8736 })?
8737 .await?;
8738 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8739 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8740 lsp_store
8741 .update(cx, |lsp_store, cx| {
8742 if let Some(local) = lsp_store.as_local_mut() {
8743 local.register_language_server_for_invisible_worktree(
8744 &worktree,
8745 language_server_id,
8746 cx,
8747 )
8748 }
8749 match lsp_store.language_server_statuses.get(&language_server_id) {
8750 Some(status) => status.worktree,
8751 None => None,
8752 }
8753 })
8754 .ok()
8755 .flatten()
8756 .zip(Some(worktree_root.clone()))
8757 } else {
8758 None
8759 };
8760 let relative_path = if let Some(known_path) = known_relative_path {
8761 known_path
8762 } else {
8763 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8764 .into_arc()
8765 };
8766 (worktree, relative_path, source_ws)
8767 };
8768 let project_path = ProjectPath {
8769 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8770 path: relative_path,
8771 };
8772 let buffer = lsp_store
8773 .update(cx, |lsp_store, cx| {
8774 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8775 buffer_store.open_buffer(project_path, cx)
8776 })
8777 })?
8778 .await?;
8779 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8780 if let Some((source_ws, worktree_root)) = source_ws {
8781 buffer.update(cx, |buffer, cx| {
8782 let settings = WorktreeSettings::get(
8783 Some(
8784 (&ProjectPath {
8785 worktree_id: source_ws,
8786 path: Arc::from(RelPath::empty()),
8787 })
8788 .into(),
8789 ),
8790 cx,
8791 );
8792 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8793 if is_read_only {
8794 buffer.set_capability(Capability::ReadOnly, cx);
8795 }
8796 });
8797 }
8798 Ok(buffer)
8799 })
8800 }
8801
8802 fn local_lsp_servers_for_buffer(
8803 &self,
8804 buffer: &Entity<Buffer>,
8805 cx: &mut Context<Self>,
8806 ) -> Vec<LanguageServerId> {
8807 let Some(local) = self.as_local() else {
8808 return Vec::new();
8809 };
8810
8811 let snapshot = buffer.read(cx).snapshot();
8812
8813 buffer.update(cx, |buffer, cx| {
8814 local
8815 .language_servers_for_buffer(buffer, cx)
8816 .map(|(_, server)| server.server_id())
8817 .filter(|server_id| {
8818 self.as_local().is_none_or(|local| {
8819 local
8820 .buffers_opened_in_servers
8821 .get(&snapshot.remote_id())
8822 .is_some_and(|servers| servers.contains(server_id))
8823 })
8824 })
8825 .collect()
8826 })
8827 }
8828
8829 fn request_multiple_lsp_locally<P, R>(
8830 &mut self,
8831 buffer: &Entity<Buffer>,
8832 position: Option<P>,
8833 request: R,
8834 cx: &mut Context<Self>,
8835 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8836 where
8837 P: ToOffset,
8838 R: LspCommand + Clone,
8839 <R::LspRequest as lsp::request::Request>::Result: Send,
8840 <R::LspRequest as lsp::request::Request>::Params: Send,
8841 {
8842 let Some(local) = self.as_local() else {
8843 return Task::ready(Vec::new());
8844 };
8845
8846 let snapshot = buffer.read(cx).snapshot();
8847 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8848
8849 let server_ids = buffer.update(cx, |buffer, cx| {
8850 local
8851 .language_servers_for_buffer(buffer, cx)
8852 .filter(|(adapter, _)| {
8853 scope
8854 .as_ref()
8855 .map(|scope| scope.language_allowed(&adapter.name))
8856 .unwrap_or(true)
8857 })
8858 .map(|(_, server)| server.server_id())
8859 .filter(|server_id| {
8860 self.as_local().is_none_or(|local| {
8861 local
8862 .buffers_opened_in_servers
8863 .get(&snapshot.remote_id())
8864 .is_some_and(|servers| servers.contains(server_id))
8865 })
8866 })
8867 .collect::<Vec<_>>()
8868 });
8869
8870 let mut response_results = server_ids
8871 .into_iter()
8872 .map(|server_id| {
8873 let task = self.request_lsp(
8874 buffer.clone(),
8875 LanguageServerToQuery::Other(server_id),
8876 request.clone(),
8877 cx,
8878 );
8879 async move { (server_id, task.await) }
8880 })
8881 .collect::<FuturesUnordered<_>>();
8882
8883 cx.background_spawn(async move {
8884 let mut responses = Vec::with_capacity(response_results.len());
8885 while let Some((server_id, response_result)) = response_results.next().await {
8886 match response_result {
8887 Ok(response) => responses.push((server_id, response)),
8888 // rust-analyzer likes to error with this when its still loading up
8889 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8890 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8891 }
8892 }
8893 responses
8894 })
8895 }
8896
8897 async fn handle_lsp_get_completions(
8898 this: Entity<Self>,
8899 envelope: TypedEnvelope<proto::GetCompletions>,
8900 mut cx: AsyncApp,
8901 ) -> Result<proto::GetCompletionsResponse> {
8902 let sender_id = envelope.original_sender_id().unwrap_or_default();
8903
8904 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8905 let buffer_handle = this.update(&mut cx, |this, cx| {
8906 this.buffer_store.read(cx).get_existing(buffer_id)
8907 })?;
8908 let request = GetCompletions::from_proto(
8909 envelope.payload,
8910 this.clone(),
8911 buffer_handle.clone(),
8912 cx.clone(),
8913 )
8914 .await?;
8915
8916 let server_to_query = match request.server_id {
8917 Some(server_id) => LanguageServerToQuery::Other(server_id),
8918 None => LanguageServerToQuery::FirstCapable,
8919 };
8920
8921 let response = this
8922 .update(&mut cx, |this, cx| {
8923 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8924 })
8925 .await?;
8926 this.update(&mut cx, |this, cx| {
8927 Ok(GetCompletions::response_to_proto(
8928 response,
8929 this,
8930 sender_id,
8931 &buffer_handle.read(cx).version(),
8932 cx,
8933 ))
8934 })
8935 }
8936
8937 async fn handle_lsp_command<T: LspCommand>(
8938 this: Entity<Self>,
8939 envelope: TypedEnvelope<T::ProtoRequest>,
8940 mut cx: AsyncApp,
8941 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8942 where
8943 <T::LspRequest as lsp::request::Request>::Params: Send,
8944 <T::LspRequest as lsp::request::Request>::Result: Send,
8945 {
8946 let sender_id = envelope.original_sender_id().unwrap_or_default();
8947 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8948 let buffer_handle = this.update(&mut cx, |this, cx| {
8949 this.buffer_store.read(cx).get_existing(buffer_id)
8950 })?;
8951 let request = T::from_proto(
8952 envelope.payload,
8953 this.clone(),
8954 buffer_handle.clone(),
8955 cx.clone(),
8956 )
8957 .await?;
8958 let response = this
8959 .update(&mut cx, |this, cx| {
8960 this.request_lsp(
8961 buffer_handle.clone(),
8962 LanguageServerToQuery::FirstCapable,
8963 request,
8964 cx,
8965 )
8966 })
8967 .await?;
8968 this.update(&mut cx, |this, cx| {
8969 Ok(T::response_to_proto(
8970 response,
8971 this,
8972 sender_id,
8973 &buffer_handle.read(cx).version(),
8974 cx,
8975 ))
8976 })
8977 }
8978
8979 async fn handle_lsp_query(
8980 lsp_store: Entity<Self>,
8981 envelope: TypedEnvelope<proto::LspQuery>,
8982 mut cx: AsyncApp,
8983 ) -> Result<proto::Ack> {
8984 use proto::lsp_query::Request;
8985 let sender_id = envelope.original_sender_id().unwrap_or_default();
8986 let lsp_query = envelope.payload;
8987 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8988 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8989 match lsp_query.request.context("invalid LSP query request")? {
8990 Request::GetReferences(get_references) => {
8991 let position = get_references.position.clone().and_then(deserialize_anchor);
8992 Self::query_lsp_locally::<GetReferences>(
8993 lsp_store,
8994 server_id,
8995 sender_id,
8996 lsp_request_id,
8997 get_references,
8998 position,
8999 &mut cx,
9000 )
9001 .await?;
9002 }
9003 Request::GetDocumentColor(get_document_color) => {
9004 Self::query_lsp_locally::<GetDocumentColor>(
9005 lsp_store,
9006 server_id,
9007 sender_id,
9008 lsp_request_id,
9009 get_document_color,
9010 None,
9011 &mut cx,
9012 )
9013 .await?;
9014 }
9015 Request::GetFoldingRanges(get_folding_ranges) => {
9016 Self::query_lsp_locally::<GetFoldingRanges>(
9017 lsp_store,
9018 server_id,
9019 sender_id,
9020 lsp_request_id,
9021 get_folding_ranges,
9022 None,
9023 &mut cx,
9024 )
9025 .await?;
9026 }
9027 Request::GetDocumentSymbols(get_document_symbols) => {
9028 Self::query_lsp_locally::<GetDocumentSymbols>(
9029 lsp_store,
9030 server_id,
9031 sender_id,
9032 lsp_request_id,
9033 get_document_symbols,
9034 None,
9035 &mut cx,
9036 )
9037 .await?;
9038 }
9039 Request::GetHover(get_hover) => {
9040 let position = get_hover.position.clone().and_then(deserialize_anchor);
9041 Self::query_lsp_locally::<GetHover>(
9042 lsp_store,
9043 server_id,
9044 sender_id,
9045 lsp_request_id,
9046 get_hover,
9047 position,
9048 &mut cx,
9049 )
9050 .await?;
9051 }
9052 Request::GetCodeActions(get_code_actions) => {
9053 Self::query_lsp_locally::<GetCodeActions>(
9054 lsp_store,
9055 server_id,
9056 sender_id,
9057 lsp_request_id,
9058 get_code_actions,
9059 None,
9060 &mut cx,
9061 )
9062 .await?;
9063 }
9064 Request::GetSignatureHelp(get_signature_help) => {
9065 let position = get_signature_help
9066 .position
9067 .clone()
9068 .and_then(deserialize_anchor);
9069 Self::query_lsp_locally::<GetSignatureHelp>(
9070 lsp_store,
9071 server_id,
9072 sender_id,
9073 lsp_request_id,
9074 get_signature_help,
9075 position,
9076 &mut cx,
9077 )
9078 .await?;
9079 }
9080 Request::GetCodeLens(get_code_lens) => {
9081 Self::query_lsp_locally::<GetCodeLens>(
9082 lsp_store,
9083 server_id,
9084 sender_id,
9085 lsp_request_id,
9086 get_code_lens,
9087 None,
9088 &mut cx,
9089 )
9090 .await?;
9091 }
9092 Request::GetDefinition(get_definition) => {
9093 let position = get_definition.position.clone().and_then(deserialize_anchor);
9094 Self::query_lsp_locally::<GetDefinitions>(
9095 lsp_store,
9096 server_id,
9097 sender_id,
9098 lsp_request_id,
9099 get_definition,
9100 position,
9101 &mut cx,
9102 )
9103 .await?;
9104 }
9105 Request::GetDeclaration(get_declaration) => {
9106 let position = get_declaration
9107 .position
9108 .clone()
9109 .and_then(deserialize_anchor);
9110 Self::query_lsp_locally::<GetDeclarations>(
9111 lsp_store,
9112 server_id,
9113 sender_id,
9114 lsp_request_id,
9115 get_declaration,
9116 position,
9117 &mut cx,
9118 )
9119 .await?;
9120 }
9121 Request::GetTypeDefinition(get_type_definition) => {
9122 let position = get_type_definition
9123 .position
9124 .clone()
9125 .and_then(deserialize_anchor);
9126 Self::query_lsp_locally::<GetTypeDefinitions>(
9127 lsp_store,
9128 server_id,
9129 sender_id,
9130 lsp_request_id,
9131 get_type_definition,
9132 position,
9133 &mut cx,
9134 )
9135 .await?;
9136 }
9137 Request::GetImplementation(get_implementation) => {
9138 let position = get_implementation
9139 .position
9140 .clone()
9141 .and_then(deserialize_anchor);
9142 Self::query_lsp_locally::<GetImplementations>(
9143 lsp_store,
9144 server_id,
9145 sender_id,
9146 lsp_request_id,
9147 get_implementation,
9148 position,
9149 &mut cx,
9150 )
9151 .await?;
9152 }
9153 Request::InlayHints(inlay_hints) => {
9154 let query_start = inlay_hints
9155 .start
9156 .clone()
9157 .and_then(deserialize_anchor)
9158 .context("invalid inlay hints range start")?;
9159 let query_end = inlay_hints
9160 .end
9161 .clone()
9162 .and_then(deserialize_anchor)
9163 .context("invalid inlay hints range end")?;
9164 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9165 &lsp_store,
9166 server_id,
9167 lsp_request_id,
9168 &inlay_hints,
9169 query_start..query_end,
9170 &mut cx,
9171 )
9172 .await
9173 .context("preparing inlay hints request")?;
9174 Self::query_lsp_locally::<InlayHints>(
9175 lsp_store,
9176 server_id,
9177 sender_id,
9178 lsp_request_id,
9179 inlay_hints,
9180 None,
9181 &mut cx,
9182 )
9183 .await
9184 .context("querying for inlay hints")?
9185 }
9186 //////////////////////////////
9187 // Below are LSP queries that need to fetch more data,
9188 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9189 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9190 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9191 &lsp_store,
9192 &get_document_diagnostics,
9193 &mut cx,
9194 )
9195 .await?;
9196 lsp_store.update(&mut cx, |lsp_store, cx| {
9197 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9198 let key = LspKey {
9199 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9200 server_queried: server_id,
9201 };
9202 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9203 ) {
9204 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9205 lsp_requests.clear();
9206 };
9207 }
9208
9209 lsp_data.lsp_requests.entry(key).or_default().insert(
9210 lsp_request_id,
9211 cx.spawn(async move |lsp_store, cx| {
9212 let diagnostics_pull = lsp_store
9213 .update(cx, |lsp_store, cx| {
9214 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9215 })
9216 .ok();
9217 if let Some(diagnostics_pull) = diagnostics_pull {
9218 match diagnostics_pull.await {
9219 Ok(()) => {}
9220 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9221 };
9222 }
9223 }),
9224 );
9225 });
9226 }
9227 Request::SemanticTokens(semantic_tokens) => {
9228 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9229 &lsp_store,
9230 &semantic_tokens,
9231 &mut cx,
9232 )
9233 .await?;
9234 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9235 lsp_store.update(&mut cx, |lsp_store, cx| {
9236 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9237 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9238 let key = LspKey {
9239 request_type: TypeId::of::<SemanticTokensFull>(),
9240 server_queried: server_id,
9241 };
9242 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9243 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9244 lsp_requests.clear();
9245 };
9246 }
9247
9248 lsp_data.lsp_requests.entry(key).or_default().insert(
9249 lsp_request_id,
9250 cx.spawn(async move |lsp_store, cx| {
9251 let tokens_fetch = lsp_store
9252 .update(cx, |lsp_store, cx| {
9253 lsp_store
9254 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9255 })
9256 .ok();
9257 if let Some(tokens_fetch) = tokens_fetch {
9258 let new_tokens = tokens_fetch.await;
9259 if let Some(new_tokens) = new_tokens {
9260 lsp_store
9261 .update(cx, |lsp_store, cx| {
9262 let response = new_tokens
9263 .into_iter()
9264 .map(|(server_id, response)| {
9265 (
9266 server_id.to_proto(),
9267 SemanticTokensFull::response_to_proto(
9268 response,
9269 lsp_store,
9270 sender_id,
9271 &buffer_version,
9272 cx,
9273 ),
9274 )
9275 })
9276 .collect::<HashMap<_, _>>();
9277 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9278 project_id,
9279 lsp_request_id,
9280 response,
9281 ) {
9282 Ok(()) => {}
9283 Err(e) => {
9284 log::error!(
9285 "Failed to send semantic tokens LSP response: {e:#}",
9286 )
9287 }
9288 }
9289 })
9290 .ok();
9291 }
9292 }
9293 }),
9294 );
9295 }
9296 });
9297 }
9298 }
9299 Ok(proto::Ack {})
9300 }
9301
9302 async fn handle_lsp_query_response(
9303 lsp_store: Entity<Self>,
9304 envelope: TypedEnvelope<proto::LspQueryResponse>,
9305 cx: AsyncApp,
9306 ) -> Result<()> {
9307 lsp_store.read_with(&cx, |lsp_store, _| {
9308 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9309 upstream_client.handle_lsp_response(envelope.clone());
9310 }
9311 });
9312 Ok(())
9313 }
9314
9315 async fn handle_apply_code_action(
9316 this: Entity<Self>,
9317 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9318 mut cx: AsyncApp,
9319 ) -> Result<proto::ApplyCodeActionResponse> {
9320 let sender_id = envelope.original_sender_id().unwrap_or_default();
9321 let action =
9322 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9323 let apply_code_action = this.update(&mut cx, |this, cx| {
9324 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9325 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9326 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9327 })?;
9328
9329 let project_transaction = apply_code_action.await?;
9330 let project_transaction = this.update(&mut cx, |this, cx| {
9331 this.buffer_store.update(cx, |buffer_store, cx| {
9332 buffer_store.serialize_project_transaction_for_peer(
9333 project_transaction,
9334 sender_id,
9335 cx,
9336 )
9337 })
9338 });
9339 Ok(proto::ApplyCodeActionResponse {
9340 transaction: Some(project_transaction),
9341 })
9342 }
9343
9344 async fn handle_register_buffer_with_language_servers(
9345 this: Entity<Self>,
9346 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9347 mut cx: AsyncApp,
9348 ) -> Result<proto::Ack> {
9349 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9350 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9351 this.update(&mut cx, |this, cx| {
9352 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9353 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9354 project_id: upstream_project_id,
9355 buffer_id: buffer_id.to_proto(),
9356 only_servers: envelope.payload.only_servers,
9357 });
9358 }
9359
9360 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9361 anyhow::bail!("buffer is not open");
9362 };
9363
9364 let handle = this.register_buffer_with_language_servers(
9365 &buffer,
9366 envelope
9367 .payload
9368 .only_servers
9369 .into_iter()
9370 .filter_map(|selector| {
9371 Some(match selector.selector? {
9372 proto::language_server_selector::Selector::ServerId(server_id) => {
9373 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9374 }
9375 proto::language_server_selector::Selector::Name(name) => {
9376 LanguageServerSelector::Name(LanguageServerName(
9377 SharedString::from(name),
9378 ))
9379 }
9380 })
9381 })
9382 .collect(),
9383 false,
9384 cx,
9385 );
9386 // Pull diagnostics for the buffer even if it was already registered.
9387 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9388 // but it's unclear if we need it.
9389 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9390 .detach();
9391 this.buffer_store().update(cx, |buffer_store, _| {
9392 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9393 });
9394
9395 Ok(())
9396 })?;
9397 Ok(proto::Ack {})
9398 }
9399
9400 async fn handle_rename_project_entry(
9401 this: Entity<Self>,
9402 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9403 mut cx: AsyncApp,
9404 ) -> Result<proto::ProjectEntryResponse> {
9405 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9406 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9407 let new_path =
9408 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9409
9410 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9411 .update(&mut cx, |this, cx| {
9412 let (worktree, entry) = this
9413 .worktree_store
9414 .read(cx)
9415 .worktree_and_entry_for_id(entry_id, cx)?;
9416 let new_worktree = this
9417 .worktree_store
9418 .read(cx)
9419 .worktree_for_id(new_worktree_id, cx)?;
9420 Some((
9421 this.worktree_store.clone(),
9422 worktree,
9423 new_worktree,
9424 entry.clone(),
9425 ))
9426 })
9427 .context("worktree not found")?;
9428 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9429 (worktree.absolutize(&old_entry.path), worktree.id())
9430 });
9431 let new_abs_path =
9432 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9433
9434 let _transaction = Self::will_rename_entry(
9435 this.downgrade(),
9436 old_worktree_id,
9437 &old_abs_path,
9438 &new_abs_path,
9439 old_entry.is_dir(),
9440 cx.clone(),
9441 )
9442 .await;
9443 let response = WorktreeStore::handle_rename_project_entry(
9444 worktree_store,
9445 envelope.payload,
9446 cx.clone(),
9447 )
9448 .await;
9449 this.read_with(&cx, |this, _| {
9450 this.did_rename_entry(
9451 old_worktree_id,
9452 &old_abs_path,
9453 &new_abs_path,
9454 old_entry.is_dir(),
9455 );
9456 });
9457 response
9458 }
9459
9460 async fn handle_update_diagnostic_summary(
9461 this: Entity<Self>,
9462 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9463 mut cx: AsyncApp,
9464 ) -> Result<()> {
9465 this.update(&mut cx, |lsp_store, cx| {
9466 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9467 let mut updated_diagnostics_paths = HashMap::default();
9468 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9469 for message_summary in envelope
9470 .payload
9471 .summary
9472 .into_iter()
9473 .chain(envelope.payload.more_summaries)
9474 {
9475 let project_path = ProjectPath {
9476 worktree_id,
9477 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9478 };
9479 let path = project_path.path.clone();
9480 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9481 let summary = DiagnosticSummary {
9482 error_count: message_summary.error_count as usize,
9483 warning_count: message_summary.warning_count as usize,
9484 };
9485
9486 if summary.is_empty() {
9487 if let Some(worktree_summaries) =
9488 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9489 && let Some(summaries) = worktree_summaries.get_mut(&path)
9490 {
9491 summaries.remove(&server_id);
9492 if summaries.is_empty() {
9493 worktree_summaries.remove(&path);
9494 }
9495 }
9496 } else {
9497 lsp_store
9498 .diagnostic_summaries
9499 .entry(worktree_id)
9500 .or_default()
9501 .entry(path)
9502 .or_default()
9503 .insert(server_id, summary);
9504 }
9505
9506 if let Some((_, project_id)) = &lsp_store.downstream_client {
9507 match &mut diagnostics_summary {
9508 Some(diagnostics_summary) => {
9509 diagnostics_summary
9510 .more_summaries
9511 .push(proto::DiagnosticSummary {
9512 path: project_path.path.as_ref().to_proto(),
9513 language_server_id: server_id.0 as u64,
9514 error_count: summary.error_count as u32,
9515 warning_count: summary.warning_count as u32,
9516 })
9517 }
9518 None => {
9519 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9520 project_id: *project_id,
9521 worktree_id: worktree_id.to_proto(),
9522 summary: Some(proto::DiagnosticSummary {
9523 path: project_path.path.as_ref().to_proto(),
9524 language_server_id: server_id.0 as u64,
9525 error_count: summary.error_count as u32,
9526 warning_count: summary.warning_count as u32,
9527 }),
9528 more_summaries: Vec::new(),
9529 })
9530 }
9531 }
9532 }
9533 updated_diagnostics_paths
9534 .entry(server_id)
9535 .or_insert_with(Vec::new)
9536 .push(project_path);
9537 }
9538
9539 if let Some((diagnostics_summary, (downstream_client, _))) =
9540 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9541 {
9542 downstream_client.send(diagnostics_summary).log_err();
9543 }
9544 for (server_id, paths) in updated_diagnostics_paths {
9545 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9546 }
9547 Ok(())
9548 })
9549 }
9550
9551 async fn handle_start_language_server(
9552 lsp_store: Entity<Self>,
9553 envelope: TypedEnvelope<proto::StartLanguageServer>,
9554 mut cx: AsyncApp,
9555 ) -> Result<()> {
9556 let server = envelope.payload.server.context("invalid server")?;
9557 let server_capabilities =
9558 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9559 .with_context(|| {
9560 format!(
9561 "incorrect server capabilities {}",
9562 envelope.payload.capabilities
9563 )
9564 })?;
9565 lsp_store.update(&mut cx, |lsp_store, cx| {
9566 let server_id = LanguageServerId(server.id as usize);
9567 let server_name = LanguageServerName::from_proto(server.name.clone());
9568 lsp_store
9569 .lsp_server_capabilities
9570 .insert(server_id, server_capabilities);
9571 lsp_store.language_server_statuses.insert(
9572 server_id,
9573 LanguageServerStatus {
9574 name: server_name.clone(),
9575 server_version: None,
9576 server_readable_version: None,
9577 pending_work: Default::default(),
9578 has_pending_diagnostic_updates: false,
9579 progress_tokens: Default::default(),
9580 worktree: server.worktree_id.map(WorktreeId::from_proto),
9581 binary: None,
9582 configuration: None,
9583 workspace_folders: BTreeSet::new(),
9584 process_id: None,
9585 },
9586 );
9587 cx.emit(LspStoreEvent::LanguageServerAdded(
9588 server_id,
9589 server_name,
9590 server.worktree_id.map(WorktreeId::from_proto),
9591 ));
9592 cx.notify();
9593 });
9594 Ok(())
9595 }
9596
9597 async fn handle_update_language_server(
9598 lsp_store: Entity<Self>,
9599 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9600 mut cx: AsyncApp,
9601 ) -> Result<()> {
9602 lsp_store.update(&mut cx, |lsp_store, cx| {
9603 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9604
9605 match envelope.payload.variant.context("invalid variant")? {
9606 proto::update_language_server::Variant::WorkStart(payload) => {
9607 lsp_store.on_lsp_work_start(
9608 language_server_id,
9609 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9610 .context("invalid progress token value")?,
9611 LanguageServerProgress {
9612 title: payload.title,
9613 is_disk_based_diagnostics_progress: false,
9614 is_cancellable: payload.is_cancellable.unwrap_or(false),
9615 message: payload.message,
9616 percentage: payload.percentage.map(|p| p as usize),
9617 last_update_at: cx.background_executor().now(),
9618 },
9619 cx,
9620 );
9621 }
9622 proto::update_language_server::Variant::WorkProgress(payload) => {
9623 lsp_store.on_lsp_work_progress(
9624 language_server_id,
9625 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9626 .context("invalid progress token value")?,
9627 LanguageServerProgress {
9628 title: None,
9629 is_disk_based_diagnostics_progress: false,
9630 is_cancellable: payload.is_cancellable.unwrap_or(false),
9631 message: payload.message,
9632 percentage: payload.percentage.map(|p| p as usize),
9633 last_update_at: cx.background_executor().now(),
9634 },
9635 cx,
9636 );
9637 }
9638
9639 proto::update_language_server::Variant::WorkEnd(payload) => {
9640 lsp_store.on_lsp_work_end(
9641 language_server_id,
9642 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9643 .context("invalid progress token value")?,
9644 cx,
9645 );
9646 }
9647
9648 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9649 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9650 }
9651
9652 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9653 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9654 }
9655
9656 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9657 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9658 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9659 cx.emit(LspStoreEvent::LanguageServerUpdate {
9660 language_server_id,
9661 name: envelope
9662 .payload
9663 .server_name
9664 .map(SharedString::new)
9665 .map(LanguageServerName),
9666 message: non_lsp,
9667 });
9668 }
9669 }
9670
9671 Ok(())
9672 })
9673 }
9674
9675 async fn handle_language_server_log(
9676 this: Entity<Self>,
9677 envelope: TypedEnvelope<proto::LanguageServerLog>,
9678 mut cx: AsyncApp,
9679 ) -> Result<()> {
9680 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9681 let log_type = envelope
9682 .payload
9683 .log_type
9684 .map(LanguageServerLogType::from_proto)
9685 .context("invalid language server log type")?;
9686
9687 let message = envelope.payload.message;
9688
9689 this.update(&mut cx, |_, cx| {
9690 cx.emit(LspStoreEvent::LanguageServerLog(
9691 language_server_id,
9692 log_type,
9693 message,
9694 ));
9695 });
9696 Ok(())
9697 }
9698
9699 async fn handle_lsp_ext_cancel_flycheck(
9700 lsp_store: Entity<Self>,
9701 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9702 cx: AsyncApp,
9703 ) -> Result<proto::Ack> {
9704 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9705 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9706 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9707 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9708 } else {
9709 None
9710 }
9711 });
9712 if let Some(task) = task {
9713 task.context("handling lsp ext cancel flycheck")?;
9714 }
9715
9716 Ok(proto::Ack {})
9717 }
9718
9719 async fn handle_lsp_ext_run_flycheck(
9720 lsp_store: Entity<Self>,
9721 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9722 mut cx: AsyncApp,
9723 ) -> Result<proto::Ack> {
9724 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9725 lsp_store.update(&mut cx, |lsp_store, cx| {
9726 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9727 let text_document = if envelope.payload.current_file_only {
9728 let buffer_id = envelope
9729 .payload
9730 .buffer_id
9731 .map(|id| BufferId::new(id))
9732 .transpose()?;
9733 buffer_id
9734 .and_then(|buffer_id| {
9735 lsp_store
9736 .buffer_store()
9737 .read(cx)
9738 .get(buffer_id)
9739 .and_then(|buffer| {
9740 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9741 })
9742 .map(|path| make_text_document_identifier(&path))
9743 })
9744 .transpose()?
9745 } else {
9746 None
9747 };
9748 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9749 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9750 )?;
9751 }
9752 anyhow::Ok(())
9753 })?;
9754
9755 Ok(proto::Ack {})
9756 }
9757
9758 async fn handle_lsp_ext_clear_flycheck(
9759 lsp_store: Entity<Self>,
9760 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9761 cx: AsyncApp,
9762 ) -> Result<proto::Ack> {
9763 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9764 lsp_store.read_with(&cx, |lsp_store, _| {
9765 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9766 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9767 } else {
9768 None
9769 }
9770 });
9771
9772 Ok(proto::Ack {})
9773 }
9774
9775 pub fn disk_based_diagnostics_started(
9776 &mut self,
9777 language_server_id: LanguageServerId,
9778 cx: &mut Context<Self>,
9779 ) {
9780 if let Some(language_server_status) =
9781 self.language_server_statuses.get_mut(&language_server_id)
9782 {
9783 language_server_status.has_pending_diagnostic_updates = true;
9784 }
9785
9786 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9787 cx.emit(LspStoreEvent::LanguageServerUpdate {
9788 language_server_id,
9789 name: self
9790 .language_server_adapter_for_id(language_server_id)
9791 .map(|adapter| adapter.name()),
9792 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9793 Default::default(),
9794 ),
9795 })
9796 }
9797
9798 pub fn disk_based_diagnostics_finished(
9799 &mut self,
9800 language_server_id: LanguageServerId,
9801 cx: &mut Context<Self>,
9802 ) {
9803 if let Some(language_server_status) =
9804 self.language_server_statuses.get_mut(&language_server_id)
9805 {
9806 language_server_status.has_pending_diagnostic_updates = false;
9807 }
9808
9809 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9810 cx.emit(LspStoreEvent::LanguageServerUpdate {
9811 language_server_id,
9812 name: self
9813 .language_server_adapter_for_id(language_server_id)
9814 .map(|adapter| adapter.name()),
9815 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9816 Default::default(),
9817 ),
9818 })
9819 }
9820
9821 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9822 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9823 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9824 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9825 // the language server might take some time to publish diagnostics.
9826 fn simulate_disk_based_diagnostics_events_if_needed(
9827 &mut self,
9828 language_server_id: LanguageServerId,
9829 cx: &mut Context<Self>,
9830 ) {
9831 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9832
9833 let Some(LanguageServerState::Running {
9834 simulate_disk_based_diagnostics_completion,
9835 adapter,
9836 ..
9837 }) = self
9838 .as_local_mut()
9839 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9840 else {
9841 return;
9842 };
9843
9844 if adapter.disk_based_diagnostics_progress_token.is_some() {
9845 return;
9846 }
9847
9848 let prev_task =
9849 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9850 cx.background_executor()
9851 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9852 .await;
9853
9854 this.update(cx, |this, cx| {
9855 this.disk_based_diagnostics_finished(language_server_id, cx);
9856
9857 if let Some(LanguageServerState::Running {
9858 simulate_disk_based_diagnostics_completion,
9859 ..
9860 }) = this.as_local_mut().and_then(|local_store| {
9861 local_store.language_servers.get_mut(&language_server_id)
9862 }) {
9863 *simulate_disk_based_diagnostics_completion = None;
9864 }
9865 })
9866 .ok();
9867 }));
9868
9869 if prev_task.is_none() {
9870 self.disk_based_diagnostics_started(language_server_id, cx);
9871 }
9872 }
9873
9874 pub fn language_server_statuses(
9875 &self,
9876 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9877 self.language_server_statuses
9878 .iter()
9879 .map(|(key, value)| (*key, value))
9880 }
9881
9882 pub(super) fn did_rename_entry(
9883 &self,
9884 worktree_id: WorktreeId,
9885 old_path: &Path,
9886 new_path: &Path,
9887 is_dir: bool,
9888 ) {
9889 maybe!({
9890 let local_store = self.as_local()?;
9891
9892 let old_uri = lsp::Uri::from_file_path(old_path)
9893 .ok()
9894 .map(|uri| uri.to_string())?;
9895 let new_uri = lsp::Uri::from_file_path(new_path)
9896 .ok()
9897 .map(|uri| uri.to_string())?;
9898
9899 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9900 let Some(filter) = local_store
9901 .language_server_paths_watched_for_rename
9902 .get(&language_server.server_id())
9903 else {
9904 continue;
9905 };
9906
9907 if filter.should_send_did_rename(&old_uri, is_dir) {
9908 language_server
9909 .notify::<DidRenameFiles>(RenameFilesParams {
9910 files: vec![FileRename {
9911 old_uri: old_uri.clone(),
9912 new_uri: new_uri.clone(),
9913 }],
9914 })
9915 .ok();
9916 }
9917 }
9918 Some(())
9919 });
9920 }
9921
9922 pub(super) fn will_rename_entry(
9923 this: WeakEntity<Self>,
9924 worktree_id: WorktreeId,
9925 old_path: &Path,
9926 new_path: &Path,
9927 is_dir: bool,
9928 cx: AsyncApp,
9929 ) -> Task<ProjectTransaction> {
9930 let old_uri = lsp::Uri::from_file_path(old_path)
9931 .ok()
9932 .map(|uri| uri.to_string());
9933 let new_uri = lsp::Uri::from_file_path(new_path)
9934 .ok()
9935 .map(|uri| uri.to_string());
9936 cx.spawn(async move |cx| {
9937 let mut tasks = vec![];
9938 this.update(cx, |this, cx| {
9939 let local_store = this.as_local()?;
9940 let old_uri = old_uri?;
9941 let new_uri = new_uri?;
9942 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9943 let Some(filter) = local_store
9944 .language_server_paths_watched_for_rename
9945 .get(&language_server.server_id())
9946 else {
9947 continue;
9948 };
9949
9950 if !filter.should_send_will_rename(&old_uri, is_dir) {
9951 continue;
9952 }
9953 let request_timeout = ProjectSettings::get_global(cx)
9954 .global_lsp_settings
9955 .get_request_timeout();
9956
9957 let apply_edit = cx.spawn({
9958 let old_uri = old_uri.clone();
9959 let new_uri = new_uri.clone();
9960 let language_server = language_server.clone();
9961 async move |this, cx| {
9962 let edit = language_server
9963 .request::<WillRenameFiles>(
9964 RenameFilesParams {
9965 files: vec![FileRename { old_uri, new_uri }],
9966 },
9967 request_timeout,
9968 )
9969 .await
9970 .into_response()
9971 .context("will rename files")
9972 .log_err()
9973 .flatten()?;
9974
9975 LocalLspStore::deserialize_workspace_edit(
9976 this.upgrade()?,
9977 edit,
9978 false,
9979 language_server.clone(),
9980 cx,
9981 )
9982 .await
9983 .ok()
9984 }
9985 });
9986 tasks.push(apply_edit);
9987 }
9988 Some(())
9989 })
9990 .ok()
9991 .flatten();
9992 let mut merged_transaction = ProjectTransaction::default();
9993 for task in tasks {
9994 // Await on tasks sequentially so that the order of application of edits is deterministic
9995 // (at least with regards to the order of registration of language servers)
9996 if let Some(transaction) = task.await {
9997 for (buffer, buffer_transaction) in transaction.0 {
9998 merged_transaction.0.insert(buffer, buffer_transaction);
9999 }
10000 }
10001 }
10002 merged_transaction
10003 })
10004 }
10005
10006 fn lsp_notify_abs_paths_changed(
10007 &mut self,
10008 server_id: LanguageServerId,
10009 changes: Vec<PathEvent>,
10010 ) {
10011 maybe!({
10012 let server = self.language_server_for_id(server_id)?;
10013 let changes = changes
10014 .into_iter()
10015 .filter_map(|event| {
10016 let typ = match event.kind? {
10017 PathEventKind::Created => lsp::FileChangeType::CREATED,
10018 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10019 PathEventKind::Changed | PathEventKind::Rescan => {
10020 lsp::FileChangeType::CHANGED
10021 }
10022 };
10023 Some(lsp::FileEvent {
10024 uri: file_path_to_lsp_url(&event.path).log_err()?,
10025 typ,
10026 })
10027 })
10028 .collect::<Vec<_>>();
10029 if !changes.is_empty() {
10030 server
10031 .notify::<lsp::notification::DidChangeWatchedFiles>(
10032 lsp::DidChangeWatchedFilesParams { changes },
10033 )
10034 .ok();
10035 }
10036 Some(())
10037 });
10038 }
10039
10040 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10041 self.as_local()?.language_server_for_id(id)
10042 }
10043
10044 fn on_lsp_progress(
10045 &mut self,
10046 progress_params: lsp::ProgressParams,
10047 language_server_id: LanguageServerId,
10048 disk_based_diagnostics_progress_token: Option<String>,
10049 cx: &mut Context<Self>,
10050 ) {
10051 match progress_params.value {
10052 lsp::ProgressParamsValue::WorkDone(progress) => {
10053 self.handle_work_done_progress(
10054 progress,
10055 language_server_id,
10056 disk_based_diagnostics_progress_token,
10057 ProgressToken::from_lsp(progress_params.token),
10058 cx,
10059 );
10060 }
10061 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10062 let registration_id = match progress_params.token {
10063 lsp::NumberOrString::Number(_) => None,
10064 lsp::NumberOrString::String(token) => token
10065 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10066 .map(|(_, id)| id.to_owned()),
10067 };
10068 if let Some(LanguageServerState::Running {
10069 workspace_diagnostics_refresh_tasks,
10070 ..
10071 }) = self
10072 .as_local_mut()
10073 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10074 && let Some(workspace_diagnostics) =
10075 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10076 {
10077 workspace_diagnostics.progress_tx.try_send(()).ok();
10078 self.apply_workspace_diagnostic_report(
10079 language_server_id,
10080 report,
10081 registration_id.map(SharedString::from),
10082 cx,
10083 )
10084 }
10085 }
10086 }
10087 }
10088
10089 fn handle_work_done_progress(
10090 &mut self,
10091 progress: lsp::WorkDoneProgress,
10092 language_server_id: LanguageServerId,
10093 disk_based_diagnostics_progress_token: Option<String>,
10094 token: ProgressToken,
10095 cx: &mut Context<Self>,
10096 ) {
10097 let language_server_status =
10098 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10099 status
10100 } else {
10101 return;
10102 };
10103
10104 if !language_server_status.progress_tokens.contains(&token) {
10105 return;
10106 }
10107
10108 let is_disk_based_diagnostics_progress =
10109 if let (Some(disk_based_token), ProgressToken::String(token)) =
10110 (&disk_based_diagnostics_progress_token, &token)
10111 {
10112 token.starts_with(disk_based_token)
10113 } else {
10114 false
10115 };
10116
10117 match progress {
10118 lsp::WorkDoneProgress::Begin(report) => {
10119 if is_disk_based_diagnostics_progress {
10120 self.disk_based_diagnostics_started(language_server_id, cx);
10121 }
10122 self.on_lsp_work_start(
10123 language_server_id,
10124 token.clone(),
10125 LanguageServerProgress {
10126 title: Some(report.title),
10127 is_disk_based_diagnostics_progress,
10128 is_cancellable: report.cancellable.unwrap_or(false),
10129 message: report.message.clone(),
10130 percentage: report.percentage.map(|p| p as usize),
10131 last_update_at: cx.background_executor().now(),
10132 },
10133 cx,
10134 );
10135 }
10136 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10137 language_server_id,
10138 token,
10139 LanguageServerProgress {
10140 title: None,
10141 is_disk_based_diagnostics_progress,
10142 is_cancellable: report.cancellable.unwrap_or(false),
10143 message: report.message,
10144 percentage: report.percentage.map(|p| p as usize),
10145 last_update_at: cx.background_executor().now(),
10146 },
10147 cx,
10148 ),
10149 lsp::WorkDoneProgress::End(_) => {
10150 language_server_status.progress_tokens.remove(&token);
10151 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10152 if is_disk_based_diagnostics_progress {
10153 self.disk_based_diagnostics_finished(language_server_id, cx);
10154 }
10155 }
10156 }
10157 }
10158
10159 fn on_lsp_work_start(
10160 &mut self,
10161 language_server_id: LanguageServerId,
10162 token: ProgressToken,
10163 progress: LanguageServerProgress,
10164 cx: &mut Context<Self>,
10165 ) {
10166 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10167 status.pending_work.insert(token.clone(), progress.clone());
10168 cx.notify();
10169 }
10170 cx.emit(LspStoreEvent::LanguageServerUpdate {
10171 language_server_id,
10172 name: self
10173 .language_server_adapter_for_id(language_server_id)
10174 .map(|adapter| adapter.name()),
10175 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10176 token: Some(token.to_proto()),
10177 title: progress.title,
10178 message: progress.message,
10179 percentage: progress.percentage.map(|p| p as u32),
10180 is_cancellable: Some(progress.is_cancellable),
10181 }),
10182 })
10183 }
10184
10185 fn on_lsp_work_progress(
10186 &mut self,
10187 language_server_id: LanguageServerId,
10188 token: ProgressToken,
10189 progress: LanguageServerProgress,
10190 cx: &mut Context<Self>,
10191 ) {
10192 let mut did_update = false;
10193 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10194 match status.pending_work.entry(token.clone()) {
10195 btree_map::Entry::Vacant(entry) => {
10196 entry.insert(progress.clone());
10197 did_update = true;
10198 }
10199 btree_map::Entry::Occupied(mut entry) => {
10200 let entry = entry.get_mut();
10201 if (progress.last_update_at - entry.last_update_at)
10202 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10203 {
10204 entry.last_update_at = progress.last_update_at;
10205 if progress.message.is_some() {
10206 entry.message = progress.message.clone();
10207 }
10208 if progress.percentage.is_some() {
10209 entry.percentage = progress.percentage;
10210 }
10211 if progress.is_cancellable != entry.is_cancellable {
10212 entry.is_cancellable = progress.is_cancellable;
10213 }
10214 did_update = true;
10215 }
10216 }
10217 }
10218 }
10219
10220 if did_update {
10221 cx.emit(LspStoreEvent::LanguageServerUpdate {
10222 language_server_id,
10223 name: self
10224 .language_server_adapter_for_id(language_server_id)
10225 .map(|adapter| adapter.name()),
10226 message: proto::update_language_server::Variant::WorkProgress(
10227 proto::LspWorkProgress {
10228 token: Some(token.to_proto()),
10229 message: progress.message,
10230 percentage: progress.percentage.map(|p| p as u32),
10231 is_cancellable: Some(progress.is_cancellable),
10232 },
10233 ),
10234 })
10235 }
10236 }
10237
10238 fn on_lsp_work_end(
10239 &mut self,
10240 language_server_id: LanguageServerId,
10241 token: ProgressToken,
10242 cx: &mut Context<Self>,
10243 ) {
10244 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10245 if let Some(work) = status.pending_work.remove(&token)
10246 && !work.is_disk_based_diagnostics_progress
10247 {
10248 cx.emit(LspStoreEvent::RefreshInlayHints {
10249 server_id: language_server_id,
10250 request_id: None,
10251 });
10252 }
10253 cx.notify();
10254 }
10255
10256 cx.emit(LspStoreEvent::LanguageServerUpdate {
10257 language_server_id,
10258 name: self
10259 .language_server_adapter_for_id(language_server_id)
10260 .map(|adapter| adapter.name()),
10261 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10262 token: Some(token.to_proto()),
10263 }),
10264 })
10265 }
10266
10267 pub async fn handle_resolve_completion_documentation(
10268 this: Entity<Self>,
10269 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10270 mut cx: AsyncApp,
10271 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10272 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10273
10274 let completion = this
10275 .read_with(&cx, |this, cx| {
10276 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10277 let server = this
10278 .language_server_for_id(id)
10279 .with_context(|| format!("No language server {id}"))?;
10280
10281 let request_timeout = ProjectSettings::get_global(cx)
10282 .global_lsp_settings
10283 .get_request_timeout();
10284
10285 anyhow::Ok(cx.background_spawn(async move {
10286 let can_resolve = server
10287 .capabilities()
10288 .completion_provider
10289 .as_ref()
10290 .and_then(|options| options.resolve_provider)
10291 .unwrap_or(false);
10292 if can_resolve {
10293 server
10294 .request::<lsp::request::ResolveCompletionItem>(
10295 lsp_completion,
10296 request_timeout,
10297 )
10298 .await
10299 .into_response()
10300 .context("resolve completion item")
10301 } else {
10302 anyhow::Ok(lsp_completion)
10303 }
10304 }))
10305 })?
10306 .await?;
10307
10308 let mut documentation_is_markdown = false;
10309 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10310 let documentation = match completion.documentation {
10311 Some(lsp::Documentation::String(text)) => text,
10312
10313 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10314 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10315 value
10316 }
10317
10318 _ => String::new(),
10319 };
10320
10321 // If we have a new buffer_id, that means we're talking to a new client
10322 // and want to check for new text_edits in the completion too.
10323 let mut old_replace_start = None;
10324 let mut old_replace_end = None;
10325 let mut old_insert_start = None;
10326 let mut old_insert_end = None;
10327 let mut new_text = String::default();
10328 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10329 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10330 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10331 anyhow::Ok(buffer.read(cx).snapshot())
10332 })?;
10333
10334 if let Some(text_edit) = completion.text_edit.as_ref() {
10335 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10336
10337 if let Some(mut edit) = edit {
10338 LineEnding::normalize(&mut edit.new_text);
10339
10340 new_text = edit.new_text;
10341 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10342 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10343 if let Some(insert_range) = edit.insert_range {
10344 old_insert_start = Some(serialize_anchor(&insert_range.start));
10345 old_insert_end = Some(serialize_anchor(&insert_range.end));
10346 }
10347 }
10348 }
10349 }
10350
10351 Ok(proto::ResolveCompletionDocumentationResponse {
10352 documentation,
10353 documentation_is_markdown,
10354 old_replace_start,
10355 old_replace_end,
10356 new_text,
10357 lsp_completion,
10358 old_insert_start,
10359 old_insert_end,
10360 })
10361 }
10362
10363 async fn handle_on_type_formatting(
10364 this: Entity<Self>,
10365 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10366 mut cx: AsyncApp,
10367 ) -> Result<proto::OnTypeFormattingResponse> {
10368 let on_type_formatting = this.update(&mut cx, |this, cx| {
10369 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10370 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10371 let position = envelope
10372 .payload
10373 .position
10374 .and_then(deserialize_anchor)
10375 .context("invalid position")?;
10376 anyhow::Ok(this.apply_on_type_formatting(
10377 buffer,
10378 position,
10379 envelope.payload.trigger.clone(),
10380 cx,
10381 ))
10382 })?;
10383
10384 let transaction = on_type_formatting
10385 .await?
10386 .as_ref()
10387 .map(language::proto::serialize_transaction);
10388 Ok(proto::OnTypeFormattingResponse { transaction })
10389 }
10390
10391 async fn handle_pull_workspace_diagnostics(
10392 lsp_store: Entity<Self>,
10393 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10394 mut cx: AsyncApp,
10395 ) -> Result<proto::Ack> {
10396 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10397 lsp_store.update(&mut cx, |lsp_store, _| {
10398 lsp_store.pull_workspace_diagnostics(server_id);
10399 });
10400 Ok(proto::Ack {})
10401 }
10402
10403 async fn handle_open_buffer_for_symbol(
10404 this: Entity<Self>,
10405 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10406 mut cx: AsyncApp,
10407 ) -> Result<proto::OpenBufferForSymbolResponse> {
10408 let peer_id = envelope.original_sender_id().unwrap_or_default();
10409 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10410 let symbol = Self::deserialize_symbol(symbol)?;
10411 this.read_with(&cx, |this, _| {
10412 if let SymbolLocation::OutsideProject {
10413 abs_path,
10414 signature,
10415 } = &symbol.path
10416 {
10417 let new_signature = this.symbol_signature(&abs_path);
10418 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10419 }
10420 Ok(())
10421 })?;
10422 let buffer = this
10423 .update(&mut cx, |this, cx| {
10424 this.open_buffer_for_symbol(
10425 &Symbol {
10426 language_server_name: symbol.language_server_name,
10427 source_worktree_id: symbol.source_worktree_id,
10428 source_language_server_id: symbol.source_language_server_id,
10429 path: symbol.path,
10430 name: symbol.name,
10431 kind: symbol.kind,
10432 range: symbol.range,
10433 label: CodeLabel::default(),
10434 container_name: symbol.container_name,
10435 },
10436 cx,
10437 )
10438 })
10439 .await?;
10440
10441 this.update(&mut cx, |this, cx| {
10442 let is_private = buffer
10443 .read(cx)
10444 .file()
10445 .map(|f| f.is_private())
10446 .unwrap_or_default();
10447 if is_private {
10448 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10449 } else {
10450 this.buffer_store
10451 .update(cx, |buffer_store, cx| {
10452 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10453 })
10454 .detach_and_log_err(cx);
10455 let buffer_id = buffer.read(cx).remote_id().to_proto();
10456 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10457 }
10458 })
10459 }
10460
10461 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10462 let mut hasher = Sha256::new();
10463 hasher.update(abs_path.to_string_lossy().as_bytes());
10464 hasher.update(self.nonce.to_be_bytes());
10465 hasher.finalize().as_slice().try_into().unwrap()
10466 }
10467
10468 pub async fn handle_get_project_symbols(
10469 this: Entity<Self>,
10470 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10471 mut cx: AsyncApp,
10472 ) -> Result<proto::GetProjectSymbolsResponse> {
10473 let symbols = this
10474 .update(&mut cx, |this, cx| {
10475 this.symbols(&envelope.payload.query, cx)
10476 })
10477 .await?;
10478
10479 Ok(proto::GetProjectSymbolsResponse {
10480 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10481 })
10482 }
10483
10484 pub async fn handle_restart_language_servers(
10485 this: Entity<Self>,
10486 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10487 mut cx: AsyncApp,
10488 ) -> Result<proto::Ack> {
10489 this.update(&mut cx, |lsp_store, cx| {
10490 let buffers =
10491 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10492 lsp_store.restart_language_servers_for_buffers(
10493 buffers,
10494 envelope
10495 .payload
10496 .only_servers
10497 .into_iter()
10498 .filter_map(|selector| {
10499 Some(match selector.selector? {
10500 proto::language_server_selector::Selector::ServerId(server_id) => {
10501 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10502 }
10503 proto::language_server_selector::Selector::Name(name) => {
10504 LanguageServerSelector::Name(LanguageServerName(
10505 SharedString::from(name),
10506 ))
10507 }
10508 })
10509 })
10510 .collect(),
10511 cx,
10512 );
10513 });
10514
10515 Ok(proto::Ack {})
10516 }
10517
10518 pub async fn handle_stop_language_servers(
10519 lsp_store: Entity<Self>,
10520 envelope: TypedEnvelope<proto::StopLanguageServers>,
10521 mut cx: AsyncApp,
10522 ) -> Result<proto::Ack> {
10523 lsp_store.update(&mut cx, |lsp_store, cx| {
10524 if envelope.payload.all
10525 && envelope.payload.also_servers.is_empty()
10526 && envelope.payload.buffer_ids.is_empty()
10527 {
10528 lsp_store.stop_all_language_servers(cx);
10529 } else {
10530 let buffers =
10531 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10532 lsp_store
10533 .stop_language_servers_for_buffers(
10534 buffers,
10535 envelope
10536 .payload
10537 .also_servers
10538 .into_iter()
10539 .filter_map(|selector| {
10540 Some(match selector.selector? {
10541 proto::language_server_selector::Selector::ServerId(
10542 server_id,
10543 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10544 server_id,
10545 )),
10546 proto::language_server_selector::Selector::Name(name) => {
10547 LanguageServerSelector::Name(LanguageServerName(
10548 SharedString::from(name),
10549 ))
10550 }
10551 })
10552 })
10553 .collect(),
10554 cx,
10555 )
10556 .detach_and_log_err(cx);
10557 }
10558 });
10559
10560 Ok(proto::Ack {})
10561 }
10562
10563 pub async fn handle_cancel_language_server_work(
10564 lsp_store: Entity<Self>,
10565 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10566 mut cx: AsyncApp,
10567 ) -> Result<proto::Ack> {
10568 lsp_store.update(&mut cx, |lsp_store, cx| {
10569 if let Some(work) = envelope.payload.work {
10570 match work {
10571 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10572 let buffers =
10573 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10574 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10575 }
10576 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10577 let server_id = LanguageServerId::from_proto(work.language_server_id);
10578 let token = work
10579 .token
10580 .map(|token| {
10581 ProgressToken::from_proto(token)
10582 .context("invalid work progress token")
10583 })
10584 .transpose()?;
10585 lsp_store.cancel_language_server_work(server_id, token, cx);
10586 }
10587 }
10588 }
10589 anyhow::Ok(())
10590 })?;
10591
10592 Ok(proto::Ack {})
10593 }
10594
10595 fn buffer_ids_to_buffers(
10596 &mut self,
10597 buffer_ids: impl Iterator<Item = u64>,
10598 cx: &mut Context<Self>,
10599 ) -> Vec<Entity<Buffer>> {
10600 buffer_ids
10601 .into_iter()
10602 .flat_map(|buffer_id| {
10603 self.buffer_store
10604 .read(cx)
10605 .get(BufferId::new(buffer_id).log_err()?)
10606 })
10607 .collect::<Vec<_>>()
10608 }
10609
10610 async fn handle_apply_additional_edits_for_completion(
10611 this: Entity<Self>,
10612 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10613 mut cx: AsyncApp,
10614 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10615 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10616 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10617 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10618 let completion = Self::deserialize_completion(
10619 envelope.payload.completion.context("invalid completion")?,
10620 )?;
10621 let all_commit_ranges = envelope
10622 .payload
10623 .all_commit_ranges
10624 .into_iter()
10625 .map(language::proto::deserialize_anchor_range)
10626 .collect::<Result<Vec<_>, _>>()?;
10627 anyhow::Ok((buffer, completion, all_commit_ranges))
10628 })?;
10629
10630 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10631 this.apply_additional_edits_for_completion(
10632 buffer,
10633 Rc::new(RefCell::new(Box::new([Completion {
10634 replace_range: completion.replace_range,
10635 new_text: completion.new_text,
10636 source: completion.source,
10637 documentation: None,
10638 label: CodeLabel::default(),
10639 match_start: None,
10640 snippet_deduplication_key: None,
10641 insert_text_mode: None,
10642 icon_path: None,
10643 confirm: None,
10644 }]))),
10645 0,
10646 false,
10647 all_commit_ranges,
10648 cx,
10649 )
10650 });
10651
10652 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10653 transaction: apply_additional_edits
10654 .await?
10655 .as_ref()
10656 .map(language::proto::serialize_transaction),
10657 })
10658 }
10659
10660 pub fn last_formatting_failure(&self) -> Option<&str> {
10661 self.last_formatting_failure.as_deref()
10662 }
10663
10664 pub fn reset_last_formatting_failure(&mut self) {
10665 self.last_formatting_failure = None;
10666 }
10667
10668 pub fn environment_for_buffer(
10669 &self,
10670 buffer: &Entity<Buffer>,
10671 cx: &mut Context<Self>,
10672 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10673 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10674 environment.update(cx, |env, cx| {
10675 env.buffer_environment(buffer, &self.worktree_store, cx)
10676 })
10677 } else {
10678 Task::ready(None).shared()
10679 }
10680 }
10681
10682 pub fn format(
10683 &mut self,
10684 buffers: HashSet<Entity<Buffer>>,
10685 target: LspFormatTarget,
10686 push_to_history: bool,
10687 trigger: FormatTrigger,
10688 cx: &mut Context<Self>,
10689 ) -> Task<anyhow::Result<ProjectTransaction>> {
10690 let logger = zlog::scoped!("format");
10691 if self.as_local().is_some() {
10692 zlog::trace!(logger => "Formatting locally");
10693 let logger = zlog::scoped!(logger => "local");
10694 let buffers = buffers
10695 .into_iter()
10696 .map(|buffer_handle| {
10697 let buffer = buffer_handle.read(cx);
10698 let buffer_abs_path = File::from_dyn(buffer.file())
10699 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10700
10701 (buffer_handle, buffer_abs_path, buffer.remote_id())
10702 })
10703 .collect::<Vec<_>>();
10704
10705 cx.spawn(async move |lsp_store, cx| {
10706 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10707
10708 for (handle, abs_path, id) in buffers {
10709 let env = lsp_store
10710 .update(cx, |lsp_store, cx| {
10711 lsp_store.environment_for_buffer(&handle, cx)
10712 })?
10713 .await;
10714
10715 let ranges = match &target {
10716 LspFormatTarget::Buffers => None,
10717 LspFormatTarget::Ranges(ranges) => {
10718 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10719 }
10720 };
10721
10722 formattable_buffers.push(FormattableBuffer {
10723 handle,
10724 abs_path,
10725 env,
10726 ranges,
10727 });
10728 }
10729 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10730
10731 let format_timer = zlog::time!(logger => "Formatting buffers");
10732 let result = LocalLspStore::format_locally(
10733 lsp_store.clone(),
10734 formattable_buffers,
10735 push_to_history,
10736 trigger,
10737 logger,
10738 cx,
10739 )
10740 .await;
10741 format_timer.end();
10742
10743 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10744
10745 lsp_store.update(cx, |lsp_store, _| {
10746 lsp_store.update_last_formatting_failure(&result);
10747 })?;
10748
10749 result
10750 })
10751 } else if let Some((client, project_id)) = self.upstream_client() {
10752 zlog::trace!(logger => "Formatting remotely");
10753 let logger = zlog::scoped!(logger => "remote");
10754
10755 let buffer_ranges = match &target {
10756 LspFormatTarget::Buffers => Vec::new(),
10757 LspFormatTarget::Ranges(ranges) => ranges
10758 .iter()
10759 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10760 buffer_id: buffer_id.to_proto(),
10761 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10762 })
10763 .collect(),
10764 };
10765
10766 let buffer_store = self.buffer_store();
10767 cx.spawn(async move |lsp_store, cx| {
10768 zlog::trace!(logger => "Sending remote format request");
10769 let request_timer = zlog::time!(logger => "remote format request");
10770 let result = client
10771 .request(proto::FormatBuffers {
10772 project_id,
10773 trigger: trigger as i32,
10774 buffer_ids: buffers
10775 .iter()
10776 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10777 .collect(),
10778 buffer_ranges,
10779 })
10780 .await
10781 .and_then(|result| result.transaction.context("missing transaction"));
10782 request_timer.end();
10783
10784 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10785
10786 lsp_store.update(cx, |lsp_store, _| {
10787 lsp_store.update_last_formatting_failure(&result);
10788 })?;
10789
10790 let transaction_response = result?;
10791 let _timer = zlog::time!(logger => "deserializing project transaction");
10792 buffer_store
10793 .update(cx, |buffer_store, cx| {
10794 buffer_store.deserialize_project_transaction(
10795 transaction_response,
10796 push_to_history,
10797 cx,
10798 )
10799 })
10800 .await
10801 })
10802 } else {
10803 zlog::trace!(logger => "Not formatting");
10804 Task::ready(Ok(ProjectTransaction::default()))
10805 }
10806 }
10807
10808 async fn handle_format_buffers(
10809 this: Entity<Self>,
10810 envelope: TypedEnvelope<proto::FormatBuffers>,
10811 mut cx: AsyncApp,
10812 ) -> Result<proto::FormatBuffersResponse> {
10813 let sender_id = envelope.original_sender_id().unwrap_or_default();
10814 let format = this.update(&mut cx, |this, cx| {
10815 let mut buffers = HashSet::default();
10816 for buffer_id in &envelope.payload.buffer_ids {
10817 let buffer_id = BufferId::new(*buffer_id)?;
10818 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10819 }
10820
10821 let target = if envelope.payload.buffer_ranges.is_empty() {
10822 LspFormatTarget::Buffers
10823 } else {
10824 let mut ranges_map = BTreeMap::new();
10825 for buffer_range in &envelope.payload.buffer_ranges {
10826 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10827 let ranges: Result<Vec<_>> = buffer_range
10828 .ranges
10829 .iter()
10830 .map(|range| {
10831 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10832 })
10833 .collect();
10834 ranges_map.insert(buffer_id, ranges?);
10835 }
10836 LspFormatTarget::Ranges(ranges_map)
10837 };
10838
10839 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10840 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10841 })?;
10842
10843 let project_transaction = format.await?;
10844 let project_transaction = this.update(&mut cx, |this, cx| {
10845 this.buffer_store.update(cx, |buffer_store, cx| {
10846 buffer_store.serialize_project_transaction_for_peer(
10847 project_transaction,
10848 sender_id,
10849 cx,
10850 )
10851 })
10852 });
10853 Ok(proto::FormatBuffersResponse {
10854 transaction: Some(project_transaction),
10855 })
10856 }
10857
10858 async fn handle_apply_code_action_kind(
10859 this: Entity<Self>,
10860 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10861 mut cx: AsyncApp,
10862 ) -> Result<proto::ApplyCodeActionKindResponse> {
10863 let sender_id = envelope.original_sender_id().unwrap_or_default();
10864 let format = this.update(&mut cx, |this, cx| {
10865 let mut buffers = HashSet::default();
10866 for buffer_id in &envelope.payload.buffer_ids {
10867 let buffer_id = BufferId::new(*buffer_id)?;
10868 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10869 }
10870 let kind = match envelope.payload.kind.as_str() {
10871 "" => CodeActionKind::EMPTY,
10872 "quickfix" => CodeActionKind::QUICKFIX,
10873 "refactor" => CodeActionKind::REFACTOR,
10874 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10875 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10876 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10877 "source" => CodeActionKind::SOURCE,
10878 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10879 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10880 _ => anyhow::bail!(
10881 "Invalid code action kind {}",
10882 envelope.payload.kind.as_str()
10883 ),
10884 };
10885 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10886 })?;
10887
10888 let project_transaction = format.await?;
10889 let project_transaction = this.update(&mut cx, |this, cx| {
10890 this.buffer_store.update(cx, |buffer_store, cx| {
10891 buffer_store.serialize_project_transaction_for_peer(
10892 project_transaction,
10893 sender_id,
10894 cx,
10895 )
10896 })
10897 });
10898 Ok(proto::ApplyCodeActionKindResponse {
10899 transaction: Some(project_transaction),
10900 })
10901 }
10902
10903 async fn shutdown_language_server(
10904 server_state: Option<LanguageServerState>,
10905 name: LanguageServerName,
10906 cx: &mut AsyncApp,
10907 ) {
10908 let server = match server_state {
10909 Some(LanguageServerState::Starting { startup, .. }) => {
10910 let mut timer = cx
10911 .background_executor()
10912 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10913 .fuse();
10914
10915 select! {
10916 server = startup.fuse() => server,
10917 () = timer => {
10918 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10919 None
10920 },
10921 }
10922 }
10923
10924 Some(LanguageServerState::Running { server, .. }) => Some(server),
10925
10926 None => None,
10927 };
10928
10929 let Some(server) = server else { return };
10930 if let Some(shutdown) = server.shutdown() {
10931 shutdown.await;
10932 }
10933 }
10934
10935 // Returns a list of all of the worktrees which no longer have a language server and the root path
10936 // for the stopped server
10937 fn stop_local_language_server(
10938 &mut self,
10939 server_id: LanguageServerId,
10940 cx: &mut Context<Self>,
10941 ) -> Task<()> {
10942 let local = match &mut self.mode {
10943 LspStoreMode::Local(local) => local,
10944 _ => {
10945 return Task::ready(());
10946 }
10947 };
10948
10949 // Remove this server ID from all entries in the given worktree.
10950 local
10951 .language_server_ids
10952 .retain(|_, state| state.id != server_id);
10953 self.buffer_store.update(cx, |buffer_store, cx| {
10954 for buffer in buffer_store.buffers() {
10955 buffer.update(cx, |buffer, cx| {
10956 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10957 buffer.set_completion_triggers(server_id, Default::default(), cx);
10958 });
10959 }
10960 });
10961
10962 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10963 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10964 summaries.retain(|path, summaries_by_server_id| {
10965 if summaries_by_server_id.remove(&server_id).is_some() {
10966 if let Some((client, project_id)) = self.downstream_client.clone() {
10967 client
10968 .send(proto::UpdateDiagnosticSummary {
10969 project_id,
10970 worktree_id: worktree_id.to_proto(),
10971 summary: Some(proto::DiagnosticSummary {
10972 path: path.as_ref().to_proto(),
10973 language_server_id: server_id.0 as u64,
10974 error_count: 0,
10975 warning_count: 0,
10976 }),
10977 more_summaries: Vec::new(),
10978 })
10979 .log_err();
10980 }
10981 cleared_paths.push(ProjectPath {
10982 worktree_id: *worktree_id,
10983 path: path.clone(),
10984 });
10985 !summaries_by_server_id.is_empty()
10986 } else {
10987 true
10988 }
10989 });
10990 }
10991 if !cleared_paths.is_empty() {
10992 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10993 server_id,
10994 paths: cleared_paths,
10995 });
10996 }
10997
10998 let local = self.as_local_mut().unwrap();
10999 for diagnostics in local.diagnostics.values_mut() {
11000 diagnostics.retain(|_, diagnostics_by_server_id| {
11001 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11002 diagnostics_by_server_id.remove(ix);
11003 !diagnostics_by_server_id.is_empty()
11004 } else {
11005 true
11006 }
11007 });
11008 }
11009 local.language_server_watched_paths.remove(&server_id);
11010
11011 let server_state = local.language_servers.remove(&server_id);
11012 self.cleanup_lsp_data(server_id);
11013 let name = self
11014 .language_server_statuses
11015 .remove(&server_id)
11016 .map(|status| status.name)
11017 .or_else(|| {
11018 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11019 Some(adapter.name())
11020 } else {
11021 None
11022 }
11023 });
11024
11025 if let Some(name) = name {
11026 log::info!("stopping language server {name}");
11027 self.languages
11028 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11029 cx.notify();
11030
11031 return cx.spawn(async move |lsp_store, cx| {
11032 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11033 lsp_store
11034 .update(cx, |lsp_store, cx| {
11035 lsp_store
11036 .languages
11037 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11038 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11039 cx.notify();
11040 })
11041 .ok();
11042 });
11043 }
11044
11045 if server_state.is_some() {
11046 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11047 }
11048 Task::ready(())
11049 }
11050
11051 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11052 self.shutdown_all_language_servers(cx).detach();
11053 }
11054
11055 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11056 if let Some((client, project_id)) = self.upstream_client() {
11057 let request = client.request(proto::StopLanguageServers {
11058 project_id,
11059 buffer_ids: Vec::new(),
11060 also_servers: Vec::new(),
11061 all: true,
11062 });
11063 cx.background_spawn(async move {
11064 request.await.ok();
11065 })
11066 } else {
11067 let Some(local) = self.as_local_mut() else {
11068 return Task::ready(());
11069 };
11070 let language_servers_to_stop = local
11071 .language_server_ids
11072 .values()
11073 .map(|state| state.id)
11074 .collect();
11075 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11076 let tasks = language_servers_to_stop
11077 .into_iter()
11078 .map(|server| self.stop_local_language_server(server, cx))
11079 .collect::<Vec<_>>();
11080 cx.background_spawn(async move {
11081 futures::future::join_all(tasks).await;
11082 })
11083 }
11084 }
11085
11086 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11087 let buffers = self.buffer_store.read(cx).buffers().collect();
11088 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11089 }
11090
11091 pub fn restart_language_servers_for_buffers(
11092 &mut self,
11093 buffers: Vec<Entity<Buffer>>,
11094 only_restart_servers: HashSet<LanguageServerSelector>,
11095 cx: &mut Context<Self>,
11096 ) {
11097 if let Some((client, project_id)) = self.upstream_client() {
11098 let request = client.request(proto::RestartLanguageServers {
11099 project_id,
11100 buffer_ids: buffers
11101 .into_iter()
11102 .map(|b| b.read(cx).remote_id().to_proto())
11103 .collect(),
11104 only_servers: only_restart_servers
11105 .into_iter()
11106 .map(|selector| {
11107 let selector = match selector {
11108 LanguageServerSelector::Id(language_server_id) => {
11109 proto::language_server_selector::Selector::ServerId(
11110 language_server_id.to_proto(),
11111 )
11112 }
11113 LanguageServerSelector::Name(language_server_name) => {
11114 proto::language_server_selector::Selector::Name(
11115 language_server_name.to_string(),
11116 )
11117 }
11118 };
11119 proto::LanguageServerSelector {
11120 selector: Some(selector),
11121 }
11122 })
11123 .collect(),
11124 all: false,
11125 });
11126 cx.background_spawn(request).detach_and_log_err(cx);
11127 } else {
11128 let stop_task = if only_restart_servers.is_empty() {
11129 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11130 } else {
11131 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11132 };
11133 cx.spawn(async move |lsp_store, cx| {
11134 stop_task.await;
11135 lsp_store.update(cx, |lsp_store, cx| {
11136 for buffer in buffers {
11137 lsp_store.register_buffer_with_language_servers(
11138 &buffer,
11139 only_restart_servers.clone(),
11140 true,
11141 cx,
11142 );
11143 }
11144 })
11145 })
11146 .detach();
11147 }
11148 }
11149
11150 pub fn stop_language_servers_for_buffers(
11151 &mut self,
11152 buffers: Vec<Entity<Buffer>>,
11153 also_stop_servers: HashSet<LanguageServerSelector>,
11154 cx: &mut Context<Self>,
11155 ) -> Task<Result<()>> {
11156 if let Some((client, project_id)) = self.upstream_client() {
11157 let request = client.request(proto::StopLanguageServers {
11158 project_id,
11159 buffer_ids: buffers
11160 .into_iter()
11161 .map(|b| b.read(cx).remote_id().to_proto())
11162 .collect(),
11163 also_servers: also_stop_servers
11164 .into_iter()
11165 .map(|selector| {
11166 let selector = match selector {
11167 LanguageServerSelector::Id(language_server_id) => {
11168 proto::language_server_selector::Selector::ServerId(
11169 language_server_id.to_proto(),
11170 )
11171 }
11172 LanguageServerSelector::Name(language_server_name) => {
11173 proto::language_server_selector::Selector::Name(
11174 language_server_name.to_string(),
11175 )
11176 }
11177 };
11178 proto::LanguageServerSelector {
11179 selector: Some(selector),
11180 }
11181 })
11182 .collect(),
11183 all: false,
11184 });
11185 cx.background_spawn(async move {
11186 let _ = request.await?;
11187 Ok(())
11188 })
11189 } else {
11190 let task =
11191 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11192 cx.background_spawn(async move {
11193 task.await;
11194 Ok(())
11195 })
11196 }
11197 }
11198
11199 fn stop_local_language_servers_for_buffers(
11200 &mut self,
11201 buffers: &[Entity<Buffer>],
11202 also_stop_servers: HashSet<LanguageServerSelector>,
11203 cx: &mut Context<Self>,
11204 ) -> Task<()> {
11205 let Some(local) = self.as_local_mut() else {
11206 return Task::ready(());
11207 };
11208 let mut language_server_names_to_stop = BTreeSet::default();
11209 let mut language_servers_to_stop = also_stop_servers
11210 .into_iter()
11211 .flat_map(|selector| match selector {
11212 LanguageServerSelector::Id(id) => Some(id),
11213 LanguageServerSelector::Name(name) => {
11214 language_server_names_to_stop.insert(name);
11215 None
11216 }
11217 })
11218 .collect::<BTreeSet<_>>();
11219
11220 let mut covered_worktrees = HashSet::default();
11221 for buffer in buffers {
11222 buffer.update(cx, |buffer, cx| {
11223 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11224 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11225 && covered_worktrees.insert(worktree_id)
11226 {
11227 language_server_names_to_stop.retain(|name| {
11228 let old_ids_count = language_servers_to_stop.len();
11229 let all_language_servers_with_this_name = local
11230 .language_server_ids
11231 .iter()
11232 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11233 language_servers_to_stop.extend(all_language_servers_with_this_name);
11234 old_ids_count == language_servers_to_stop.len()
11235 });
11236 }
11237 });
11238 }
11239 for name in language_server_names_to_stop {
11240 language_servers_to_stop.extend(
11241 local
11242 .language_server_ids
11243 .iter()
11244 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11245 );
11246 }
11247
11248 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11249 let tasks = language_servers_to_stop
11250 .into_iter()
11251 .map(|server| self.stop_local_language_server(server, cx))
11252 .collect::<Vec<_>>();
11253
11254 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11255 }
11256
11257 #[cfg(any(test, feature = "test-support"))]
11258 pub fn update_diagnostics(
11259 &mut self,
11260 server_id: LanguageServerId,
11261 diagnostics: lsp::PublishDiagnosticsParams,
11262 result_id: Option<SharedString>,
11263 source_kind: DiagnosticSourceKind,
11264 disk_based_sources: &[String],
11265 cx: &mut Context<Self>,
11266 ) -> Result<()> {
11267 self.merge_lsp_diagnostics(
11268 source_kind,
11269 vec![DocumentDiagnosticsUpdate {
11270 diagnostics,
11271 result_id,
11272 server_id,
11273 disk_based_sources: Cow::Borrowed(disk_based_sources),
11274 registration_id: None,
11275 }],
11276 |_, _, _| false,
11277 cx,
11278 )
11279 }
11280
11281 pub fn merge_lsp_diagnostics(
11282 &mut self,
11283 source_kind: DiagnosticSourceKind,
11284 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11285 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11286 cx: &mut Context<Self>,
11287 ) -> Result<()> {
11288 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11289 let updates = lsp_diagnostics
11290 .into_iter()
11291 .filter_map(|update| {
11292 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11293 Some(DocumentDiagnosticsUpdate {
11294 diagnostics: self.lsp_to_document_diagnostics(
11295 abs_path,
11296 source_kind,
11297 update.server_id,
11298 update.diagnostics,
11299 &update.disk_based_sources,
11300 update.registration_id.clone(),
11301 ),
11302 result_id: update.result_id,
11303 server_id: update.server_id,
11304 disk_based_sources: update.disk_based_sources,
11305 registration_id: update.registration_id,
11306 })
11307 })
11308 .collect();
11309 self.merge_diagnostic_entries(updates, merge, cx)?;
11310 Ok(())
11311 }
11312
11313 fn lsp_to_document_diagnostics(
11314 &mut self,
11315 document_abs_path: PathBuf,
11316 source_kind: DiagnosticSourceKind,
11317 server_id: LanguageServerId,
11318 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11319 disk_based_sources: &[String],
11320 registration_id: Option<SharedString>,
11321 ) -> DocumentDiagnostics {
11322 let mut diagnostics = Vec::default();
11323 let mut primary_diagnostic_group_ids = HashMap::default();
11324 let mut sources_by_group_id = HashMap::default();
11325 let mut supporting_diagnostics = HashMap::default();
11326
11327 let adapter = self.language_server_adapter_for_id(server_id);
11328
11329 // Ensure that primary diagnostics are always the most severe
11330 lsp_diagnostics
11331 .diagnostics
11332 .sort_by_key(|item| item.severity);
11333
11334 for diagnostic in &lsp_diagnostics.diagnostics {
11335 let source = diagnostic.source.as_ref();
11336 let range = range_from_lsp(diagnostic.range);
11337 let is_supporting = diagnostic
11338 .related_information
11339 .as_ref()
11340 .is_some_and(|infos| {
11341 infos.iter().any(|info| {
11342 primary_diagnostic_group_ids.contains_key(&(
11343 source,
11344 diagnostic.code.clone(),
11345 range_from_lsp(info.location.range),
11346 ))
11347 })
11348 });
11349
11350 let is_unnecessary = diagnostic
11351 .tags
11352 .as_ref()
11353 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11354
11355 let underline = self
11356 .language_server_adapter_for_id(server_id)
11357 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11358
11359 if is_supporting {
11360 supporting_diagnostics.insert(
11361 (source, diagnostic.code.clone(), range),
11362 (diagnostic.severity, is_unnecessary),
11363 );
11364 } else {
11365 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11366 let is_disk_based =
11367 source.is_some_and(|source| disk_based_sources.contains(source));
11368
11369 sources_by_group_id.insert(group_id, source);
11370 primary_diagnostic_group_ids
11371 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11372
11373 diagnostics.push(DiagnosticEntry {
11374 range,
11375 diagnostic: Diagnostic {
11376 source: diagnostic.source.clone(),
11377 source_kind,
11378 code: diagnostic.code.clone(),
11379 code_description: diagnostic
11380 .code_description
11381 .as_ref()
11382 .and_then(|d| d.href.clone()),
11383 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11384 markdown: adapter.as_ref().and_then(|adapter| {
11385 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11386 }),
11387 message: diagnostic.message.trim().to_string(),
11388 group_id,
11389 is_primary: true,
11390 is_disk_based,
11391 is_unnecessary,
11392 underline,
11393 data: diagnostic.data.clone(),
11394 registration_id: registration_id.clone(),
11395 },
11396 });
11397 if let Some(infos) = &diagnostic.related_information {
11398 for info in infos {
11399 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11400 let range = range_from_lsp(info.location.range);
11401 diagnostics.push(DiagnosticEntry {
11402 range,
11403 diagnostic: Diagnostic {
11404 source: diagnostic.source.clone(),
11405 source_kind,
11406 code: diagnostic.code.clone(),
11407 code_description: diagnostic
11408 .code_description
11409 .as_ref()
11410 .and_then(|d| d.href.clone()),
11411 severity: DiagnosticSeverity::INFORMATION,
11412 markdown: adapter.as_ref().and_then(|adapter| {
11413 adapter.diagnostic_message_to_markdown(&info.message)
11414 }),
11415 message: info.message.trim().to_string(),
11416 group_id,
11417 is_primary: false,
11418 is_disk_based,
11419 is_unnecessary: false,
11420 underline,
11421 data: diagnostic.data.clone(),
11422 registration_id: registration_id.clone(),
11423 },
11424 });
11425 }
11426 }
11427 }
11428 }
11429 }
11430
11431 for entry in &mut diagnostics {
11432 let diagnostic = &mut entry.diagnostic;
11433 if !diagnostic.is_primary {
11434 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11435 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11436 source,
11437 diagnostic.code.clone(),
11438 entry.range.clone(),
11439 )) {
11440 if let Some(severity) = severity {
11441 diagnostic.severity = severity;
11442 }
11443 diagnostic.is_unnecessary = is_unnecessary;
11444 }
11445 }
11446 }
11447
11448 DocumentDiagnostics {
11449 diagnostics,
11450 document_abs_path,
11451 version: lsp_diagnostics.version,
11452 }
11453 }
11454
11455 fn insert_newly_running_language_server(
11456 &mut self,
11457 adapter: Arc<CachedLspAdapter>,
11458 language_server: Arc<LanguageServer>,
11459 server_id: LanguageServerId,
11460 key: LanguageServerSeed,
11461 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11462 cx: &mut Context<Self>,
11463 ) {
11464 let Some(local) = self.as_local_mut() else {
11465 return;
11466 };
11467 // If the language server for this key doesn't match the server id, don't store the
11468 // server. Which will cause it to be dropped, killing the process
11469 if local
11470 .language_server_ids
11471 .get(&key)
11472 .map(|state| state.id != server_id)
11473 .unwrap_or(false)
11474 {
11475 return;
11476 }
11477
11478 // Update language_servers collection with Running variant of LanguageServerState
11479 // indicating that the server is up and running and ready
11480 let workspace_folders = workspace_folders.lock().clone();
11481 language_server.set_workspace_folders(workspace_folders);
11482
11483 let workspace_diagnostics_refresh_tasks = language_server
11484 .capabilities()
11485 .diagnostic_provider
11486 .and_then(|provider| {
11487 local
11488 .language_server_dynamic_registrations
11489 .entry(server_id)
11490 .or_default()
11491 .diagnostics
11492 .entry(None)
11493 .or_insert(provider.clone());
11494 let workspace_refresher =
11495 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11496
11497 Some((None, workspace_refresher))
11498 })
11499 .into_iter()
11500 .collect();
11501 local.language_servers.insert(
11502 server_id,
11503 LanguageServerState::Running {
11504 workspace_diagnostics_refresh_tasks,
11505 adapter: adapter.clone(),
11506 server: language_server.clone(),
11507 simulate_disk_based_diagnostics_completion: None,
11508 },
11509 );
11510 local
11511 .languages
11512 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11513 if let Some(file_ops_caps) = language_server
11514 .capabilities()
11515 .workspace
11516 .as_ref()
11517 .and_then(|ws| ws.file_operations.as_ref())
11518 {
11519 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11520 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11521 if did_rename_caps.or(will_rename_caps).is_some() {
11522 let watcher = RenamePathsWatchedForServer::default()
11523 .with_did_rename_patterns(did_rename_caps)
11524 .with_will_rename_patterns(will_rename_caps);
11525 local
11526 .language_server_paths_watched_for_rename
11527 .insert(server_id, watcher);
11528 }
11529 }
11530
11531 self.language_server_statuses.insert(
11532 server_id,
11533 LanguageServerStatus {
11534 name: language_server.name(),
11535 server_version: language_server.version(),
11536 server_readable_version: language_server.readable_version(),
11537 pending_work: Default::default(),
11538 has_pending_diagnostic_updates: false,
11539 progress_tokens: Default::default(),
11540 worktree: Some(key.worktree_id),
11541 binary: Some(language_server.binary().clone()),
11542 configuration: Some(language_server.configuration().clone()),
11543 workspace_folders: language_server.workspace_folders(),
11544 process_id: language_server.process_id(),
11545 },
11546 );
11547
11548 cx.emit(LspStoreEvent::LanguageServerAdded(
11549 server_id,
11550 language_server.name(),
11551 Some(key.worktree_id),
11552 ));
11553
11554 let server_capabilities = language_server.capabilities();
11555 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11556 downstream_client
11557 .send(proto::StartLanguageServer {
11558 project_id: *project_id,
11559 server: Some(proto::LanguageServer {
11560 id: server_id.to_proto(),
11561 name: language_server.name().to_string(),
11562 worktree_id: Some(key.worktree_id.to_proto()),
11563 }),
11564 capabilities: serde_json::to_string(&server_capabilities)
11565 .expect("serializing server LSP capabilities"),
11566 })
11567 .log_err();
11568 }
11569 self.lsp_server_capabilities
11570 .insert(server_id, server_capabilities);
11571
11572 // Tell the language server about every open buffer in the worktree that matches the language.
11573 // Also check for buffers in worktrees that reused this server
11574 let mut worktrees_using_server = vec![key.worktree_id];
11575 if let Some(local) = self.as_local() {
11576 // Find all worktrees that have this server in their language server tree
11577 for (worktree_id, servers) in &local.lsp_tree.instances {
11578 if *worktree_id != key.worktree_id {
11579 for server_map in servers.roots.values() {
11580 if server_map
11581 .values()
11582 .any(|(node, _)| node.id() == Some(server_id))
11583 {
11584 worktrees_using_server.push(*worktree_id);
11585 }
11586 }
11587 }
11588 }
11589 }
11590
11591 let mut buffer_paths_registered = Vec::new();
11592 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11593 let mut lsp_adapters = HashMap::default();
11594 for buffer_handle in buffer_store.buffers() {
11595 let buffer = buffer_handle.read(cx);
11596 let file = match File::from_dyn(buffer.file()) {
11597 Some(file) => file,
11598 None => continue,
11599 };
11600 let language = match buffer.language() {
11601 Some(language) => language,
11602 None => continue,
11603 };
11604
11605 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11606 || !lsp_adapters
11607 .entry(language.name())
11608 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11609 .iter()
11610 .any(|a| a.name == key.name)
11611 {
11612 continue;
11613 }
11614 // didOpen
11615 let file = match file.as_local() {
11616 Some(file) => file,
11617 None => continue,
11618 };
11619
11620 let local = self.as_local_mut().unwrap();
11621
11622 let buffer_id = buffer.remote_id();
11623 if local.registered_buffers.contains_key(&buffer_id) {
11624 let abs_path = file.abs_path(cx);
11625 let uri = match lsp::Uri::from_file_path(&abs_path) {
11626 Ok(uri) => uri,
11627 Err(()) => {
11628 log::error!("failed to convert path to URI: {:?}", abs_path);
11629 continue;
11630 }
11631 };
11632
11633 let versions = local
11634 .buffer_snapshots
11635 .entry(buffer_id)
11636 .or_default()
11637 .entry(server_id)
11638 .and_modify(|_| {
11639 assert!(
11640 false,
11641 "There should not be an existing snapshot for a newly inserted buffer"
11642 )
11643 })
11644 .or_insert_with(|| {
11645 vec![LspBufferSnapshot {
11646 version: 0,
11647 snapshot: buffer.text_snapshot(),
11648 }]
11649 });
11650
11651 let snapshot = versions.last().unwrap();
11652 let version = snapshot.version;
11653 let initial_snapshot = &snapshot.snapshot;
11654 language_server.register_buffer(
11655 uri,
11656 adapter.language_id(&language.name()),
11657 version,
11658 initial_snapshot.text(),
11659 );
11660 buffer_paths_registered.push((buffer_id, abs_path));
11661 local
11662 .buffers_opened_in_servers
11663 .entry(buffer_id)
11664 .or_default()
11665 .insert(server_id);
11666 }
11667 buffer_handle.update(cx, |buffer, cx| {
11668 buffer.set_completion_triggers(
11669 server_id,
11670 language_server
11671 .capabilities()
11672 .completion_provider
11673 .as_ref()
11674 .and_then(|provider| {
11675 provider
11676 .trigger_characters
11677 .as_ref()
11678 .map(|characters| characters.iter().cloned().collect())
11679 })
11680 .unwrap_or_default(),
11681 cx,
11682 )
11683 });
11684 }
11685 });
11686
11687 for (buffer_id, abs_path) in buffer_paths_registered {
11688 cx.emit(LspStoreEvent::LanguageServerUpdate {
11689 language_server_id: server_id,
11690 name: Some(adapter.name()),
11691 message: proto::update_language_server::Variant::RegisteredForBuffer(
11692 proto::RegisteredForBuffer {
11693 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11694 buffer_id: buffer_id.to_proto(),
11695 },
11696 ),
11697 });
11698 }
11699
11700 cx.notify();
11701 }
11702
11703 pub fn language_servers_running_disk_based_diagnostics(
11704 &self,
11705 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11706 self.language_server_statuses
11707 .iter()
11708 .filter_map(|(id, status)| {
11709 if status.has_pending_diagnostic_updates {
11710 Some(*id)
11711 } else {
11712 None
11713 }
11714 })
11715 }
11716
11717 pub(crate) fn cancel_language_server_work_for_buffers(
11718 &mut self,
11719 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11720 cx: &mut Context<Self>,
11721 ) {
11722 if let Some((client, project_id)) = self.upstream_client() {
11723 let request = client.request(proto::CancelLanguageServerWork {
11724 project_id,
11725 work: Some(proto::cancel_language_server_work::Work::Buffers(
11726 proto::cancel_language_server_work::Buffers {
11727 buffer_ids: buffers
11728 .into_iter()
11729 .map(|b| b.read(cx).remote_id().to_proto())
11730 .collect(),
11731 },
11732 )),
11733 });
11734 cx.background_spawn(request).detach_and_log_err(cx);
11735 } else if let Some(local) = self.as_local() {
11736 let servers = buffers
11737 .into_iter()
11738 .flat_map(|buffer| {
11739 buffer.update(cx, |buffer, cx| {
11740 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11741 })
11742 })
11743 .collect::<HashSet<_>>();
11744 for server_id in servers {
11745 self.cancel_language_server_work(server_id, None, cx);
11746 }
11747 }
11748 }
11749
11750 pub(crate) fn cancel_language_server_work(
11751 &mut self,
11752 server_id: LanguageServerId,
11753 token_to_cancel: Option<ProgressToken>,
11754 cx: &mut Context<Self>,
11755 ) {
11756 if let Some(local) = self.as_local() {
11757 let status = self.language_server_statuses.get(&server_id);
11758 let server = local.language_servers.get(&server_id);
11759 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11760 {
11761 for (token, progress) in &status.pending_work {
11762 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11763 && token != token_to_cancel
11764 {
11765 continue;
11766 }
11767 if progress.is_cancellable {
11768 server
11769 .notify::<lsp::notification::WorkDoneProgressCancel>(
11770 WorkDoneProgressCancelParams {
11771 token: token.to_lsp(),
11772 },
11773 )
11774 .ok();
11775 }
11776 }
11777 }
11778 } else if let Some((client, project_id)) = self.upstream_client() {
11779 let request = client.request(proto::CancelLanguageServerWork {
11780 project_id,
11781 work: Some(
11782 proto::cancel_language_server_work::Work::LanguageServerWork(
11783 proto::cancel_language_server_work::LanguageServerWork {
11784 language_server_id: server_id.to_proto(),
11785 token: token_to_cancel.map(|token| token.to_proto()),
11786 },
11787 ),
11788 ),
11789 });
11790 cx.background_spawn(request).detach_and_log_err(cx);
11791 }
11792 }
11793
11794 fn register_supplementary_language_server(
11795 &mut self,
11796 id: LanguageServerId,
11797 name: LanguageServerName,
11798 server: Arc<LanguageServer>,
11799 cx: &mut Context<Self>,
11800 ) {
11801 if let Some(local) = self.as_local_mut() {
11802 local
11803 .supplementary_language_servers
11804 .insert(id, (name.clone(), server));
11805 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11806 }
11807 }
11808
11809 fn unregister_supplementary_language_server(
11810 &mut self,
11811 id: LanguageServerId,
11812 cx: &mut Context<Self>,
11813 ) {
11814 if let Some(local) = self.as_local_mut() {
11815 local.supplementary_language_servers.remove(&id);
11816 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11817 }
11818 }
11819
11820 pub(crate) fn supplementary_language_servers(
11821 &self,
11822 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11823 self.as_local().into_iter().flat_map(|local| {
11824 local
11825 .supplementary_language_servers
11826 .iter()
11827 .map(|(id, (name, _))| (*id, name.clone()))
11828 })
11829 }
11830
11831 pub fn language_server_adapter_for_id(
11832 &self,
11833 id: LanguageServerId,
11834 ) -> Option<Arc<CachedLspAdapter>> {
11835 self.as_local()
11836 .and_then(|local| local.language_servers.get(&id))
11837 .and_then(|language_server_state| match language_server_state {
11838 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11839 _ => None,
11840 })
11841 }
11842
11843 pub(super) fn update_local_worktree_language_servers(
11844 &mut self,
11845 worktree_handle: &Entity<Worktree>,
11846 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11847 cx: &mut Context<Self>,
11848 ) {
11849 if changes.is_empty() {
11850 return;
11851 }
11852
11853 let Some(local) = self.as_local() else { return };
11854
11855 local.prettier_store.update(cx, |prettier_store, cx| {
11856 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11857 });
11858
11859 let worktree_id = worktree_handle.read(cx).id();
11860 let mut language_server_ids = local
11861 .language_server_ids
11862 .iter()
11863 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11864 .collect::<Vec<_>>();
11865 language_server_ids.sort();
11866 language_server_ids.dedup();
11867
11868 // let abs_path = worktree_handle.read(cx).abs_path();
11869 for server_id in &language_server_ids {
11870 if let Some(LanguageServerState::Running { server, .. }) =
11871 local.language_servers.get(server_id)
11872 && let Some(watched_paths) = local
11873 .language_server_watched_paths
11874 .get(server_id)
11875 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11876 {
11877 let params = lsp::DidChangeWatchedFilesParams {
11878 changes: changes
11879 .iter()
11880 .filter_map(|(path, _, change)| {
11881 if !watched_paths.is_match(path.as_std_path()) {
11882 return None;
11883 }
11884 let typ = match change {
11885 PathChange::Loaded => return None,
11886 PathChange::Added => lsp::FileChangeType::CREATED,
11887 PathChange::Removed => lsp::FileChangeType::DELETED,
11888 PathChange::Updated => lsp::FileChangeType::CHANGED,
11889 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11890 };
11891 let uri = lsp::Uri::from_file_path(
11892 worktree_handle.read(cx).absolutize(&path),
11893 )
11894 .ok()?;
11895 Some(lsp::FileEvent { uri, typ })
11896 })
11897 .collect(),
11898 };
11899 if !params.changes.is_empty() {
11900 server
11901 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11902 .ok();
11903 }
11904 }
11905 }
11906 for (path, _, _) in changes {
11907 if let Some(file_name) = path.file_name()
11908 && local.watched_manifest_filenames.contains(file_name)
11909 {
11910 self.request_workspace_config_refresh();
11911 break;
11912 }
11913 }
11914 }
11915
11916 pub fn wait_for_remote_buffer(
11917 &mut self,
11918 id: BufferId,
11919 cx: &mut Context<Self>,
11920 ) -> Task<Result<Entity<Buffer>>> {
11921 self.buffer_store.update(cx, |buffer_store, cx| {
11922 buffer_store.wait_for_remote_buffer(id, cx)
11923 })
11924 }
11925
11926 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11927 let mut result = proto::Symbol {
11928 language_server_name: symbol.language_server_name.0.to_string(),
11929 source_worktree_id: symbol.source_worktree_id.to_proto(),
11930 language_server_id: symbol.source_language_server_id.to_proto(),
11931 name: symbol.name.clone(),
11932 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11933 start: Some(proto::PointUtf16 {
11934 row: symbol.range.start.0.row,
11935 column: symbol.range.start.0.column,
11936 }),
11937 end: Some(proto::PointUtf16 {
11938 row: symbol.range.end.0.row,
11939 column: symbol.range.end.0.column,
11940 }),
11941 worktree_id: Default::default(),
11942 path: Default::default(),
11943 signature: Default::default(),
11944 container_name: symbol.container_name.clone(),
11945 };
11946 match &symbol.path {
11947 SymbolLocation::InProject(path) => {
11948 result.worktree_id = path.worktree_id.to_proto();
11949 result.path = path.path.to_proto();
11950 }
11951 SymbolLocation::OutsideProject {
11952 abs_path,
11953 signature,
11954 } => {
11955 result.path = abs_path.to_string_lossy().into_owned();
11956 result.signature = signature.to_vec();
11957 }
11958 }
11959 result
11960 }
11961
11962 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11963 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11964 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11965 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11966
11967 let path = if serialized_symbol.signature.is_empty() {
11968 SymbolLocation::InProject(ProjectPath {
11969 worktree_id,
11970 path: RelPath::from_proto(&serialized_symbol.path)
11971 .context("invalid symbol path")?,
11972 })
11973 } else {
11974 SymbolLocation::OutsideProject {
11975 abs_path: Path::new(&serialized_symbol.path).into(),
11976 signature: serialized_symbol
11977 .signature
11978 .try_into()
11979 .map_err(|_| anyhow!("invalid signature"))?,
11980 }
11981 };
11982
11983 let start = serialized_symbol.start.context("invalid start")?;
11984 let end = serialized_symbol.end.context("invalid end")?;
11985 Ok(CoreSymbol {
11986 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11987 source_worktree_id,
11988 source_language_server_id: LanguageServerId::from_proto(
11989 serialized_symbol.language_server_id,
11990 ),
11991 path,
11992 name: serialized_symbol.name,
11993 range: Unclipped(PointUtf16::new(start.row, start.column))
11994 ..Unclipped(PointUtf16::new(end.row, end.column)),
11995 kind,
11996 container_name: serialized_symbol.container_name,
11997 })
11998 }
11999
12000 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12001 let mut serialized_completion = proto::Completion {
12002 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12003 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12004 new_text: completion.new_text.clone(),
12005 ..proto::Completion::default()
12006 };
12007 match &completion.source {
12008 CompletionSource::Lsp {
12009 insert_range,
12010 server_id,
12011 lsp_completion,
12012 lsp_defaults,
12013 resolved,
12014 } => {
12015 let (old_insert_start, old_insert_end) = insert_range
12016 .as_ref()
12017 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12018 .unzip();
12019
12020 serialized_completion.old_insert_start = old_insert_start;
12021 serialized_completion.old_insert_end = old_insert_end;
12022 serialized_completion.source = proto::completion::Source::Lsp as i32;
12023 serialized_completion.server_id = server_id.0 as u64;
12024 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12025 serialized_completion.lsp_defaults = lsp_defaults
12026 .as_deref()
12027 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12028 serialized_completion.resolved = *resolved;
12029 }
12030 CompletionSource::BufferWord {
12031 word_range,
12032 resolved,
12033 } => {
12034 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12035 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12036 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12037 serialized_completion.resolved = *resolved;
12038 }
12039 CompletionSource::Custom => {
12040 serialized_completion.source = proto::completion::Source::Custom as i32;
12041 serialized_completion.resolved = true;
12042 }
12043 CompletionSource::Dap { sort_text } => {
12044 serialized_completion.source = proto::completion::Source::Dap as i32;
12045 serialized_completion.sort_text = Some(sort_text.clone());
12046 }
12047 }
12048
12049 serialized_completion
12050 }
12051
12052 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12053 let old_replace_start = completion
12054 .old_replace_start
12055 .and_then(deserialize_anchor)
12056 .context("invalid old start")?;
12057 let old_replace_end = completion
12058 .old_replace_end
12059 .and_then(deserialize_anchor)
12060 .context("invalid old end")?;
12061 let insert_range = {
12062 match completion.old_insert_start.zip(completion.old_insert_end) {
12063 Some((start, end)) => {
12064 let start = deserialize_anchor(start).context("invalid insert old start")?;
12065 let end = deserialize_anchor(end).context("invalid insert old end")?;
12066 Some(start..end)
12067 }
12068 None => None,
12069 }
12070 };
12071 Ok(CoreCompletion {
12072 replace_range: old_replace_start..old_replace_end,
12073 new_text: completion.new_text,
12074 source: match proto::completion::Source::from_i32(completion.source) {
12075 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12076 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12077 insert_range,
12078 server_id: LanguageServerId::from_proto(completion.server_id),
12079 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12080 lsp_defaults: completion
12081 .lsp_defaults
12082 .as_deref()
12083 .map(serde_json::from_slice)
12084 .transpose()?,
12085 resolved: completion.resolved,
12086 },
12087 Some(proto::completion::Source::BufferWord) => {
12088 let word_range = completion
12089 .buffer_word_start
12090 .and_then(deserialize_anchor)
12091 .context("invalid buffer word start")?
12092 ..completion
12093 .buffer_word_end
12094 .and_then(deserialize_anchor)
12095 .context("invalid buffer word end")?;
12096 CompletionSource::BufferWord {
12097 word_range,
12098 resolved: completion.resolved,
12099 }
12100 }
12101 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12102 sort_text: completion
12103 .sort_text
12104 .context("expected sort text to exist")?,
12105 },
12106 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12107 },
12108 })
12109 }
12110
12111 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12112 let (kind, lsp_action) = match &action.lsp_action {
12113 LspAction::Action(code_action) => (
12114 proto::code_action::Kind::Action as i32,
12115 serde_json::to_vec(code_action).unwrap(),
12116 ),
12117 LspAction::Command(command) => (
12118 proto::code_action::Kind::Command as i32,
12119 serde_json::to_vec(command).unwrap(),
12120 ),
12121 LspAction::CodeLens(code_lens) => (
12122 proto::code_action::Kind::CodeLens as i32,
12123 serde_json::to_vec(code_lens).unwrap(),
12124 ),
12125 };
12126
12127 proto::CodeAction {
12128 server_id: action.server_id.0 as u64,
12129 start: Some(serialize_anchor(&action.range.start)),
12130 end: Some(serialize_anchor(&action.range.end)),
12131 lsp_action,
12132 kind,
12133 resolved: action.resolved,
12134 }
12135 }
12136
12137 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12138 let start = action
12139 .start
12140 .and_then(deserialize_anchor)
12141 .context("invalid start")?;
12142 let end = action
12143 .end
12144 .and_then(deserialize_anchor)
12145 .context("invalid end")?;
12146 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12147 Some(proto::code_action::Kind::Action) => {
12148 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12149 }
12150 Some(proto::code_action::Kind::Command) => {
12151 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12152 }
12153 Some(proto::code_action::Kind::CodeLens) => {
12154 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12155 }
12156 None => anyhow::bail!("Unknown action kind {}", action.kind),
12157 };
12158 Ok(CodeAction {
12159 server_id: LanguageServerId(action.server_id as usize),
12160 range: start..end,
12161 resolved: action.resolved,
12162 lsp_action,
12163 })
12164 }
12165
12166 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12167 match &formatting_result {
12168 Ok(_) => self.last_formatting_failure = None,
12169 Err(error) => {
12170 let error_string = format!("{error:#}");
12171 log::error!("Formatting failed: {error_string}");
12172 self.last_formatting_failure
12173 .replace(error_string.lines().join(" "));
12174 }
12175 }
12176 }
12177
12178 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12179 self.lsp_server_capabilities.remove(&for_server);
12180 self.semantic_token_config.remove_server_data(for_server);
12181 for lsp_data in self.lsp_data.values_mut() {
12182 lsp_data.remove_server_data(for_server);
12183 }
12184 if let Some(local) = self.as_local_mut() {
12185 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12186 local
12187 .workspace_pull_diagnostics_result_ids
12188 .remove(&for_server);
12189 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12190 buffer_servers.remove(&for_server);
12191 }
12192 }
12193 }
12194
12195 pub fn result_id_for_buffer_pull(
12196 &self,
12197 server_id: LanguageServerId,
12198 buffer_id: BufferId,
12199 registration_id: &Option<SharedString>,
12200 cx: &App,
12201 ) -> Option<SharedString> {
12202 let abs_path = self
12203 .buffer_store
12204 .read(cx)
12205 .get(buffer_id)
12206 .and_then(|b| File::from_dyn(b.read(cx).file()))
12207 .map(|f| f.abs_path(cx))?;
12208 self.as_local()?
12209 .buffer_pull_diagnostics_result_ids
12210 .get(&server_id)?
12211 .get(registration_id)?
12212 .get(&abs_path)?
12213 .clone()
12214 }
12215
12216 /// Gets all result_ids for a workspace diagnostics pull request.
12217 /// 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.
12218 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12219 pub fn result_ids_for_workspace_refresh(
12220 &self,
12221 server_id: LanguageServerId,
12222 registration_id: &Option<SharedString>,
12223 ) -> HashMap<PathBuf, SharedString> {
12224 let Some(local) = self.as_local() else {
12225 return HashMap::default();
12226 };
12227 local
12228 .workspace_pull_diagnostics_result_ids
12229 .get(&server_id)
12230 .into_iter()
12231 .filter_map(|diagnostics| diagnostics.get(registration_id))
12232 .flatten()
12233 .filter_map(|(abs_path, result_id)| {
12234 let result_id = local
12235 .buffer_pull_diagnostics_result_ids
12236 .get(&server_id)
12237 .and_then(|buffer_ids_result_ids| {
12238 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12239 })
12240 .cloned()
12241 .flatten()
12242 .or_else(|| result_id.clone())?;
12243 Some((abs_path.clone(), result_id))
12244 })
12245 .collect()
12246 }
12247
12248 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12249 if let Some(LanguageServerState::Running {
12250 workspace_diagnostics_refresh_tasks,
12251 ..
12252 }) = self
12253 .as_local_mut()
12254 .and_then(|local| local.language_servers.get_mut(&server_id))
12255 {
12256 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12257 diagnostics.refresh_tx.try_send(()).ok();
12258 }
12259 }
12260 }
12261
12262 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12263 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12264 /// which requires refreshing both workspace and document diagnostics.
12265 pub fn pull_document_diagnostics_for_server(
12266 &mut self,
12267 server_id: LanguageServerId,
12268 source_buffer_id: Option<BufferId>,
12269 cx: &mut Context<Self>,
12270 ) -> Shared<Task<()>> {
12271 let Some(local) = self.as_local_mut() else {
12272 return Task::ready(()).shared();
12273 };
12274 let mut buffers_to_refresh = HashSet::default();
12275 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12276 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12277 buffers_to_refresh.insert(*buffer_id);
12278 }
12279 }
12280
12281 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12282 }
12283
12284 pub fn pull_document_diagnostics_for_buffer_edit(
12285 &mut self,
12286 buffer_id: BufferId,
12287 cx: &mut Context<Self>,
12288 ) {
12289 let Some(local) = self.as_local_mut() else {
12290 return;
12291 };
12292 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12293 else {
12294 return;
12295 };
12296 for server_id in languages_servers {
12297 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12298 }
12299 }
12300
12301 fn apply_workspace_diagnostic_report(
12302 &mut self,
12303 server_id: LanguageServerId,
12304 report: lsp::WorkspaceDiagnosticReportResult,
12305 registration_id: Option<SharedString>,
12306 cx: &mut Context<Self>,
12307 ) {
12308 let mut workspace_diagnostics =
12309 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12310 report,
12311 server_id,
12312 registration_id,
12313 );
12314 workspace_diagnostics.retain(|d| match &d.diagnostics {
12315 LspPullDiagnostics::Response {
12316 server_id,
12317 registration_id,
12318 ..
12319 } => self.diagnostic_registration_exists(*server_id, registration_id),
12320 LspPullDiagnostics::Default => false,
12321 });
12322 let mut unchanged_buffers = HashMap::default();
12323 let workspace_diagnostics_updates = workspace_diagnostics
12324 .into_iter()
12325 .filter_map(
12326 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12327 LspPullDiagnostics::Response {
12328 server_id,
12329 uri,
12330 diagnostics,
12331 registration_id,
12332 } => Some((
12333 server_id,
12334 uri,
12335 diagnostics,
12336 workspace_diagnostics.version,
12337 registration_id,
12338 )),
12339 LspPullDiagnostics::Default => None,
12340 },
12341 )
12342 .fold(
12343 HashMap::default(),
12344 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12345 let (result_id, diagnostics) = match diagnostics {
12346 PulledDiagnostics::Unchanged { result_id } => {
12347 unchanged_buffers
12348 .entry(new_registration_id.clone())
12349 .or_insert_with(HashSet::default)
12350 .insert(uri.clone());
12351 (Some(result_id), Vec::new())
12352 }
12353 PulledDiagnostics::Changed {
12354 result_id,
12355 diagnostics,
12356 } => (result_id, diagnostics),
12357 };
12358 let disk_based_sources = Cow::Owned(
12359 self.language_server_adapter_for_id(server_id)
12360 .as_ref()
12361 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12362 .unwrap_or(&[])
12363 .to_vec(),
12364 );
12365
12366 let Some(abs_path) = uri.to_file_path().ok() else {
12367 return acc;
12368 };
12369 let Some((worktree, relative_path)) =
12370 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12371 else {
12372 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12373 return acc;
12374 };
12375 let worktree_id = worktree.read(cx).id();
12376 let project_path = ProjectPath {
12377 worktree_id,
12378 path: relative_path,
12379 };
12380 if let Some(local_lsp_store) = self.as_local_mut() {
12381 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12382 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12383 }
12384 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12385 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12386 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12387 acc.entry(server_id)
12388 .or_insert_with(HashMap::default)
12389 .entry(new_registration_id.clone())
12390 .or_insert_with(Vec::new)
12391 .push(DocumentDiagnosticsUpdate {
12392 server_id,
12393 diagnostics: lsp::PublishDiagnosticsParams {
12394 uri,
12395 diagnostics,
12396 version,
12397 },
12398 result_id: result_id.map(SharedString::new),
12399 disk_based_sources,
12400 registration_id: new_registration_id,
12401 });
12402 }
12403 acc
12404 },
12405 );
12406
12407 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12408 for (registration_id, diagnostic_updates) in diagnostic_updates {
12409 self.merge_lsp_diagnostics(
12410 DiagnosticSourceKind::Pulled,
12411 diagnostic_updates,
12412 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12413 DiagnosticSourceKind::Pulled => {
12414 old_diagnostic.registration_id != registration_id
12415 || unchanged_buffers
12416 .get(&old_diagnostic.registration_id)
12417 .is_some_and(|unchanged_buffers| {
12418 unchanged_buffers.contains(&document_uri)
12419 })
12420 }
12421 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12422 },
12423 cx,
12424 )
12425 .log_err();
12426 }
12427 }
12428 }
12429
12430 fn register_server_capabilities(
12431 &mut self,
12432 server_id: LanguageServerId,
12433 params: lsp::RegistrationParams,
12434 cx: &mut Context<Self>,
12435 ) -> anyhow::Result<()> {
12436 let server = self
12437 .language_server_for_id(server_id)
12438 .with_context(|| format!("no server {server_id} found"))?;
12439 for reg in params.registrations {
12440 match reg.method.as_str() {
12441 "workspace/didChangeWatchedFiles" => {
12442 if let Some(options) = reg.register_options {
12443 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12444 let caps = serde_json::from_value(options)?;
12445 local_lsp_store
12446 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12447 true
12448 } else {
12449 false
12450 };
12451 if notify {
12452 notify_server_capabilities_updated(&server, cx);
12453 }
12454 }
12455 }
12456 "workspace/didChangeConfiguration" => {
12457 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12458 }
12459 "workspace/didChangeWorkspaceFolders" => {
12460 // In this case register options is an empty object, we can ignore it
12461 let caps = lsp::WorkspaceFoldersServerCapabilities {
12462 supported: Some(true),
12463 change_notifications: Some(OneOf::Right(reg.id)),
12464 };
12465 server.update_capabilities(|capabilities| {
12466 capabilities
12467 .workspace
12468 .get_or_insert_default()
12469 .workspace_folders = Some(caps);
12470 });
12471 notify_server_capabilities_updated(&server, cx);
12472 }
12473 "workspace/symbol" => {
12474 let options = parse_register_capabilities(reg)?;
12475 server.update_capabilities(|capabilities| {
12476 capabilities.workspace_symbol_provider = Some(options);
12477 });
12478 notify_server_capabilities_updated(&server, cx);
12479 }
12480 "workspace/fileOperations" => {
12481 if let Some(options) = reg.register_options {
12482 let caps = serde_json::from_value(options)?;
12483 server.update_capabilities(|capabilities| {
12484 capabilities
12485 .workspace
12486 .get_or_insert_default()
12487 .file_operations = Some(caps);
12488 });
12489 notify_server_capabilities_updated(&server, cx);
12490 }
12491 }
12492 "workspace/executeCommand" => {
12493 if let Some(options) = reg.register_options {
12494 let options = serde_json::from_value(options)?;
12495 server.update_capabilities(|capabilities| {
12496 capabilities.execute_command_provider = Some(options);
12497 });
12498 notify_server_capabilities_updated(&server, cx);
12499 }
12500 }
12501 "textDocument/rangeFormatting" => {
12502 let options = parse_register_capabilities(reg)?;
12503 server.update_capabilities(|capabilities| {
12504 capabilities.document_range_formatting_provider = Some(options);
12505 });
12506 notify_server_capabilities_updated(&server, cx);
12507 }
12508 "textDocument/onTypeFormatting" => {
12509 if let Some(options) = reg
12510 .register_options
12511 .map(serde_json::from_value)
12512 .transpose()?
12513 {
12514 server.update_capabilities(|capabilities| {
12515 capabilities.document_on_type_formatting_provider = Some(options);
12516 });
12517 notify_server_capabilities_updated(&server, cx);
12518 }
12519 }
12520 "textDocument/formatting" => {
12521 let options = parse_register_capabilities(reg)?;
12522 server.update_capabilities(|capabilities| {
12523 capabilities.document_formatting_provider = Some(options);
12524 });
12525 notify_server_capabilities_updated(&server, cx);
12526 }
12527 "textDocument/rename" => {
12528 let options = parse_register_capabilities(reg)?;
12529 server.update_capabilities(|capabilities| {
12530 capabilities.rename_provider = Some(options);
12531 });
12532 notify_server_capabilities_updated(&server, cx);
12533 }
12534 "textDocument/inlayHint" => {
12535 let options = parse_register_capabilities(reg)?;
12536 server.update_capabilities(|capabilities| {
12537 capabilities.inlay_hint_provider = Some(options);
12538 });
12539 notify_server_capabilities_updated(&server, cx);
12540 }
12541 "textDocument/documentSymbol" => {
12542 let options = parse_register_capabilities(reg)?;
12543 server.update_capabilities(|capabilities| {
12544 capabilities.document_symbol_provider = Some(options);
12545 });
12546 notify_server_capabilities_updated(&server, cx);
12547 }
12548 "textDocument/codeAction" => {
12549 let options = parse_register_capabilities(reg)?;
12550 let provider = match options {
12551 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12552 OneOf::Right(caps) => caps,
12553 };
12554 server.update_capabilities(|capabilities| {
12555 capabilities.code_action_provider = Some(provider);
12556 });
12557 notify_server_capabilities_updated(&server, cx);
12558 }
12559 "textDocument/definition" => {
12560 let options = parse_register_capabilities(reg)?;
12561 server.update_capabilities(|capabilities| {
12562 capabilities.definition_provider = Some(options);
12563 });
12564 notify_server_capabilities_updated(&server, cx);
12565 }
12566 "textDocument/completion" => {
12567 if let Some(caps) = reg
12568 .register_options
12569 .map(serde_json::from_value::<CompletionOptions>)
12570 .transpose()?
12571 {
12572 server.update_capabilities(|capabilities| {
12573 capabilities.completion_provider = Some(caps.clone());
12574 });
12575
12576 if let Some(local) = self.as_local() {
12577 let mut buffers_with_language_server = Vec::new();
12578 for handle in self.buffer_store.read(cx).buffers() {
12579 let buffer_id = handle.read(cx).remote_id();
12580 if local
12581 .buffers_opened_in_servers
12582 .get(&buffer_id)
12583 .filter(|s| s.contains(&server_id))
12584 .is_some()
12585 {
12586 buffers_with_language_server.push(handle);
12587 }
12588 }
12589 let triggers = caps
12590 .trigger_characters
12591 .unwrap_or_default()
12592 .into_iter()
12593 .collect::<BTreeSet<_>>();
12594 for handle in buffers_with_language_server {
12595 let triggers = triggers.clone();
12596 let _ = handle.update(cx, move |buffer, cx| {
12597 buffer.set_completion_triggers(server_id, triggers, cx);
12598 });
12599 }
12600 }
12601 notify_server_capabilities_updated(&server, cx);
12602 }
12603 }
12604 "textDocument/hover" => {
12605 let options = parse_register_capabilities(reg)?;
12606 let provider = match options {
12607 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12608 OneOf::Right(caps) => caps,
12609 };
12610 server.update_capabilities(|capabilities| {
12611 capabilities.hover_provider = Some(provider);
12612 });
12613 notify_server_capabilities_updated(&server, cx);
12614 }
12615 "textDocument/signatureHelp" => {
12616 if let Some(caps) = reg
12617 .register_options
12618 .map(serde_json::from_value)
12619 .transpose()?
12620 {
12621 server.update_capabilities(|capabilities| {
12622 capabilities.signature_help_provider = Some(caps);
12623 });
12624 notify_server_capabilities_updated(&server, cx);
12625 }
12626 }
12627 "textDocument/didChange" => {
12628 if let Some(sync_kind) = reg
12629 .register_options
12630 .and_then(|opts| opts.get("syncKind").cloned())
12631 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12632 .transpose()?
12633 {
12634 server.update_capabilities(|capabilities| {
12635 let mut sync_options =
12636 Self::take_text_document_sync_options(capabilities);
12637 sync_options.change = Some(sync_kind);
12638 capabilities.text_document_sync =
12639 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12640 });
12641 notify_server_capabilities_updated(&server, cx);
12642 }
12643 }
12644 "textDocument/didSave" => {
12645 if let Some(include_text) = reg
12646 .register_options
12647 .map(|opts| {
12648 let transpose = opts
12649 .get("includeText")
12650 .cloned()
12651 .map(serde_json::from_value::<Option<bool>>)
12652 .transpose();
12653 match transpose {
12654 Ok(value) => Ok(value.flatten()),
12655 Err(e) => Err(e),
12656 }
12657 })
12658 .transpose()?
12659 {
12660 server.update_capabilities(|capabilities| {
12661 let mut sync_options =
12662 Self::take_text_document_sync_options(capabilities);
12663 sync_options.save =
12664 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12665 include_text,
12666 }));
12667 capabilities.text_document_sync =
12668 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12669 });
12670 notify_server_capabilities_updated(&server, cx);
12671 }
12672 }
12673 "textDocument/codeLens" => {
12674 if let Some(caps) = reg
12675 .register_options
12676 .map(serde_json::from_value)
12677 .transpose()?
12678 {
12679 server.update_capabilities(|capabilities| {
12680 capabilities.code_lens_provider = Some(caps);
12681 });
12682 notify_server_capabilities_updated(&server, cx);
12683 }
12684 }
12685 "textDocument/diagnostic" => {
12686 if let Some(caps) = reg
12687 .register_options
12688 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12689 .transpose()?
12690 {
12691 let local = self
12692 .as_local_mut()
12693 .context("Expected LSP Store to be local")?;
12694 let state = local
12695 .language_servers
12696 .get_mut(&server_id)
12697 .context("Could not obtain Language Servers state")?;
12698 local
12699 .language_server_dynamic_registrations
12700 .entry(server_id)
12701 .or_default()
12702 .diagnostics
12703 .insert(Some(reg.id.clone()), caps.clone());
12704
12705 let supports_workspace_diagnostics =
12706 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12707 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12708 diagnostic_options.workspace_diagnostics
12709 }
12710 DiagnosticServerCapabilities::RegistrationOptions(
12711 diagnostic_registration_options,
12712 ) => {
12713 diagnostic_registration_options
12714 .diagnostic_options
12715 .workspace_diagnostics
12716 }
12717 };
12718
12719 if supports_workspace_diagnostics(&caps) {
12720 if let LanguageServerState::Running {
12721 workspace_diagnostics_refresh_tasks,
12722 ..
12723 } = state
12724 && let Some(task) = lsp_workspace_diagnostics_refresh(
12725 Some(reg.id.clone()),
12726 caps.clone(),
12727 server.clone(),
12728 cx,
12729 )
12730 {
12731 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12732 }
12733 }
12734
12735 server.update_capabilities(|capabilities| {
12736 capabilities.diagnostic_provider = Some(caps);
12737 });
12738
12739 notify_server_capabilities_updated(&server, cx);
12740
12741 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12742 }
12743 }
12744 "textDocument/documentColor" => {
12745 let options = parse_register_capabilities(reg)?;
12746 let provider = match options {
12747 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12748 OneOf::Right(caps) => caps,
12749 };
12750 server.update_capabilities(|capabilities| {
12751 capabilities.color_provider = Some(provider);
12752 });
12753 notify_server_capabilities_updated(&server, cx);
12754 }
12755 "textDocument/foldingRange" => {
12756 let options = parse_register_capabilities(reg)?;
12757 let provider = match options {
12758 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12759 OneOf::Right(caps) => caps,
12760 };
12761 server.update_capabilities(|capabilities| {
12762 capabilities.folding_range_provider = Some(provider);
12763 });
12764 notify_server_capabilities_updated(&server, cx);
12765 }
12766 _ => log::warn!("unhandled capability registration: {reg:?}"),
12767 }
12768 }
12769
12770 Ok(())
12771 }
12772
12773 fn unregister_server_capabilities(
12774 &mut self,
12775 server_id: LanguageServerId,
12776 params: lsp::UnregistrationParams,
12777 cx: &mut Context<Self>,
12778 ) -> anyhow::Result<()> {
12779 let server = self
12780 .language_server_for_id(server_id)
12781 .with_context(|| format!("no server {server_id} found"))?;
12782 for unreg in params.unregisterations.iter() {
12783 match unreg.method.as_str() {
12784 "workspace/didChangeWatchedFiles" => {
12785 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12786 local_lsp_store
12787 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12788 true
12789 } else {
12790 false
12791 };
12792 if notify {
12793 notify_server_capabilities_updated(&server, cx);
12794 }
12795 }
12796 "workspace/didChangeConfiguration" => {
12797 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12798 }
12799 "workspace/didChangeWorkspaceFolders" => {
12800 server.update_capabilities(|capabilities| {
12801 capabilities
12802 .workspace
12803 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12804 workspace_folders: None,
12805 file_operations: None,
12806 })
12807 .workspace_folders = None;
12808 });
12809 notify_server_capabilities_updated(&server, cx);
12810 }
12811 "workspace/symbol" => {
12812 server.update_capabilities(|capabilities| {
12813 capabilities.workspace_symbol_provider = None
12814 });
12815 notify_server_capabilities_updated(&server, cx);
12816 }
12817 "workspace/fileOperations" => {
12818 server.update_capabilities(|capabilities| {
12819 capabilities
12820 .workspace
12821 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12822 workspace_folders: None,
12823 file_operations: None,
12824 })
12825 .file_operations = None;
12826 });
12827 notify_server_capabilities_updated(&server, cx);
12828 }
12829 "workspace/executeCommand" => {
12830 server.update_capabilities(|capabilities| {
12831 capabilities.execute_command_provider = None;
12832 });
12833 notify_server_capabilities_updated(&server, cx);
12834 }
12835 "textDocument/rangeFormatting" => {
12836 server.update_capabilities(|capabilities| {
12837 capabilities.document_range_formatting_provider = None
12838 });
12839 notify_server_capabilities_updated(&server, cx);
12840 }
12841 "textDocument/onTypeFormatting" => {
12842 server.update_capabilities(|capabilities| {
12843 capabilities.document_on_type_formatting_provider = None;
12844 });
12845 notify_server_capabilities_updated(&server, cx);
12846 }
12847 "textDocument/formatting" => {
12848 server.update_capabilities(|capabilities| {
12849 capabilities.document_formatting_provider = None;
12850 });
12851 notify_server_capabilities_updated(&server, cx);
12852 }
12853 "textDocument/rename" => {
12854 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12855 notify_server_capabilities_updated(&server, cx);
12856 }
12857 "textDocument/codeAction" => {
12858 server.update_capabilities(|capabilities| {
12859 capabilities.code_action_provider = None;
12860 });
12861 notify_server_capabilities_updated(&server, cx);
12862 }
12863 "textDocument/definition" => {
12864 server.update_capabilities(|capabilities| {
12865 capabilities.definition_provider = None;
12866 });
12867 notify_server_capabilities_updated(&server, cx);
12868 }
12869 "textDocument/completion" => {
12870 server.update_capabilities(|capabilities| {
12871 capabilities.completion_provider = None;
12872 });
12873 notify_server_capabilities_updated(&server, cx);
12874 }
12875 "textDocument/hover" => {
12876 server.update_capabilities(|capabilities| {
12877 capabilities.hover_provider = None;
12878 });
12879 notify_server_capabilities_updated(&server, cx);
12880 }
12881 "textDocument/signatureHelp" => {
12882 server.update_capabilities(|capabilities| {
12883 capabilities.signature_help_provider = None;
12884 });
12885 notify_server_capabilities_updated(&server, cx);
12886 }
12887 "textDocument/didChange" => {
12888 server.update_capabilities(|capabilities| {
12889 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12890 sync_options.change = None;
12891 capabilities.text_document_sync =
12892 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12893 });
12894 notify_server_capabilities_updated(&server, cx);
12895 }
12896 "textDocument/didSave" => {
12897 server.update_capabilities(|capabilities| {
12898 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12899 sync_options.save = None;
12900 capabilities.text_document_sync =
12901 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12902 });
12903 notify_server_capabilities_updated(&server, cx);
12904 }
12905 "textDocument/codeLens" => {
12906 server.update_capabilities(|capabilities| {
12907 capabilities.code_lens_provider = None;
12908 });
12909 notify_server_capabilities_updated(&server, cx);
12910 }
12911 "textDocument/diagnostic" => {
12912 let local = self
12913 .as_local_mut()
12914 .context("Expected LSP Store to be local")?;
12915
12916 let state = local
12917 .language_servers
12918 .get_mut(&server_id)
12919 .context("Could not obtain Language Servers state")?;
12920 let registrations = local
12921 .language_server_dynamic_registrations
12922 .get_mut(&server_id)
12923 .with_context(|| {
12924 format!("Expected dynamic registration to exist for server {server_id}")
12925 })?;
12926 registrations.diagnostics
12927 .remove(&Some(unreg.id.clone()))
12928 .with_context(|| format!(
12929 "Attempted to unregister non-existent diagnostic registration with ID {}",
12930 unreg.id)
12931 )?;
12932 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12933
12934 if let LanguageServerState::Running {
12935 workspace_diagnostics_refresh_tasks,
12936 ..
12937 } = state
12938 {
12939 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12940 }
12941
12942 self.clear_unregistered_diagnostics(
12943 server_id,
12944 SharedString::from(unreg.id.clone()),
12945 cx,
12946 )?;
12947
12948 if removed_last_diagnostic_provider {
12949 server.update_capabilities(|capabilities| {
12950 debug_assert!(capabilities.diagnostic_provider.is_some());
12951 capabilities.diagnostic_provider = None;
12952 });
12953 }
12954
12955 notify_server_capabilities_updated(&server, cx);
12956 }
12957 "textDocument/documentColor" => {
12958 server.update_capabilities(|capabilities| {
12959 capabilities.color_provider = None;
12960 });
12961 notify_server_capabilities_updated(&server, cx);
12962 }
12963 "textDocument/foldingRange" => {
12964 server.update_capabilities(|capabilities| {
12965 capabilities.folding_range_provider = None;
12966 });
12967 notify_server_capabilities_updated(&server, cx);
12968 }
12969 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12970 }
12971 }
12972
12973 Ok(())
12974 }
12975
12976 fn clear_unregistered_diagnostics(
12977 &mut self,
12978 server_id: LanguageServerId,
12979 cleared_registration_id: SharedString,
12980 cx: &mut Context<Self>,
12981 ) -> anyhow::Result<()> {
12982 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12983
12984 self.buffer_store.update(cx, |buffer_store, cx| {
12985 for buffer_handle in buffer_store.buffers() {
12986 let buffer = buffer_handle.read(cx);
12987 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12988 let Some(abs_path) = abs_path else {
12989 continue;
12990 };
12991 affected_abs_paths.insert(abs_path);
12992 }
12993 });
12994
12995 let local = self.as_local().context("Expected LSP Store to be local")?;
12996 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12997 let Some(worktree) = self
12998 .worktree_store
12999 .read(cx)
13000 .worktree_for_id(*worktree_id, cx)
13001 else {
13002 continue;
13003 };
13004
13005 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13006 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13007 let has_matching_registration =
13008 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13009 entry.diagnostic.registration_id.as_ref()
13010 == Some(&cleared_registration_id)
13011 });
13012 if has_matching_registration {
13013 let abs_path = worktree.read(cx).absolutize(rel_path);
13014 affected_abs_paths.insert(abs_path);
13015 }
13016 }
13017 }
13018 }
13019
13020 if affected_abs_paths.is_empty() {
13021 return Ok(());
13022 }
13023
13024 // Send a fake diagnostic update which clears the state for the registration ID
13025 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13026 affected_abs_paths
13027 .into_iter()
13028 .map(|abs_path| DocumentDiagnosticsUpdate {
13029 diagnostics: DocumentDiagnostics {
13030 diagnostics: Vec::new(),
13031 document_abs_path: abs_path,
13032 version: None,
13033 },
13034 result_id: None,
13035 registration_id: Some(cleared_registration_id.clone()),
13036 server_id,
13037 disk_based_sources: Cow::Borrowed(&[]),
13038 })
13039 .collect();
13040
13041 let merge_registration_id = cleared_registration_id.clone();
13042 self.merge_diagnostic_entries(
13043 clears,
13044 move |_, diagnostic, _| {
13045 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13046 diagnostic.registration_id != Some(merge_registration_id.clone())
13047 } else {
13048 true
13049 }
13050 },
13051 cx,
13052 )?;
13053
13054 Ok(())
13055 }
13056
13057 async fn deduplicate_range_based_lsp_requests<T>(
13058 lsp_store: &Entity<Self>,
13059 server_id: Option<LanguageServerId>,
13060 lsp_request_id: LspRequestId,
13061 proto_request: &T::ProtoRequest,
13062 range: Range<Anchor>,
13063 cx: &mut AsyncApp,
13064 ) -> Result<()>
13065 where
13066 T: LspCommand,
13067 T::ProtoRequest: proto::LspRequestMessage,
13068 {
13069 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13070 let version = deserialize_version(proto_request.buffer_version());
13071 let buffer = lsp_store.update(cx, |this, cx| {
13072 this.buffer_store.read(cx).get_existing(buffer_id)
13073 })?;
13074 buffer
13075 .update(cx, |buffer, _| buffer.wait_for_version(version))
13076 .await?;
13077 lsp_store.update(cx, |lsp_store, cx| {
13078 let buffer_snapshot = buffer.read(cx).snapshot();
13079 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13080 let chunks_queried_for = lsp_data
13081 .inlay_hints
13082 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13083 .collect::<Vec<_>>();
13084 match chunks_queried_for.as_slice() {
13085 &[chunk] => {
13086 let key = LspKey {
13087 request_type: TypeId::of::<T>(),
13088 server_queried: server_id,
13089 };
13090 let previous_request = lsp_data
13091 .chunk_lsp_requests
13092 .entry(key)
13093 .or_default()
13094 .insert(chunk, lsp_request_id);
13095 if let Some((previous_request, running_requests)) =
13096 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13097 {
13098 running_requests.remove(&previous_request);
13099 }
13100 }
13101 _ambiguous_chunks => {
13102 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13103 // there, a buffer version-based check will be performed and outdated requests discarded.
13104 }
13105 }
13106 anyhow::Ok(())
13107 })?;
13108
13109 Ok(())
13110 }
13111
13112 async fn query_lsp_locally<T>(
13113 lsp_store: Entity<Self>,
13114 for_server_id: Option<LanguageServerId>,
13115 sender_id: proto::PeerId,
13116 lsp_request_id: LspRequestId,
13117 proto_request: T::ProtoRequest,
13118 position: Option<Anchor>,
13119 cx: &mut AsyncApp,
13120 ) -> Result<()>
13121 where
13122 T: LspCommand + Clone,
13123 T::ProtoRequest: proto::LspRequestMessage,
13124 <T::ProtoRequest as proto::RequestMessage>::Response:
13125 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13126 {
13127 let (buffer_version, buffer) =
13128 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13129 let request =
13130 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13131 let key = LspKey {
13132 request_type: TypeId::of::<T>(),
13133 server_queried: for_server_id,
13134 };
13135 lsp_store.update(cx, |lsp_store, cx| {
13136 let request_task = match for_server_id {
13137 Some(server_id) => {
13138 let server_task = lsp_store.request_lsp(
13139 buffer.clone(),
13140 LanguageServerToQuery::Other(server_id),
13141 request.clone(),
13142 cx,
13143 );
13144 cx.background_spawn(async move {
13145 let mut responses = Vec::new();
13146 match server_task.await {
13147 Ok(response) => responses.push((server_id, response)),
13148 // rust-analyzer likes to error with this when its still loading up
13149 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13150 Err(e) => log::error!(
13151 "Error handling response for request {request:?}: {e:#}"
13152 ),
13153 }
13154 responses
13155 })
13156 }
13157 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13158 };
13159 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13160 if T::ProtoRequest::stop_previous_requests() {
13161 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13162 lsp_requests.clear();
13163 }
13164 }
13165 lsp_data.lsp_requests.entry(key).or_default().insert(
13166 lsp_request_id,
13167 cx.spawn(async move |lsp_store, cx| {
13168 let response = request_task.await;
13169 lsp_store
13170 .update(cx, |lsp_store, cx| {
13171 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13172 {
13173 let response = response
13174 .into_iter()
13175 .map(|(server_id, response)| {
13176 (
13177 server_id.to_proto(),
13178 T::response_to_proto(
13179 response,
13180 lsp_store,
13181 sender_id,
13182 &buffer_version,
13183 cx,
13184 )
13185 .into(),
13186 )
13187 })
13188 .collect::<HashMap<_, _>>();
13189 match client.send_lsp_response::<T::ProtoRequest>(
13190 project_id,
13191 lsp_request_id,
13192 response,
13193 ) {
13194 Ok(()) => {}
13195 Err(e) => {
13196 log::error!("Failed to send LSP response: {e:#}",)
13197 }
13198 }
13199 }
13200 })
13201 .ok();
13202 }),
13203 );
13204 });
13205 Ok(())
13206 }
13207
13208 async fn wait_for_buffer_version<T>(
13209 lsp_store: &Entity<Self>,
13210 proto_request: &T::ProtoRequest,
13211 cx: &mut AsyncApp,
13212 ) -> Result<(Global, Entity<Buffer>)>
13213 where
13214 T: LspCommand,
13215 T::ProtoRequest: proto::LspRequestMessage,
13216 {
13217 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13218 let version = deserialize_version(proto_request.buffer_version());
13219 let buffer = lsp_store.update(cx, |this, cx| {
13220 this.buffer_store.read(cx).get_existing(buffer_id)
13221 })?;
13222 buffer
13223 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13224 .await?;
13225 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13226 Ok((buffer_version, buffer))
13227 }
13228
13229 fn take_text_document_sync_options(
13230 capabilities: &mut lsp::ServerCapabilities,
13231 ) -> lsp::TextDocumentSyncOptions {
13232 match capabilities.text_document_sync.take() {
13233 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13234 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13235 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13236 sync_options.change = Some(sync_kind);
13237 sync_options
13238 }
13239 None => lsp::TextDocumentSyncOptions::default(),
13240 }
13241 }
13242
13243 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13244 self.downstream_client.clone()
13245 }
13246
13247 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13248 self.worktree_store.clone()
13249 }
13250
13251 /// Gets what's stored in the LSP data for the given buffer.
13252 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13253 self.lsp_data.get_mut(&buffer_id)
13254 }
13255
13256 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13257 /// new [`BufferLspData`] will be created to replace the previous state.
13258 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13259 let (buffer_id, buffer_version) =
13260 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13261 let lsp_data = self
13262 .lsp_data
13263 .entry(buffer_id)
13264 .or_insert_with(|| BufferLspData::new(buffer, cx));
13265 if buffer_version.changed_since(&lsp_data.buffer_version) {
13266 // To send delta requests for semantic tokens, the previous tokens
13267 // need to be kept between buffer changes.
13268 let semantic_tokens = lsp_data.semantic_tokens.take();
13269 *lsp_data = BufferLspData::new(buffer, cx);
13270 lsp_data.semantic_tokens = semantic_tokens;
13271 }
13272 lsp_data
13273 }
13274}
13275
13276// Registration with registerOptions as null, should fallback to true.
13277// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13278fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13279 reg: lsp::Registration,
13280) -> Result<OneOf<bool, T>> {
13281 Ok(match reg.register_options {
13282 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13283 None => OneOf::Left(true),
13284 })
13285}
13286
13287fn subscribe_to_binary_statuses(
13288 languages: &Arc<LanguageRegistry>,
13289 cx: &mut Context<'_, LspStore>,
13290) -> Task<()> {
13291 let mut server_statuses = languages.language_server_binary_statuses();
13292 cx.spawn(async move |lsp_store, cx| {
13293 while let Some((server_name, binary_status)) = server_statuses.next().await {
13294 if lsp_store
13295 .update(cx, |_, cx| {
13296 let mut message = None;
13297 let binary_status = match binary_status {
13298 BinaryStatus::None => proto::ServerBinaryStatus::None,
13299 BinaryStatus::CheckingForUpdate => {
13300 proto::ServerBinaryStatus::CheckingForUpdate
13301 }
13302 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13303 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13304 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13305 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13306 BinaryStatus::Failed { error } => {
13307 message = Some(error);
13308 proto::ServerBinaryStatus::Failed
13309 }
13310 };
13311 cx.emit(LspStoreEvent::LanguageServerUpdate {
13312 // Binary updates are about the binary that might not have any language server id at that point.
13313 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13314 language_server_id: LanguageServerId(0),
13315 name: Some(server_name),
13316 message: proto::update_language_server::Variant::StatusUpdate(
13317 proto::StatusUpdate {
13318 message,
13319 status: Some(proto::status_update::Status::Binary(
13320 binary_status as i32,
13321 )),
13322 },
13323 ),
13324 });
13325 })
13326 .is_err()
13327 {
13328 break;
13329 }
13330 }
13331 })
13332}
13333
13334fn lsp_workspace_diagnostics_refresh(
13335 registration_id: Option<String>,
13336 options: DiagnosticServerCapabilities,
13337 server: Arc<LanguageServer>,
13338 cx: &mut Context<'_, LspStore>,
13339) -> Option<WorkspaceRefreshTask> {
13340 let identifier = workspace_diagnostic_identifier(&options)?;
13341 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13342
13343 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13344 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13345 refresh_tx.try_send(()).ok();
13346
13347 let request_timeout = ProjectSettings::get_global(cx)
13348 .global_lsp_settings
13349 .get_request_timeout();
13350
13351 // 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.
13352 // This allows users to increase the duration if need be
13353 let timeout = if request_timeout != Duration::ZERO {
13354 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13355 } else {
13356 request_timeout
13357 };
13358
13359 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13360 let mut attempts = 0;
13361 let max_attempts = 50;
13362 let mut requests = 0;
13363
13364 loop {
13365 let Some(()) = refresh_rx.recv().await else {
13366 return;
13367 };
13368
13369 'request: loop {
13370 requests += 1;
13371 if attempts > max_attempts {
13372 log::error!(
13373 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13374 );
13375 return;
13376 }
13377 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13378 cx.background_executor()
13379 .timer(Duration::from_millis(backoff_millis))
13380 .await;
13381 attempts += 1;
13382
13383 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13384 lsp_store
13385 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13386 .into_iter()
13387 .filter_map(|(abs_path, result_id)| {
13388 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13389 Some(lsp::PreviousResultId {
13390 uri,
13391 value: result_id.to_string(),
13392 })
13393 })
13394 .collect()
13395 }) else {
13396 return;
13397 };
13398
13399 let token = if let Some(registration_id) = ®istration_id {
13400 format!(
13401 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13402 server.server_id(),
13403 )
13404 } else {
13405 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13406 };
13407
13408 progress_rx.try_recv().ok();
13409 let timer = server.request_timer(timeout).fuse();
13410 let progress = pin!(progress_rx.recv().fuse());
13411 let response_result = server
13412 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13413 lsp::WorkspaceDiagnosticParams {
13414 previous_result_ids,
13415 identifier: identifier.clone(),
13416 work_done_progress_params: Default::default(),
13417 partial_result_params: lsp::PartialResultParams {
13418 partial_result_token: Some(lsp::ProgressToken::String(token)),
13419 },
13420 },
13421 select(timer, progress).then(|either| match either {
13422 Either::Left((message, ..)) => ready(message).left_future(),
13423 Either::Right(..) => pending::<String>().right_future(),
13424 }),
13425 )
13426 .await;
13427
13428 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13429 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13430 match response_result {
13431 ConnectionResult::Timeout => {
13432 log::error!("Timeout during workspace diagnostics pull");
13433 continue 'request;
13434 }
13435 ConnectionResult::ConnectionReset => {
13436 log::error!("Server closed a workspace diagnostics pull request");
13437 continue 'request;
13438 }
13439 ConnectionResult::Result(Err(e)) => {
13440 log::error!("Error during workspace diagnostics pull: {e:#}");
13441 break 'request;
13442 }
13443 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13444 attempts = 0;
13445 if lsp_store
13446 .update(cx, |lsp_store, cx| {
13447 lsp_store.apply_workspace_diagnostic_report(
13448 server.server_id(),
13449 pulled_diagnostics,
13450 registration_id_shared.clone(),
13451 cx,
13452 )
13453 })
13454 .is_err()
13455 {
13456 return;
13457 }
13458 break 'request;
13459 }
13460 }
13461 }
13462 }
13463 });
13464
13465 Some(WorkspaceRefreshTask {
13466 refresh_tx,
13467 progress_tx,
13468 task: workspace_query_language_server,
13469 })
13470}
13471
13472fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13473 match &options {
13474 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13475 .identifier
13476 .as_deref()
13477 .map(SharedString::new),
13478 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13479 let diagnostic_options = ®istration_options.diagnostic_options;
13480 diagnostic_options
13481 .identifier
13482 .as_deref()
13483 .map(SharedString::new)
13484 }
13485 }
13486}
13487
13488fn workspace_diagnostic_identifier(
13489 options: &DiagnosticServerCapabilities,
13490) -> Option<Option<String>> {
13491 match &options {
13492 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13493 if !diagnostic_options.workspace_diagnostics {
13494 return None;
13495 }
13496 Some(diagnostic_options.identifier.clone())
13497 }
13498 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13499 let diagnostic_options = ®istration_options.diagnostic_options;
13500 if !diagnostic_options.workspace_diagnostics {
13501 return None;
13502 }
13503 Some(diagnostic_options.identifier.clone())
13504 }
13505 }
13506}
13507
13508fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13509 let CompletionSource::BufferWord {
13510 word_range,
13511 resolved,
13512 } = &mut completion.source
13513 else {
13514 return;
13515 };
13516 if *resolved {
13517 return;
13518 }
13519
13520 if completion.new_text
13521 != snapshot
13522 .text_for_range(word_range.clone())
13523 .collect::<String>()
13524 {
13525 return;
13526 }
13527
13528 let mut offset = 0;
13529 for chunk in snapshot.chunks(word_range.clone(), true) {
13530 let end_offset = offset + chunk.text.len();
13531 if let Some(highlight_id) = chunk.syntax_highlight_id {
13532 completion
13533 .label
13534 .runs
13535 .push((offset..end_offset, highlight_id));
13536 }
13537 offset = end_offset;
13538 }
13539 *resolved = true;
13540}
13541
13542impl EventEmitter<LspStoreEvent> for LspStore {}
13543
13544fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13545 hover
13546 .contents
13547 .retain(|hover_block| !hover_block.text.trim().is_empty());
13548 if hover.contents.is_empty() {
13549 None
13550 } else {
13551 Some(hover)
13552 }
13553}
13554
13555async fn populate_labels_for_completions(
13556 new_completions: Vec<CoreCompletion>,
13557 language: Option<Arc<Language>>,
13558 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13559) -> Vec<Completion> {
13560 let lsp_completions = new_completions
13561 .iter()
13562 .filter_map(|new_completion| {
13563 new_completion
13564 .source
13565 .lsp_completion(true)
13566 .map(|lsp_completion| lsp_completion.into_owned())
13567 })
13568 .collect::<Vec<_>>();
13569
13570 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13571 lsp_adapter
13572 .labels_for_completions(&lsp_completions, language)
13573 .await
13574 .log_err()
13575 .unwrap_or_default()
13576 } else {
13577 Vec::new()
13578 }
13579 .into_iter()
13580 .fuse();
13581
13582 let mut completions = Vec::new();
13583 for completion in new_completions {
13584 match completion.source.lsp_completion(true) {
13585 Some(lsp_completion) => {
13586 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13587
13588 let mut label = labels.next().flatten().unwrap_or_else(|| {
13589 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13590 });
13591 ensure_uniform_list_compatible_label(&mut label);
13592 completions.push(Completion {
13593 label,
13594 documentation,
13595 replace_range: completion.replace_range,
13596 new_text: completion.new_text,
13597 insert_text_mode: lsp_completion.insert_text_mode,
13598 source: completion.source,
13599 icon_path: None,
13600 confirm: None,
13601 match_start: None,
13602 snippet_deduplication_key: None,
13603 });
13604 }
13605 None => {
13606 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13607 ensure_uniform_list_compatible_label(&mut label);
13608 completions.push(Completion {
13609 label,
13610 documentation: None,
13611 replace_range: completion.replace_range,
13612 new_text: completion.new_text,
13613 source: completion.source,
13614 insert_text_mode: None,
13615 icon_path: None,
13616 confirm: None,
13617 match_start: None,
13618 snippet_deduplication_key: None,
13619 });
13620 }
13621 }
13622 }
13623 completions
13624}
13625
13626#[derive(Debug)]
13627pub enum LanguageServerToQuery {
13628 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13629 FirstCapable,
13630 /// Query a specific language server.
13631 Other(LanguageServerId),
13632}
13633
13634#[derive(Default)]
13635struct RenamePathsWatchedForServer {
13636 did_rename: Vec<RenameActionPredicate>,
13637 will_rename: Vec<RenameActionPredicate>,
13638}
13639
13640impl RenamePathsWatchedForServer {
13641 fn with_did_rename_patterns(
13642 mut self,
13643 did_rename: Option<&FileOperationRegistrationOptions>,
13644 ) -> Self {
13645 if let Some(did_rename) = did_rename {
13646 self.did_rename = did_rename
13647 .filters
13648 .iter()
13649 .filter_map(|filter| filter.try_into().log_err())
13650 .collect();
13651 }
13652 self
13653 }
13654 fn with_will_rename_patterns(
13655 mut self,
13656 will_rename: Option<&FileOperationRegistrationOptions>,
13657 ) -> Self {
13658 if let Some(will_rename) = will_rename {
13659 self.will_rename = will_rename
13660 .filters
13661 .iter()
13662 .filter_map(|filter| filter.try_into().log_err())
13663 .collect();
13664 }
13665 self
13666 }
13667
13668 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13669 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13670 }
13671 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13672 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13673 }
13674}
13675
13676impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13677 type Error = globset::Error;
13678 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13679 Ok(Self {
13680 kind: ops.pattern.matches.clone(),
13681 glob: GlobBuilder::new(&ops.pattern.glob)
13682 .case_insensitive(
13683 ops.pattern
13684 .options
13685 .as_ref()
13686 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13687 )
13688 .build()?
13689 .compile_matcher(),
13690 })
13691 }
13692}
13693struct RenameActionPredicate {
13694 glob: GlobMatcher,
13695 kind: Option<FileOperationPatternKind>,
13696}
13697
13698impl RenameActionPredicate {
13699 // Returns true if language server should be notified
13700 fn eval(&self, path: &str, is_dir: bool) -> bool {
13701 self.kind.as_ref().is_none_or(|kind| {
13702 let expected_kind = if is_dir {
13703 FileOperationPatternKind::Folder
13704 } else {
13705 FileOperationPatternKind::File
13706 };
13707 kind == &expected_kind
13708 }) && self.glob.is_match(path)
13709 }
13710}
13711
13712#[derive(Default)]
13713struct LanguageServerWatchedPaths {
13714 worktree_paths: HashMap<WorktreeId, GlobSet>,
13715 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13716}
13717
13718#[derive(Default)]
13719struct LanguageServerWatchedPathsBuilder {
13720 worktree_paths: HashMap<WorktreeId, GlobSet>,
13721 abs_paths: HashMap<Arc<Path>, GlobSet>,
13722}
13723
13724impl LanguageServerWatchedPathsBuilder {
13725 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13726 self.worktree_paths.insert(worktree_id, glob_set);
13727 }
13728 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13729 self.abs_paths.insert(path, glob_set);
13730 }
13731 fn build(
13732 self,
13733 fs: Arc<dyn Fs>,
13734 language_server_id: LanguageServerId,
13735 cx: &mut Context<LspStore>,
13736 ) -> LanguageServerWatchedPaths {
13737 let lsp_store = cx.weak_entity();
13738
13739 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13740 let abs_paths = self
13741 .abs_paths
13742 .into_iter()
13743 .map(|(abs_path, globset)| {
13744 let task = cx.spawn({
13745 let abs_path = abs_path.clone();
13746 let fs = fs.clone();
13747
13748 let lsp_store = lsp_store.clone();
13749 async move |_, cx| {
13750 maybe!(async move {
13751 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13752 while let Some(update) = push_updates.0.next().await {
13753 let action = lsp_store
13754 .update(cx, |this, _| {
13755 let Some(local) = this.as_local() else {
13756 return ControlFlow::Break(());
13757 };
13758 let Some(watcher) = local
13759 .language_server_watched_paths
13760 .get(&language_server_id)
13761 else {
13762 return ControlFlow::Break(());
13763 };
13764 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13765 "Watched abs path is not registered with a watcher",
13766 );
13767 let matching_entries = update
13768 .into_iter()
13769 .filter(|event| globs.is_match(&event.path))
13770 .collect::<Vec<_>>();
13771 this.lsp_notify_abs_paths_changed(
13772 language_server_id,
13773 matching_entries,
13774 );
13775 ControlFlow::Continue(())
13776 })
13777 .ok()?;
13778
13779 if action.is_break() {
13780 break;
13781 }
13782 }
13783 Some(())
13784 })
13785 .await;
13786 }
13787 });
13788 (abs_path, (globset, task))
13789 })
13790 .collect();
13791 LanguageServerWatchedPaths {
13792 worktree_paths: self.worktree_paths,
13793 abs_paths,
13794 }
13795 }
13796}
13797
13798struct LspBufferSnapshot {
13799 version: i32,
13800 snapshot: TextBufferSnapshot,
13801}
13802
13803/// A prompt requested by LSP server.
13804#[derive(Clone, Debug)]
13805pub struct LanguageServerPromptRequest {
13806 pub id: usize,
13807 pub level: PromptLevel,
13808 pub message: String,
13809 pub actions: Vec<MessageActionItem>,
13810 pub lsp_name: String,
13811 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13812}
13813
13814impl LanguageServerPromptRequest {
13815 pub fn new(
13816 level: PromptLevel,
13817 message: String,
13818 actions: Vec<MessageActionItem>,
13819 lsp_name: String,
13820 response_channel: smol::channel::Sender<MessageActionItem>,
13821 ) -> Self {
13822 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13823 LanguageServerPromptRequest {
13824 id,
13825 level,
13826 message,
13827 actions,
13828 lsp_name,
13829 response_channel,
13830 }
13831 }
13832 pub async fn respond(self, index: usize) -> Option<()> {
13833 if let Some(response) = self.actions.into_iter().nth(index) {
13834 self.response_channel.send(response).await.ok()
13835 } else {
13836 None
13837 }
13838 }
13839
13840 #[cfg(any(test, feature = "test-support"))]
13841 pub fn test(
13842 level: PromptLevel,
13843 message: String,
13844 actions: Vec<MessageActionItem>,
13845 lsp_name: String,
13846 ) -> Self {
13847 let (tx, _rx) = smol::channel::unbounded();
13848 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13849 }
13850}
13851impl PartialEq for LanguageServerPromptRequest {
13852 fn eq(&self, other: &Self) -> bool {
13853 self.message == other.message && self.actions == other.actions
13854 }
13855}
13856
13857#[derive(Clone, Debug, PartialEq)]
13858pub enum LanguageServerLogType {
13859 Log(MessageType),
13860 Trace { verbose_info: Option<String> },
13861 Rpc { received: bool },
13862}
13863
13864impl LanguageServerLogType {
13865 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13866 match self {
13867 Self::Log(log_type) => {
13868 use proto::log_message::LogLevel;
13869 let level = match *log_type {
13870 MessageType::ERROR => LogLevel::Error,
13871 MessageType::WARNING => LogLevel::Warning,
13872 MessageType::INFO => LogLevel::Info,
13873 MessageType::LOG => LogLevel::Log,
13874 other => {
13875 log::warn!("Unknown lsp log message type: {other:?}");
13876 LogLevel::Log
13877 }
13878 };
13879 proto::language_server_log::LogType::Log(proto::LogMessage {
13880 level: level as i32,
13881 })
13882 }
13883 Self::Trace { verbose_info } => {
13884 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13885 verbose_info: verbose_info.to_owned(),
13886 })
13887 }
13888 Self::Rpc { received } => {
13889 let kind = if *received {
13890 proto::rpc_message::Kind::Received
13891 } else {
13892 proto::rpc_message::Kind::Sent
13893 };
13894 let kind = kind as i32;
13895 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13896 }
13897 }
13898 }
13899
13900 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13901 use proto::log_message::LogLevel;
13902 use proto::rpc_message;
13903 match log_type {
13904 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13905 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13906 LogLevel::Error => MessageType::ERROR,
13907 LogLevel::Warning => MessageType::WARNING,
13908 LogLevel::Info => MessageType::INFO,
13909 LogLevel::Log => MessageType::LOG,
13910 },
13911 ),
13912 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13913 verbose_info: trace_message.verbose_info,
13914 },
13915 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13916 received: match rpc_message::Kind::from_i32(message.kind)
13917 .unwrap_or(rpc_message::Kind::Received)
13918 {
13919 rpc_message::Kind::Received => true,
13920 rpc_message::Kind::Sent => false,
13921 },
13922 },
13923 }
13924 }
13925}
13926
13927pub struct WorkspaceRefreshTask {
13928 refresh_tx: mpsc::Sender<()>,
13929 progress_tx: mpsc::Sender<()>,
13930 #[allow(dead_code)]
13931 task: Task<()>,
13932}
13933
13934pub enum LanguageServerState {
13935 Starting {
13936 startup: Task<Option<Arc<LanguageServer>>>,
13937 /// List of language servers that will be added to the workspace once it's initialization completes.
13938 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13939 },
13940
13941 Running {
13942 adapter: Arc<CachedLspAdapter>,
13943 server: Arc<LanguageServer>,
13944 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13945 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13946 },
13947}
13948
13949impl LanguageServerState {
13950 fn add_workspace_folder(&self, uri: Uri) {
13951 match self {
13952 LanguageServerState::Starting {
13953 pending_workspace_folders,
13954 ..
13955 } => {
13956 pending_workspace_folders.lock().insert(uri);
13957 }
13958 LanguageServerState::Running { server, .. } => {
13959 server.add_workspace_folder(uri);
13960 }
13961 }
13962 }
13963 fn _remove_workspace_folder(&self, uri: Uri) {
13964 match self {
13965 LanguageServerState::Starting {
13966 pending_workspace_folders,
13967 ..
13968 } => {
13969 pending_workspace_folders.lock().remove(&uri);
13970 }
13971 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13972 }
13973 }
13974}
13975
13976impl std::fmt::Debug for LanguageServerState {
13977 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13978 match self {
13979 LanguageServerState::Starting { .. } => {
13980 f.debug_struct("LanguageServerState::Starting").finish()
13981 }
13982 LanguageServerState::Running { .. } => {
13983 f.debug_struct("LanguageServerState::Running").finish()
13984 }
13985 }
13986 }
13987}
13988
13989#[derive(Clone, Debug, Serialize)]
13990pub struct LanguageServerProgress {
13991 pub is_disk_based_diagnostics_progress: bool,
13992 pub is_cancellable: bool,
13993 pub title: Option<String>,
13994 pub message: Option<String>,
13995 pub percentage: Option<usize>,
13996 #[serde(skip_serializing)]
13997 pub last_update_at: Instant,
13998}
13999
14000#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14001pub struct DiagnosticSummary {
14002 pub error_count: usize,
14003 pub warning_count: usize,
14004}
14005
14006impl DiagnosticSummary {
14007 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14008 let mut this = Self {
14009 error_count: 0,
14010 warning_count: 0,
14011 };
14012
14013 for entry in diagnostics {
14014 if entry.diagnostic.is_primary {
14015 match entry.diagnostic.severity {
14016 DiagnosticSeverity::ERROR => this.error_count += 1,
14017 DiagnosticSeverity::WARNING => this.warning_count += 1,
14018 _ => {}
14019 }
14020 }
14021 }
14022
14023 this
14024 }
14025
14026 pub fn is_empty(&self) -> bool {
14027 self.error_count == 0 && self.warning_count == 0
14028 }
14029
14030 pub fn to_proto(
14031 self,
14032 language_server_id: LanguageServerId,
14033 path: &RelPath,
14034 ) -> proto::DiagnosticSummary {
14035 proto::DiagnosticSummary {
14036 path: path.to_proto(),
14037 language_server_id: language_server_id.0 as u64,
14038 error_count: self.error_count as u32,
14039 warning_count: self.warning_count as u32,
14040 }
14041 }
14042}
14043
14044#[derive(Clone, Debug)]
14045pub enum CompletionDocumentation {
14046 /// There is no documentation for this completion.
14047 Undocumented,
14048 /// A single line of documentation.
14049 SingleLine(SharedString),
14050 /// Multiple lines of plain text documentation.
14051 MultiLinePlainText(SharedString),
14052 /// Markdown documentation.
14053 MultiLineMarkdown(SharedString),
14054 /// Both single line and multiple lines of plain text documentation.
14055 SingleLineAndMultiLinePlainText {
14056 single_line: SharedString,
14057 plain_text: Option<SharedString>,
14058 },
14059}
14060
14061impl CompletionDocumentation {
14062 #[cfg(any(test, feature = "test-support"))]
14063 pub fn text(&self) -> SharedString {
14064 match self {
14065 CompletionDocumentation::Undocumented => "".into(),
14066 CompletionDocumentation::SingleLine(s) => s.clone(),
14067 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14068 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14069 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14070 single_line.clone()
14071 }
14072 }
14073 }
14074}
14075
14076impl From<lsp::Documentation> for CompletionDocumentation {
14077 fn from(docs: lsp::Documentation) -> Self {
14078 match docs {
14079 lsp::Documentation::String(text) => {
14080 if text.lines().count() <= 1 {
14081 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14082 } else {
14083 CompletionDocumentation::MultiLinePlainText(text.into())
14084 }
14085 }
14086
14087 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14088 lsp::MarkupKind::PlainText => {
14089 if value.lines().count() <= 1 {
14090 CompletionDocumentation::SingleLine(value.into())
14091 } else {
14092 CompletionDocumentation::MultiLinePlainText(value.into())
14093 }
14094 }
14095
14096 lsp::MarkupKind::Markdown => {
14097 CompletionDocumentation::MultiLineMarkdown(value.into())
14098 }
14099 },
14100 }
14101 }
14102}
14103
14104pub enum ResolvedHint {
14105 Resolved(InlayHint),
14106 Resolving(Shared<Task<()>>),
14107}
14108
14109pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14110 glob.components()
14111 .take_while(|component| match component {
14112 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14113 _ => true,
14114 })
14115 .collect()
14116}
14117
14118pub struct SshLspAdapter {
14119 name: LanguageServerName,
14120 binary: LanguageServerBinary,
14121 initialization_options: Option<String>,
14122 code_action_kinds: Option<Vec<CodeActionKind>>,
14123}
14124
14125impl SshLspAdapter {
14126 pub fn new(
14127 name: LanguageServerName,
14128 binary: LanguageServerBinary,
14129 initialization_options: Option<String>,
14130 code_action_kinds: Option<String>,
14131 ) -> Self {
14132 Self {
14133 name,
14134 binary,
14135 initialization_options,
14136 code_action_kinds: code_action_kinds
14137 .as_ref()
14138 .and_then(|c| serde_json::from_str(c).ok()),
14139 }
14140 }
14141}
14142
14143impl LspInstaller for SshLspAdapter {
14144 type BinaryVersion = ();
14145 async fn check_if_user_installed(
14146 &self,
14147 _: &dyn LspAdapterDelegate,
14148 _: Option<Toolchain>,
14149 _: &AsyncApp,
14150 ) -> Option<LanguageServerBinary> {
14151 Some(self.binary.clone())
14152 }
14153
14154 async fn cached_server_binary(
14155 &self,
14156 _: PathBuf,
14157 _: &dyn LspAdapterDelegate,
14158 ) -> Option<LanguageServerBinary> {
14159 None
14160 }
14161
14162 async fn fetch_latest_server_version(
14163 &self,
14164 _: &dyn LspAdapterDelegate,
14165 _: bool,
14166 _: &mut AsyncApp,
14167 ) -> Result<()> {
14168 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14169 }
14170
14171 async fn fetch_server_binary(
14172 &self,
14173 _: (),
14174 _: PathBuf,
14175 _: &dyn LspAdapterDelegate,
14176 ) -> Result<LanguageServerBinary> {
14177 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14178 }
14179}
14180
14181#[async_trait(?Send)]
14182impl LspAdapter for SshLspAdapter {
14183 fn name(&self) -> LanguageServerName {
14184 self.name.clone()
14185 }
14186
14187 async fn initialization_options(
14188 self: Arc<Self>,
14189 _: &Arc<dyn LspAdapterDelegate>,
14190 _: &mut AsyncApp,
14191 ) -> Result<Option<serde_json::Value>> {
14192 let Some(options) = &self.initialization_options else {
14193 return Ok(None);
14194 };
14195 let result = serde_json::from_str(options)?;
14196 Ok(result)
14197 }
14198
14199 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14200 self.code_action_kinds.clone()
14201 }
14202}
14203
14204pub fn language_server_settings<'a>(
14205 delegate: &'a dyn LspAdapterDelegate,
14206 language: &LanguageServerName,
14207 cx: &'a App,
14208) -> Option<&'a LspSettings> {
14209 language_server_settings_for(
14210 SettingsLocation {
14211 worktree_id: delegate.worktree_id(),
14212 path: RelPath::empty(),
14213 },
14214 language,
14215 cx,
14216 )
14217}
14218
14219pub fn language_server_settings_for<'a>(
14220 location: SettingsLocation<'a>,
14221 language: &LanguageServerName,
14222 cx: &'a App,
14223) -> Option<&'a LspSettings> {
14224 ProjectSettings::get(Some(location), cx).lsp.get(language)
14225}
14226
14227pub struct LocalLspAdapterDelegate {
14228 lsp_store: WeakEntity<LspStore>,
14229 worktree: worktree::Snapshot,
14230 fs: Arc<dyn Fs>,
14231 http_client: Arc<dyn HttpClient>,
14232 language_registry: Arc<LanguageRegistry>,
14233 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14234}
14235
14236impl LocalLspAdapterDelegate {
14237 pub fn new(
14238 language_registry: Arc<LanguageRegistry>,
14239 environment: &Entity<ProjectEnvironment>,
14240 lsp_store: WeakEntity<LspStore>,
14241 worktree: &Entity<Worktree>,
14242 http_client: Arc<dyn HttpClient>,
14243 fs: Arc<dyn Fs>,
14244 cx: &mut App,
14245 ) -> Arc<Self> {
14246 let load_shell_env_task =
14247 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14248
14249 Arc::new(Self {
14250 lsp_store,
14251 worktree: worktree.read(cx).snapshot(),
14252 fs,
14253 http_client,
14254 language_registry,
14255 load_shell_env_task,
14256 })
14257 }
14258
14259 pub fn from_local_lsp(
14260 local: &LocalLspStore,
14261 worktree: &Entity<Worktree>,
14262 cx: &mut App,
14263 ) -> Arc<Self> {
14264 Self::new(
14265 local.languages.clone(),
14266 &local.environment,
14267 local.weak.clone(),
14268 worktree,
14269 local.http_client.clone(),
14270 local.fs.clone(),
14271 cx,
14272 )
14273 }
14274}
14275
14276#[async_trait]
14277impl LspAdapterDelegate for LocalLspAdapterDelegate {
14278 fn show_notification(&self, message: &str, cx: &mut App) {
14279 self.lsp_store
14280 .update(cx, |_, cx| {
14281 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14282 })
14283 .ok();
14284 }
14285
14286 fn http_client(&self) -> Arc<dyn HttpClient> {
14287 self.http_client.clone()
14288 }
14289
14290 fn worktree_id(&self) -> WorktreeId {
14291 self.worktree.id()
14292 }
14293
14294 fn worktree_root_path(&self) -> &Path {
14295 self.worktree.abs_path().as_ref()
14296 }
14297
14298 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14299 self.worktree.resolve_relative_path(path)
14300 }
14301
14302 async fn shell_env(&self) -> HashMap<String, String> {
14303 let task = self.load_shell_env_task.clone();
14304 task.await.unwrap_or_default()
14305 }
14306
14307 async fn npm_package_installed_version(
14308 &self,
14309 package_name: &str,
14310 ) -> Result<Option<(PathBuf, Version)>> {
14311 let local_package_directory = self.worktree_root_path();
14312 let node_modules_directory = local_package_directory.join("node_modules");
14313
14314 if let Some(version) =
14315 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14316 {
14317 return Ok(Some((node_modules_directory, version)));
14318 }
14319 let Some(npm) = self.which("npm".as_ref()).await else {
14320 log::warn!(
14321 "Failed to find npm executable for {:?}",
14322 local_package_directory
14323 );
14324 return Ok(None);
14325 };
14326
14327 let env = self.shell_env().await;
14328 let output = util::command::new_command(&npm)
14329 .args(["root", "-g"])
14330 .envs(env)
14331 .current_dir(local_package_directory)
14332 .output()
14333 .await?;
14334 let global_node_modules =
14335 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14336
14337 if let Some(version) =
14338 read_package_installed_version(global_node_modules.clone(), package_name).await?
14339 {
14340 return Ok(Some((global_node_modules, version)));
14341 }
14342 return Ok(None);
14343 }
14344
14345 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14346 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14347 if self.fs.is_file(&worktree_abs_path).await {
14348 worktree_abs_path.pop();
14349 }
14350
14351 let env = self.shell_env().await;
14352
14353 let shell_path = env.get("PATH").cloned();
14354
14355 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14356 }
14357
14358 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14359 let mut working_dir = self.worktree_root_path().to_path_buf();
14360 if self.fs.is_file(&working_dir).await {
14361 working_dir.pop();
14362 }
14363 let output = util::command::new_command(&command.path)
14364 .args(command.arguments)
14365 .envs(command.env.clone().unwrap_or_default())
14366 .current_dir(working_dir)
14367 .output()
14368 .await?;
14369
14370 anyhow::ensure!(
14371 output.status.success(),
14372 "{}, stdout: {:?}, stderr: {:?}",
14373 output.status,
14374 String::from_utf8_lossy(&output.stdout),
14375 String::from_utf8_lossy(&output.stderr)
14376 );
14377 Ok(())
14378 }
14379
14380 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14381 self.language_registry
14382 .update_lsp_binary_status(server_name, status);
14383 }
14384
14385 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14386 self.language_registry
14387 .all_lsp_adapters()
14388 .into_iter()
14389 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14390 .collect()
14391 }
14392
14393 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14394 let dir = self.language_registry.language_server_download_dir(name)?;
14395
14396 if !dir.exists() {
14397 smol::fs::create_dir_all(&dir)
14398 .await
14399 .context("failed to create container directory")
14400 .log_err()?;
14401 }
14402
14403 Some(dir)
14404 }
14405
14406 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14407 let entry = self
14408 .worktree
14409 .entry_for_path(path)
14410 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14411 let abs_path = self.worktree.absolutize(&entry.path);
14412 self.fs.load(&abs_path).await
14413 }
14414}
14415
14416async fn populate_labels_for_symbols(
14417 symbols: Vec<CoreSymbol>,
14418 language_registry: &Arc<LanguageRegistry>,
14419 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14420 output: &mut Vec<Symbol>,
14421) {
14422 #[allow(clippy::mutable_key_type)]
14423 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14424
14425 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14426 for symbol in symbols {
14427 let Some(file_name) = symbol.path.file_name() else {
14428 continue;
14429 };
14430 let language = language_registry
14431 .load_language_for_file_path(Path::new(file_name))
14432 .await
14433 .ok()
14434 .or_else(|| {
14435 unknown_paths.insert(file_name.into());
14436 None
14437 });
14438 symbols_by_language
14439 .entry(language)
14440 .or_default()
14441 .push(symbol);
14442 }
14443
14444 for unknown_path in unknown_paths {
14445 log::info!("no language found for symbol in file {unknown_path:?}");
14446 }
14447
14448 let mut label_params = Vec::new();
14449 for (language, mut symbols) in symbols_by_language {
14450 label_params.clear();
14451 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14452 name: mem::take(&mut symbol.name),
14453 kind: symbol.kind,
14454 container_name: symbol.container_name.take(),
14455 }));
14456
14457 let mut labels = Vec::new();
14458 if let Some(language) = language {
14459 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14460 language_registry
14461 .lsp_adapters(&language.name())
14462 .first()
14463 .cloned()
14464 });
14465 if let Some(lsp_adapter) = lsp_adapter {
14466 labels = lsp_adapter
14467 .labels_for_symbols(&label_params, &language)
14468 .await
14469 .log_err()
14470 .unwrap_or_default();
14471 }
14472 }
14473
14474 for (
14475 (
14476 symbol,
14477 language::Symbol {
14478 name,
14479 container_name,
14480 ..
14481 },
14482 ),
14483 label,
14484 ) in symbols
14485 .into_iter()
14486 .zip(label_params.drain(..))
14487 .zip(labels.into_iter().chain(iter::repeat(None)))
14488 {
14489 output.push(Symbol {
14490 language_server_name: symbol.language_server_name,
14491 source_worktree_id: symbol.source_worktree_id,
14492 source_language_server_id: symbol.source_language_server_id,
14493 path: symbol.path,
14494 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14495 name,
14496 kind: symbol.kind,
14497 range: symbol.range,
14498 container_name,
14499 });
14500 }
14501 }
14502}
14503
14504pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14505 text.lines()
14506 .map(|line| line.trim())
14507 .filter(|line| !line.is_empty())
14508 .join(separator)
14509}
14510
14511fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14512 match server.capabilities().text_document_sync.as_ref()? {
14513 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14514 // Server wants didSave but didn't specify includeText.
14515 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14516 // Server doesn't want didSave at all.
14517 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14518 // Server provided SaveOptions.
14519 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14520 Some(save_options.include_text.unwrap_or(false))
14521 }
14522 },
14523 // We do not have any save info. Kind affects didChange only.
14524 lsp::TextDocumentSyncCapability::Kind(_) => None,
14525 }
14526}
14527
14528/// Completion items are displayed in a `UniformList`.
14529/// Usually, those items are single-line strings, but in LSP responses,
14530/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14531/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14532/// 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,
14533/// breaking the completions menu presentation.
14534///
14535/// 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.
14536pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14537 let mut new_text = String::with_capacity(label.text.len());
14538 let mut offset_map = vec![0; label.text.len() + 1];
14539 let mut last_char_was_space = false;
14540 let mut new_idx = 0;
14541 let chars = label.text.char_indices().fuse();
14542 let mut newlines_removed = false;
14543
14544 for (idx, c) in chars {
14545 offset_map[idx] = new_idx;
14546
14547 match c {
14548 '\n' if last_char_was_space => {
14549 newlines_removed = true;
14550 }
14551 '\t' | ' ' if last_char_was_space => {}
14552 '\n' if !last_char_was_space => {
14553 new_text.push(' ');
14554 new_idx += 1;
14555 last_char_was_space = true;
14556 newlines_removed = true;
14557 }
14558 ' ' | '\t' => {
14559 new_text.push(' ');
14560 new_idx += 1;
14561 last_char_was_space = true;
14562 }
14563 _ => {
14564 new_text.push(c);
14565 new_idx += c.len_utf8();
14566 last_char_was_space = false;
14567 }
14568 }
14569 }
14570 offset_map[label.text.len()] = new_idx;
14571
14572 // Only modify the label if newlines were removed.
14573 if !newlines_removed {
14574 return;
14575 }
14576
14577 let last_index = new_idx;
14578 let mut run_ranges_errors = Vec::new();
14579 label.runs.retain_mut(|(range, _)| {
14580 match offset_map.get(range.start) {
14581 Some(&start) => range.start = start,
14582 None => {
14583 run_ranges_errors.push(range.clone());
14584 return false;
14585 }
14586 }
14587
14588 match offset_map.get(range.end) {
14589 Some(&end) => range.end = end,
14590 None => {
14591 run_ranges_errors.push(range.clone());
14592 range.end = last_index;
14593 }
14594 }
14595 true
14596 });
14597 if !run_ranges_errors.is_empty() {
14598 log::error!(
14599 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14600 label.text
14601 );
14602 }
14603
14604 let mut wrong_filter_range = None;
14605 if label.filter_range == (0..label.text.len()) {
14606 label.filter_range = 0..new_text.len();
14607 } else {
14608 let mut original_filter_range = Some(label.filter_range.clone());
14609 match offset_map.get(label.filter_range.start) {
14610 Some(&start) => label.filter_range.start = start,
14611 None => {
14612 wrong_filter_range = original_filter_range.take();
14613 label.filter_range.start = last_index;
14614 }
14615 }
14616
14617 match offset_map.get(label.filter_range.end) {
14618 Some(&end) => label.filter_range.end = end,
14619 None => {
14620 wrong_filter_range = original_filter_range.take();
14621 label.filter_range.end = last_index;
14622 }
14623 }
14624 }
14625 if let Some(wrong_filter_range) = wrong_filter_range {
14626 log::error!(
14627 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14628 label.text
14629 );
14630 }
14631
14632 label.text = new_text;
14633}
14634
14635/// Apply edits to the buffer that will become part of the formatting transaction.
14636/// Fails if the buffer has been edited since the start of that transaction.
14637fn extend_formatting_transaction(
14638 buffer: &FormattableBuffer,
14639 formatting_transaction_id: text::TransactionId,
14640 cx: &mut AsyncApp,
14641 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14642) -> anyhow::Result<()> {
14643 buffer.handle.update(cx, |buffer, cx| {
14644 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14645 if last_transaction_id != Some(formatting_transaction_id) {
14646 anyhow::bail!("Buffer edited while formatting. Aborting")
14647 }
14648 buffer.start_transaction();
14649 operation(buffer, cx);
14650 if let Some(transaction_id) = buffer.end_transaction(cx) {
14651 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14652 }
14653 Ok(())
14654 })
14655}