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