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 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 async move {
1321 join_all(shutdown_futures).await;
1322 }
1323 }
1324
1325 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1326 match server_state {
1327 LanguageServerState::Running { server, .. } => {
1328 if let Some(shutdown) = server.shutdown() {
1329 shutdown.await;
1330 }
1331 }
1332 LanguageServerState::Starting { startup, .. } => {
1333 if let Some(server) = startup.await
1334 && let Some(shutdown) = server.shutdown()
1335 {
1336 shutdown.await;
1337 }
1338 }
1339 }
1340 Ok(())
1341 }
1342
1343 fn language_servers_for_worktree(
1344 &self,
1345 worktree_id: WorktreeId,
1346 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1347 self.language_server_ids
1348 .iter()
1349 .filter_map(move |(seed, state)| {
1350 if seed.worktree_id != worktree_id {
1351 return None;
1352 }
1353
1354 if let Some(LanguageServerState::Running { server, .. }) =
1355 self.language_servers.get(&state.id)
1356 {
1357 Some(server)
1358 } else {
1359 None
1360 }
1361 })
1362 }
1363
1364 fn language_server_ids_for_project_path(
1365 &self,
1366 project_path: ProjectPath,
1367 language: &Language,
1368 cx: &mut App,
1369 ) -> Vec<LanguageServerId> {
1370 let Some(worktree) = self
1371 .worktree_store
1372 .read(cx)
1373 .worktree_for_id(project_path.worktree_id, cx)
1374 else {
1375 return Vec::new();
1376 };
1377 let delegate: Arc<dyn ManifestDelegate> =
1378 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1379
1380 self.lsp_tree
1381 .get(
1382 project_path,
1383 language.name(),
1384 language.manifest(),
1385 &delegate,
1386 cx,
1387 )
1388 .collect::<Vec<_>>()
1389 }
1390
1391 fn language_server_ids_for_buffer(
1392 &self,
1393 buffer: &Buffer,
1394 cx: &mut App,
1395 ) -> Vec<LanguageServerId> {
1396 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1397 let worktree_id = file.worktree_id(cx);
1398
1399 let path: Arc<RelPath> = file
1400 .path()
1401 .parent()
1402 .map(Arc::from)
1403 .unwrap_or_else(|| file.path().clone());
1404 let worktree_path = ProjectPath { worktree_id, path };
1405 self.language_server_ids_for_project_path(worktree_path, language, cx)
1406 } else {
1407 Vec::new()
1408 }
1409 }
1410
1411 fn language_servers_for_buffer<'a>(
1412 &'a self,
1413 buffer: &'a Buffer,
1414 cx: &'a mut App,
1415 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1416 self.language_server_ids_for_buffer(buffer, cx)
1417 .into_iter()
1418 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1419 LanguageServerState::Running {
1420 adapter, server, ..
1421 } => Some((adapter, server)),
1422 _ => None,
1423 })
1424 }
1425
1426 async fn execute_code_action_kind_locally(
1427 lsp_store: WeakEntity<LspStore>,
1428 mut buffers: Vec<Entity<Buffer>>,
1429 kind: CodeActionKind,
1430 push_to_history: bool,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent code actions requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.read(cx).remote_id())
1440 });
1441 })?;
1442 let _cleanup = defer({
1443 let this = lsp_store.clone();
1444 let mut cx = cx.clone();
1445 let buffers = &buffers;
1446 move || {
1447 this.update(&mut cx, |this, cx| {
1448 let this = this.as_local_mut().unwrap();
1449 for buffer in buffers {
1450 this.buffers_being_formatted
1451 .remove(&buffer.read(cx).remote_id());
1452 }
1453 })
1454 .ok();
1455 }
1456 });
1457 let mut project_transaction = ProjectTransaction::default();
1458
1459 for buffer in &buffers {
1460 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1461 buffer.update(cx, |buffer, cx| {
1462 lsp_store
1463 .as_local()
1464 .unwrap()
1465 .language_servers_for_buffer(buffer, cx)
1466 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1467 .collect::<Vec<_>>()
1468 })
1469 })?;
1470 for (_, language_server) in adapters_and_servers.iter() {
1471 let actions = Self::get_server_code_actions_from_action_kinds(
1472 &lsp_store,
1473 language_server.server_id(),
1474 vec![kind.clone()],
1475 buffer,
1476 cx,
1477 )
1478 .await?;
1479 Self::execute_code_actions_on_server(
1480 &lsp_store,
1481 language_server,
1482 actions,
1483 push_to_history,
1484 &mut project_transaction,
1485 cx,
1486 )
1487 .await?;
1488 }
1489 }
1490 Ok(project_transaction)
1491 }
1492
1493 async fn format_locally(
1494 lsp_store: WeakEntity<LspStore>,
1495 mut buffers: Vec<FormattableBuffer>,
1496 push_to_history: bool,
1497 trigger: FormatTrigger,
1498 logger: zlog::Logger,
1499 cx: &mut AsyncApp,
1500 ) -> anyhow::Result<ProjectTransaction> {
1501 // Do not allow multiple concurrent formatting requests for the
1502 // same buffer.
1503 lsp_store.update(cx, |this, cx| {
1504 let this = this.as_local_mut().unwrap();
1505 buffers.retain(|buffer| {
1506 this.buffers_being_formatted
1507 .insert(buffer.handle.read(cx).remote_id())
1508 });
1509 })?;
1510
1511 let _cleanup = defer({
1512 let this = lsp_store.clone();
1513 let mut cx = cx.clone();
1514 let buffers = &buffers;
1515 move || {
1516 this.update(&mut cx, |this, cx| {
1517 let this = this.as_local_mut().unwrap();
1518 for buffer in buffers {
1519 this.buffers_being_formatted
1520 .remove(&buffer.handle.read(cx).remote_id());
1521 }
1522 })
1523 .ok();
1524 }
1525 });
1526
1527 let mut project_transaction = ProjectTransaction::default();
1528
1529 for buffer in &buffers {
1530 zlog::debug!(
1531 logger =>
1532 "formatting buffer '{:?}'",
1533 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1534 );
1535 // Create an empty transaction to hold all of the formatting edits.
1536 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1537 // ensure no transactions created while formatting are
1538 // grouped with the previous transaction in the history
1539 // based on the transaction group interval
1540 buffer.finalize_last_transaction();
1541 buffer
1542 .start_transaction()
1543 .context("transaction already open")?;
1544 buffer.end_transaction(cx);
1545 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1546 buffer.finalize_last_transaction();
1547 anyhow::Ok(transaction_id)
1548 })?;
1549
1550 let result = Self::format_buffer_locally(
1551 lsp_store.clone(),
1552 buffer,
1553 formatting_transaction_id,
1554 trigger,
1555 logger,
1556 cx,
1557 )
1558 .await;
1559
1560 buffer.handle.update(cx, |buffer, cx| {
1561 let Some(formatting_transaction) =
1562 buffer.get_transaction(formatting_transaction_id).cloned()
1563 else {
1564 zlog::warn!(logger => "no formatting transaction");
1565 return;
1566 };
1567 if formatting_transaction.edit_ids.is_empty() {
1568 zlog::debug!(logger => "no changes made while formatting");
1569 buffer.forget_transaction(formatting_transaction_id);
1570 return;
1571 }
1572 if !push_to_history {
1573 zlog::trace!(logger => "forgetting format transaction");
1574 buffer.forget_transaction(formatting_transaction.id);
1575 }
1576 project_transaction
1577 .0
1578 .insert(cx.entity(), formatting_transaction);
1579 });
1580
1581 result?;
1582 }
1583
1584 Ok(project_transaction)
1585 }
1586
1587 async fn format_buffer_locally(
1588 lsp_store: WeakEntity<LspStore>,
1589 buffer: &FormattableBuffer,
1590 formatting_transaction_id: clock::Lamport,
1591 trigger: FormatTrigger,
1592 logger: zlog::Logger,
1593 cx: &mut AsyncApp,
1594 ) -> Result<()> {
1595 let (adapters_and_servers, settings, request_timeout) =
1596 lsp_store.update(cx, |lsp_store, cx| {
1597 buffer.handle.update(cx, |buffer, cx| {
1598 let adapters_and_servers = lsp_store
1599 .as_local()
1600 .unwrap()
1601 .language_servers_for_buffer(buffer, cx)
1602 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1603 .collect::<Vec<_>>();
1604 let settings =
1605 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1606 .into_owned();
1607 let request_timeout = ProjectSettings::get_global(cx)
1608 .global_lsp_settings
1609 .get_request_timeout();
1610 (adapters_and_servers, settings, request_timeout)
1611 })
1612 })?;
1613
1614 // handle whitespace formatting
1615 if settings.remove_trailing_whitespace_on_save {
1616 zlog::trace!(logger => "removing trailing whitespace");
1617 let diff = buffer
1618 .handle
1619 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1620 .await;
1621 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1622 buffer.apply_diff(diff, cx);
1623 })?;
1624 }
1625
1626 if settings.ensure_final_newline_on_save {
1627 zlog::trace!(logger => "ensuring final newline");
1628 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1629 buffer.ensure_final_newline(cx);
1630 })?;
1631 }
1632
1633 // Formatter for `code_actions_on_format` that runs before
1634 // the rest of the formatters
1635 let mut code_actions_on_format_formatters = None;
1636 let should_run_code_actions_on_format = !matches!(
1637 (trigger, &settings.format_on_save),
1638 (FormatTrigger::Save, &FormatOnSave::Off)
1639 );
1640 if should_run_code_actions_on_format {
1641 let have_code_actions_to_run_on_format = settings
1642 .code_actions_on_format
1643 .values()
1644 .any(|enabled| *enabled);
1645 if have_code_actions_to_run_on_format {
1646 zlog::trace!(logger => "going to run code actions on format");
1647 code_actions_on_format_formatters = Some(
1648 settings
1649 .code_actions_on_format
1650 .iter()
1651 .filter_map(|(action, enabled)| enabled.then_some(action))
1652 .cloned()
1653 .map(Formatter::CodeAction)
1654 .collect::<Vec<_>>(),
1655 );
1656 }
1657 }
1658
1659 let formatters = match (trigger, &settings.format_on_save) {
1660 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1661 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1662 settings.formatter.as_ref()
1663 }
1664 };
1665
1666 let formatters = code_actions_on_format_formatters
1667 .iter()
1668 .flatten()
1669 .chain(formatters);
1670
1671 for formatter in formatters {
1672 let formatter = if formatter == &Formatter::Auto {
1673 if settings.prettier.allowed {
1674 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1675 &Formatter::Prettier
1676 } else {
1677 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1678 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1679 }
1680 } else {
1681 formatter
1682 };
1683 if let Err(err) = Self::apply_formatter(
1684 formatter,
1685 &lsp_store,
1686 buffer,
1687 formatting_transaction_id,
1688 &adapters_and_servers,
1689 &settings,
1690 request_timeout,
1691 logger,
1692 cx,
1693 )
1694 .await
1695 {
1696 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1697 }
1698 }
1699
1700 Ok(())
1701 }
1702
1703 async fn apply_formatter(
1704 formatter: &Formatter,
1705 lsp_store: &WeakEntity<LspStore>,
1706 buffer: &FormattableBuffer,
1707 formatting_transaction_id: clock::Lamport,
1708 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1709 settings: &LanguageSettings,
1710 request_timeout: Duration,
1711 logger: zlog::Logger,
1712 cx: &mut AsyncApp,
1713 ) -> anyhow::Result<()> {
1714 match formatter {
1715 Formatter::None => {
1716 zlog::trace!(logger => "skipping formatter 'none'");
1717 return Ok(());
1718 }
1719 Formatter::Auto => {
1720 debug_panic!("Auto resolved above");
1721 return Ok(());
1722 }
1723 Formatter::Prettier => {
1724 let logger = zlog::scoped!(logger => "prettier");
1725 zlog::trace!(logger => "formatting");
1726 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1727
1728 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1729 lsp_store.prettier_store().unwrap().downgrade()
1730 })?;
1731 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1732 .await
1733 .transpose()?;
1734 let Some(diff) = diff else {
1735 zlog::trace!(logger => "No changes");
1736 return Ok(());
1737 };
1738
1739 extend_formatting_transaction(
1740 buffer,
1741 formatting_transaction_id,
1742 cx,
1743 |buffer, cx| {
1744 buffer.apply_diff(diff, cx);
1745 },
1746 )?;
1747 }
1748 Formatter::External { command, arguments } => {
1749 let logger = zlog::scoped!(logger => "command");
1750 zlog::trace!(logger => "formatting");
1751 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1752
1753 let diff =
1754 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1755 .await
1756 .with_context(|| {
1757 format!("Failed to format buffer via external command: {}", command)
1758 })?;
1759 let Some(diff) = diff else {
1760 zlog::trace!(logger => "No changes");
1761 return Ok(());
1762 };
1763
1764 extend_formatting_transaction(
1765 buffer,
1766 formatting_transaction_id,
1767 cx,
1768 |buffer, cx| {
1769 buffer.apply_diff(diff, cx);
1770 },
1771 )?;
1772 }
1773 Formatter::LanguageServer(specifier) => {
1774 let logger = zlog::scoped!(logger => "language-server");
1775 zlog::trace!(logger => "formatting");
1776 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1777
1778 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1779 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1780 return Ok(());
1781 };
1782
1783 let language_server = match specifier {
1784 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1785 adapters_and_servers.iter().find_map(|(adapter, server)| {
1786 if adapter.name.0.as_ref() == name {
1787 Some(server.clone())
1788 } else {
1789 None
1790 }
1791 })
1792 }
1793 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1794 .iter()
1795 .find(|(_, server)| Self::server_supports_formatting(server))
1796 .map(|(_, server)| server.clone()),
1797 };
1798
1799 let Some(language_server) = language_server else {
1800 log::debug!(
1801 "No language server found to format buffer '{:?}'. Skipping",
1802 buffer_path_abs.as_path().to_string_lossy()
1803 );
1804 return Ok(());
1805 };
1806
1807 zlog::trace!(
1808 logger =>
1809 "Formatting buffer '{:?}' using language server '{:?}'",
1810 buffer_path_abs.as_path().to_string_lossy(),
1811 language_server.name()
1812 );
1813
1814 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1815 zlog::trace!(logger => "formatting ranges");
1816 Self::format_ranges_via_lsp(
1817 &lsp_store,
1818 &buffer.handle,
1819 ranges,
1820 buffer_path_abs,
1821 &language_server,
1822 &settings,
1823 cx,
1824 )
1825 .await
1826 .context("Failed to format ranges via language server")?
1827 } else {
1828 zlog::trace!(logger => "formatting full");
1829 Self::format_via_lsp(
1830 &lsp_store,
1831 &buffer.handle,
1832 buffer_path_abs,
1833 &language_server,
1834 &settings,
1835 cx,
1836 )
1837 .await
1838 .context("failed to format via language server")?
1839 };
1840
1841 if edits.is_empty() {
1842 zlog::trace!(logger => "No changes");
1843 return Ok(());
1844 }
1845 extend_formatting_transaction(
1846 buffer,
1847 formatting_transaction_id,
1848 cx,
1849 |buffer, cx| {
1850 buffer.edit(edits, None, cx);
1851 },
1852 )?;
1853 }
1854 Formatter::CodeAction(code_action_name) => {
1855 let logger = zlog::scoped!(logger => "code-actions");
1856 zlog::trace!(logger => "formatting");
1857 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1858
1859 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1860 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1861 return Ok(());
1862 };
1863
1864 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1865 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1866
1867 let mut actions_and_servers = Vec::new();
1868
1869 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1870 let actions_result = Self::get_server_code_actions_from_action_kinds(
1871 &lsp_store,
1872 language_server.server_id(),
1873 vec![code_action_kind.clone()],
1874 &buffer.handle,
1875 cx,
1876 )
1877 .await
1878 .with_context(|| {
1879 format!(
1880 "Failed to resolve code action {:?} with language server {}",
1881 code_action_kind,
1882 language_server.name()
1883 )
1884 });
1885 let Ok(actions) = actions_result else {
1886 // note: it may be better to set result to the error and break formatters here
1887 // but for now we try to execute the actions that we can resolve and skip the rest
1888 zlog::error!(
1889 logger =>
1890 "Failed to resolve code action {:?} with language server {}",
1891 code_action_kind,
1892 language_server.name()
1893 );
1894 continue;
1895 };
1896 for action in actions {
1897 actions_and_servers.push((action, index));
1898 }
1899 }
1900
1901 if actions_and_servers.is_empty() {
1902 zlog::warn!(logger => "No code actions were resolved, continuing");
1903 return Ok(());
1904 }
1905
1906 'actions: for (mut action, server_index) in actions_and_servers {
1907 let server = &adapters_and_servers[server_index].1;
1908
1909 let describe_code_action = |action: &CodeAction| {
1910 format!(
1911 "code action '{}' with title \"{}\" on server {}",
1912 action
1913 .lsp_action
1914 .action_kind()
1915 .unwrap_or("unknown".into())
1916 .as_str(),
1917 action.lsp_action.title(),
1918 server.name(),
1919 )
1920 };
1921
1922 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1923
1924 if let Err(err) =
1925 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1926 {
1927 zlog::error!(
1928 logger =>
1929 "Failed to resolve {}. Error: {}",
1930 describe_code_action(&action),
1931 err
1932 );
1933 continue;
1934 }
1935
1936 if let Some(edit) = action.lsp_action.edit().cloned() {
1937 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1938 // but filters out and logs warnings for code actions that require unreasonably
1939 // difficult handling on our part, such as:
1940 // - applying edits that call commands
1941 // which can result in arbitrary workspace edits being sent from the server that
1942 // have no way of being tied back to the command that initiated them (i.e. we
1943 // can't know which edits are part of the format request, or if the server is done sending
1944 // actions in response to the command)
1945 // - actions that create/delete/modify/rename files other than the one we are formatting
1946 // as we then would need to handle such changes correctly in the local history as well
1947 // as the remote history through the ProjectTransaction
1948 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1949 // Supporting these actions is not impossible, but not supported as of yet.
1950 if edit.changes.is_none() && edit.document_changes.is_none() {
1951 zlog::trace!(
1952 logger =>
1953 "No changes for code action. Skipping {}",
1954 describe_code_action(&action),
1955 );
1956 continue;
1957 }
1958
1959 let mut operations = Vec::new();
1960 if let Some(document_changes) = edit.document_changes {
1961 match document_changes {
1962 lsp::DocumentChanges::Edits(edits) => operations.extend(
1963 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1964 ),
1965 lsp::DocumentChanges::Operations(ops) => operations = ops,
1966 }
1967 } else if let Some(changes) = edit.changes {
1968 operations.extend(changes.into_iter().map(|(uri, edits)| {
1969 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1970 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
1971 uri,
1972 version: None,
1973 },
1974 edits: edits.into_iter().map(Edit::Plain).collect(),
1975 })
1976 }));
1977 }
1978
1979 let mut edits = Vec::with_capacity(operations.len());
1980
1981 if operations.is_empty() {
1982 zlog::trace!(
1983 logger =>
1984 "No changes for code action. Skipping {}",
1985 describe_code_action(&action),
1986 );
1987 continue;
1988 }
1989 for operation in operations {
1990 let op = match operation {
1991 lsp::DocumentChangeOperation::Edit(op) => op,
1992 lsp::DocumentChangeOperation::Op(_) => {
1993 zlog::warn!(
1994 logger =>
1995 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1996 describe_code_action(&action),
1997 );
1998 continue 'actions;
1999 }
2000 };
2001 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2002 zlog::warn!(
2003 logger =>
2004 "Failed to convert URI '{:?}' to file path. Skipping {}",
2005 &op.text_document.uri,
2006 describe_code_action(&action),
2007 );
2008 continue 'actions;
2009 };
2010 if &file_path != buffer_path_abs {
2011 zlog::warn!(
2012 logger =>
2013 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2014 file_path,
2015 buffer_path_abs,
2016 describe_code_action(&action),
2017 );
2018 continue 'actions;
2019 }
2020
2021 let mut lsp_edits = Vec::new();
2022 for edit in op.edits {
2023 match edit {
2024 Edit::Plain(edit) => {
2025 if !lsp_edits.contains(&edit) {
2026 lsp_edits.push(edit);
2027 }
2028 }
2029 Edit::Annotated(edit) => {
2030 if !lsp_edits.contains(&edit.text_edit) {
2031 lsp_edits.push(edit.text_edit);
2032 }
2033 }
2034 Edit::Snippet(_) => {
2035 zlog::warn!(
2036 logger =>
2037 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2038 describe_code_action(&action),
2039 );
2040 continue 'actions;
2041 }
2042 }
2043 }
2044 let edits_result = lsp_store
2045 .update(cx, |lsp_store, cx| {
2046 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2047 &buffer.handle,
2048 lsp_edits,
2049 server.server_id(),
2050 op.text_document.version,
2051 cx,
2052 )
2053 })?
2054 .await;
2055 let Ok(resolved_edits) = edits_result else {
2056 zlog::warn!(
2057 logger =>
2058 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2059 buffer_path_abs.as_path(),
2060 describe_code_action(&action),
2061 );
2062 continue 'actions;
2063 };
2064 edits.extend(resolved_edits);
2065 }
2066
2067 if edits.is_empty() {
2068 zlog::warn!(logger => "No edits resolved from LSP");
2069 continue;
2070 }
2071
2072 extend_formatting_transaction(
2073 buffer,
2074 formatting_transaction_id,
2075 cx,
2076 |buffer, cx| {
2077 zlog::info!(
2078 "Applying edits {edits:?}. Content: {:?}",
2079 buffer.text()
2080 );
2081 buffer.edit(edits, None, cx);
2082 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2083 },
2084 )?;
2085 }
2086
2087 let Some(command) = action.lsp_action.command() else {
2088 continue;
2089 };
2090
2091 zlog::warn!(
2092 logger =>
2093 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2094 &command.command,
2095 );
2096
2097 let server_capabilities = server.capabilities();
2098 let available_commands = server_capabilities
2099 .execute_command_provider
2100 .as_ref()
2101 .map(|options| options.commands.as_slice())
2102 .unwrap_or_default();
2103 if !available_commands.contains(&command.command) {
2104 zlog::warn!(
2105 logger =>
2106 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2107 command.command,
2108 server.name(),
2109 );
2110 continue;
2111 }
2112
2113 extend_formatting_transaction(
2114 buffer,
2115 formatting_transaction_id,
2116 cx,
2117 |_, _| {},
2118 )?;
2119 zlog::info!(logger => "Executing command {}", &command.command);
2120
2121 lsp_store.update(cx, |this, _| {
2122 this.as_local_mut()
2123 .unwrap()
2124 .last_workspace_edits_by_language_server
2125 .remove(&server.server_id());
2126 })?;
2127
2128 let execute_command_result = server
2129 .request::<lsp::request::ExecuteCommand>(
2130 lsp::ExecuteCommandParams {
2131 command: command.command.clone(),
2132 arguments: command.arguments.clone().unwrap_or_default(),
2133 ..Default::default()
2134 },
2135 request_timeout,
2136 )
2137 .await
2138 .into_response();
2139
2140 if execute_command_result.is_err() {
2141 zlog::error!(
2142 logger =>
2143 "Failed to execute command '{}' as part of {}",
2144 &command.command,
2145 describe_code_action(&action),
2146 );
2147 continue 'actions;
2148 }
2149
2150 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2151 this.as_local_mut()
2152 .unwrap()
2153 .last_workspace_edits_by_language_server
2154 .remove(&server.server_id())
2155 .unwrap_or_default()
2156 })?;
2157
2158 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2159 {
2160 zlog::trace!(
2161 logger =>
2162 "Successfully captured {} edits that resulted from command {}",
2163 transaction.edit_ids.len(),
2164 &command.command,
2165 );
2166 let transaction_id_project_transaction = transaction.id;
2167 buffer.handle.update(cx, |buffer, _| {
2168 // it may have been removed from history if push_to_history was
2169 // false in deserialize_workspace_edit. If so push it so we
2170 // can merge it with the format transaction
2171 // and pop the combined transaction off the history stack
2172 // later if push_to_history is false
2173 if buffer.get_transaction(transaction.id).is_none() {
2174 buffer.push_transaction(transaction, Instant::now());
2175 }
2176 buffer.merge_transactions(
2177 transaction_id_project_transaction,
2178 formatting_transaction_id,
2179 );
2180 });
2181 }
2182
2183 if project_transaction_command.0.is_empty() {
2184 continue;
2185 }
2186
2187 let mut extra_buffers = String::new();
2188 for buffer in project_transaction_command.0.keys() {
2189 buffer.read_with(cx, |b, cx| {
2190 let Some(path) = b.project_path(cx) else {
2191 return;
2192 };
2193
2194 if !extra_buffers.is_empty() {
2195 extra_buffers.push_str(", ");
2196 }
2197 extra_buffers.push_str(path.path.as_unix_str());
2198 });
2199 }
2200 zlog::warn!(
2201 logger =>
2202 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2203 &command.command,
2204 extra_buffers,
2205 );
2206 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2207 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2208 // add it so it's included, and merge it into the format transaction when its created later
2209 }
2210 }
2211 }
2212
2213 Ok(())
2214 }
2215
2216 pub async fn format_ranges_via_lsp(
2217 this: &WeakEntity<LspStore>,
2218 buffer_handle: &Entity<Buffer>,
2219 ranges: &[Range<Anchor>],
2220 abs_path: &Path,
2221 language_server: &Arc<LanguageServer>,
2222 settings: &LanguageSettings,
2223 cx: &mut AsyncApp,
2224 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2225 let capabilities = &language_server.capabilities();
2226 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2227 if range_formatting_provider == Some(&OneOf::Left(false)) {
2228 anyhow::bail!(
2229 "{} language server does not support range formatting",
2230 language_server.name()
2231 );
2232 }
2233
2234 let uri = file_path_to_lsp_url(abs_path)?;
2235 let text_document = lsp::TextDocumentIdentifier::new(uri);
2236
2237 let request_timeout = cx.update(|app| {
2238 ProjectSettings::get_global(app)
2239 .global_lsp_settings
2240 .get_request_timeout()
2241 });
2242 let lsp_edits = {
2243 let mut lsp_ranges = Vec::new();
2244 this.update(cx, |_this, cx| {
2245 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2246 // not have been sent to the language server. This seems like a fairly systemic
2247 // issue, though, the resolution probably is not specific to formatting.
2248 //
2249 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2250 // LSP.
2251 let snapshot = buffer_handle.read(cx).snapshot();
2252 for range in ranges {
2253 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2254 }
2255 anyhow::Ok(())
2256 })??;
2257
2258 let mut edits = None;
2259 for range in lsp_ranges {
2260 if let Some(mut edit) = language_server
2261 .request::<lsp::request::RangeFormatting>(
2262 lsp::DocumentRangeFormattingParams {
2263 text_document: text_document.clone(),
2264 range,
2265 options: lsp_command::lsp_formatting_options(settings),
2266 work_done_progress_params: Default::default(),
2267 },
2268 request_timeout,
2269 )
2270 .await
2271 .into_response()?
2272 {
2273 edits.get_or_insert_with(Vec::new).append(&mut edit);
2274 }
2275 }
2276 edits
2277 };
2278
2279 if let Some(lsp_edits) = lsp_edits {
2280 this.update(cx, |this, cx| {
2281 this.as_local_mut().unwrap().edits_from_lsp(
2282 buffer_handle,
2283 lsp_edits,
2284 language_server.server_id(),
2285 None,
2286 cx,
2287 )
2288 })?
2289 .await
2290 } else {
2291 Ok(Vec::with_capacity(0))
2292 }
2293 }
2294
2295 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2296 let capabilities = server.capabilities();
2297 let formatting = capabilities.document_formatting_provider.as_ref();
2298 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2299 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2300 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2301 }
2302
2303 async fn format_via_lsp(
2304 this: &WeakEntity<LspStore>,
2305 buffer: &Entity<Buffer>,
2306 abs_path: &Path,
2307 language_server: &Arc<LanguageServer>,
2308 settings: &LanguageSettings,
2309 cx: &mut AsyncApp,
2310 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2311 let logger = zlog::scoped!("lsp_format");
2312 zlog::debug!(logger => "Formatting via LSP");
2313
2314 let uri = file_path_to_lsp_url(abs_path)?;
2315 let text_document = lsp::TextDocumentIdentifier::new(uri);
2316 let capabilities = &language_server.capabilities();
2317
2318 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2319 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2320
2321 let request_timeout = cx.update(|app| {
2322 ProjectSettings::get_global(app)
2323 .global_lsp_settings
2324 .get_request_timeout()
2325 });
2326
2327 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2328 let _timer = zlog::time!(logger => "format-full");
2329 language_server
2330 .request::<lsp::request::Formatting>(
2331 lsp::DocumentFormattingParams {
2332 text_document,
2333 options: lsp_command::lsp_formatting_options(settings),
2334 work_done_progress_params: Default::default(),
2335 },
2336 request_timeout,
2337 )
2338 .await
2339 .into_response()?
2340 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2341 let _timer = zlog::time!(logger => "format-range");
2342 let buffer_start = lsp::Position::new(0, 0);
2343 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2344 language_server
2345 .request::<lsp::request::RangeFormatting>(
2346 lsp::DocumentRangeFormattingParams {
2347 text_document: text_document.clone(),
2348 range: lsp::Range::new(buffer_start, buffer_end),
2349 options: lsp_command::lsp_formatting_options(settings),
2350 work_done_progress_params: Default::default(),
2351 },
2352 request_timeout,
2353 )
2354 .await
2355 .into_response()?
2356 } else {
2357 None
2358 };
2359
2360 if let Some(lsp_edits) = lsp_edits {
2361 this.update(cx, |this, cx| {
2362 this.as_local_mut().unwrap().edits_from_lsp(
2363 buffer,
2364 lsp_edits,
2365 language_server.server_id(),
2366 None,
2367 cx,
2368 )
2369 })?
2370 .await
2371 } else {
2372 Ok(Vec::with_capacity(0))
2373 }
2374 }
2375
2376 async fn format_via_external_command(
2377 buffer: &FormattableBuffer,
2378 command: &str,
2379 arguments: Option<&[String]>,
2380 cx: &mut AsyncApp,
2381 ) -> Result<Option<Diff>> {
2382 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2383 let file = File::from_dyn(buffer.file())?;
2384 let worktree = file.worktree.read(cx);
2385 let mut worktree_path = worktree.abs_path().to_path_buf();
2386 if worktree.root_entry()?.is_file() {
2387 worktree_path.pop();
2388 }
2389 Some(worktree_path)
2390 });
2391
2392 use util::command::Stdio;
2393 let mut child = util::command::new_command(command);
2394
2395 if let Some(buffer_env) = buffer.env.as_ref() {
2396 child.envs(buffer_env);
2397 }
2398
2399 if let Some(working_dir_path) = working_dir_path {
2400 child.current_dir(working_dir_path);
2401 }
2402
2403 if let Some(arguments) = arguments {
2404 child.args(arguments.iter().map(|arg| {
2405 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2406 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2407 } else {
2408 arg.replace("{buffer_path}", "Untitled")
2409 }
2410 }));
2411 }
2412
2413 let mut child = child
2414 .stdin(Stdio::piped())
2415 .stdout(Stdio::piped())
2416 .stderr(Stdio::piped())
2417 .spawn()?;
2418
2419 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2420 let text = buffer
2421 .handle
2422 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2423 for chunk in text.chunks() {
2424 stdin.write_all(chunk.as_bytes()).await?;
2425 }
2426 stdin.flush().await?;
2427
2428 let output = child.output().await?;
2429 anyhow::ensure!(
2430 output.status.success(),
2431 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2432 output.status.code(),
2433 String::from_utf8_lossy(&output.stdout),
2434 String::from_utf8_lossy(&output.stderr),
2435 );
2436
2437 let stdout = String::from_utf8(output.stdout)?;
2438 Ok(Some(
2439 buffer
2440 .handle
2441 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2442 .await,
2443 ))
2444 }
2445
2446 async fn try_resolve_code_action(
2447 lang_server: &LanguageServer,
2448 action: &mut CodeAction,
2449 request_timeout: Duration,
2450 ) -> anyhow::Result<()> {
2451 match &mut action.lsp_action {
2452 LspAction::Action(lsp_action) => {
2453 if !action.resolved
2454 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2455 && lsp_action.data.is_some()
2456 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2457 {
2458 **lsp_action = lang_server
2459 .request::<lsp::request::CodeActionResolveRequest>(
2460 *lsp_action.clone(),
2461 request_timeout,
2462 )
2463 .await
2464 .into_response()?;
2465 }
2466 }
2467 LspAction::CodeLens(lens) => {
2468 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2469 *lens = lang_server
2470 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2471 .await
2472 .into_response()?;
2473 }
2474 }
2475 LspAction::Command(_) => {}
2476 }
2477
2478 action.resolved = true;
2479 anyhow::Ok(())
2480 }
2481
2482 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2483 let buffer = buffer_handle.read(cx);
2484
2485 let file = buffer.file().cloned();
2486
2487 let Some(file) = File::from_dyn(file.as_ref()) else {
2488 return;
2489 };
2490 if !file.is_local() {
2491 return;
2492 }
2493 let path = ProjectPath::from_file(file, cx);
2494 let worktree_id = file.worktree_id(cx);
2495 let language = buffer.language().cloned();
2496
2497 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2498 for (server_id, diagnostics) in
2499 diagnostics.get(file.path()).cloned().unwrap_or_default()
2500 {
2501 self.update_buffer_diagnostics(
2502 buffer_handle,
2503 server_id,
2504 None,
2505 None,
2506 None,
2507 Vec::new(),
2508 diagnostics,
2509 cx,
2510 )
2511 .log_err();
2512 }
2513 }
2514 let Some(language) = language else {
2515 return;
2516 };
2517 let Some(snapshot) = self
2518 .worktree_store
2519 .read(cx)
2520 .worktree_for_id(worktree_id, cx)
2521 .map(|worktree| worktree.read(cx).snapshot())
2522 else {
2523 return;
2524 };
2525 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2526
2527 for server_id in
2528 self.lsp_tree
2529 .get(path, language.name(), language.manifest(), &delegate, cx)
2530 {
2531 let server = self
2532 .language_servers
2533 .get(&server_id)
2534 .and_then(|server_state| {
2535 if let LanguageServerState::Running { server, .. } = server_state {
2536 Some(server.clone())
2537 } else {
2538 None
2539 }
2540 });
2541 let server = match server {
2542 Some(server) => server,
2543 None => continue,
2544 };
2545
2546 buffer_handle.update(cx, |buffer, cx| {
2547 buffer.set_completion_triggers(
2548 server.server_id(),
2549 server
2550 .capabilities()
2551 .completion_provider
2552 .as_ref()
2553 .and_then(|provider| {
2554 provider
2555 .trigger_characters
2556 .as_ref()
2557 .map(|characters| characters.iter().cloned().collect())
2558 })
2559 .unwrap_or_default(),
2560 cx,
2561 );
2562 });
2563 }
2564 }
2565
2566 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2567 buffer.update(cx, |buffer, cx| {
2568 let Some(language) = buffer.language() else {
2569 return;
2570 };
2571 let path = ProjectPath {
2572 worktree_id: old_file.worktree_id(cx),
2573 path: old_file.path.clone(),
2574 };
2575 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2576 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2577 buffer.set_completion_triggers(server_id, Default::default(), cx);
2578 }
2579 });
2580 }
2581
2582 fn update_buffer_diagnostics(
2583 &mut self,
2584 buffer: &Entity<Buffer>,
2585 server_id: LanguageServerId,
2586 registration_id: Option<Option<SharedString>>,
2587 result_id: Option<SharedString>,
2588 version: Option<i32>,
2589 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2590 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2591 cx: &mut Context<LspStore>,
2592 ) -> Result<()> {
2593 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2594 Ordering::Equal
2595 .then_with(|| b.is_primary.cmp(&a.is_primary))
2596 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2597 .then_with(|| a.severity.cmp(&b.severity))
2598 .then_with(|| a.message.cmp(&b.message))
2599 }
2600
2601 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2602 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2603 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2604
2605 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2606 Ordering::Equal
2607 .then_with(|| a.range.start.cmp(&b.range.start))
2608 .then_with(|| b.range.end.cmp(&a.range.end))
2609 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2610 });
2611
2612 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2613
2614 let edits_since_save = std::cell::LazyCell::new(|| {
2615 let saved_version = buffer.read(cx).saved_version();
2616 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2617 });
2618
2619 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2620
2621 for (new_diagnostic, entry) in diagnostics {
2622 let start;
2623 let end;
2624 if new_diagnostic && entry.diagnostic.is_disk_based {
2625 // Some diagnostics are based on files on disk instead of buffers'
2626 // current contents. Adjust these diagnostics' ranges to reflect
2627 // any unsaved edits.
2628 // Do not alter the reused ones though, as their coordinates were stored as anchors
2629 // and were properly adjusted on reuse.
2630 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2631 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2632 } else {
2633 start = entry.range.start;
2634 end = entry.range.end;
2635 }
2636
2637 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2638 ..snapshot.clip_point_utf16(end, Bias::Right);
2639
2640 // Expand empty ranges by one codepoint
2641 if range.start == range.end {
2642 // This will be go to the next boundary when being clipped
2643 range.end.column += 1;
2644 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2645 if range.start == range.end && range.end.column > 0 {
2646 range.start.column -= 1;
2647 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2648 }
2649 }
2650
2651 sanitized_diagnostics.push(DiagnosticEntry {
2652 range,
2653 diagnostic: entry.diagnostic,
2654 });
2655 }
2656 drop(edits_since_save);
2657
2658 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2659 buffer.update(cx, |buffer, cx| {
2660 if let Some(registration_id) = registration_id {
2661 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2662 self.buffer_pull_diagnostics_result_ids
2663 .entry(server_id)
2664 .or_default()
2665 .entry(registration_id)
2666 .or_default()
2667 .insert(abs_path, result_id);
2668 }
2669 }
2670
2671 buffer.update_diagnostics(server_id, set, cx)
2672 });
2673
2674 Ok(())
2675 }
2676
2677 fn register_language_server_for_invisible_worktree(
2678 &mut self,
2679 worktree: &Entity<Worktree>,
2680 language_server_id: LanguageServerId,
2681 cx: &mut App,
2682 ) {
2683 let worktree = worktree.read(cx);
2684 let worktree_id = worktree.id();
2685 debug_assert!(!worktree.is_visible());
2686 let Some(mut origin_seed) = self
2687 .language_server_ids
2688 .iter()
2689 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2690 else {
2691 return;
2692 };
2693 origin_seed.worktree_id = worktree_id;
2694 self.language_server_ids
2695 .entry(origin_seed)
2696 .or_insert_with(|| UnifiedLanguageServer {
2697 id: language_server_id,
2698 project_roots: Default::default(),
2699 });
2700 }
2701
2702 fn register_buffer_with_language_servers(
2703 &mut self,
2704 buffer_handle: &Entity<Buffer>,
2705 only_register_servers: HashSet<LanguageServerSelector>,
2706 cx: &mut Context<LspStore>,
2707 ) {
2708 let buffer = buffer_handle.read(cx);
2709 let buffer_id = buffer.remote_id();
2710
2711 let Some(file) = File::from_dyn(buffer.file()) else {
2712 return;
2713 };
2714 if !file.is_local() {
2715 return;
2716 }
2717
2718 let abs_path = file.abs_path(cx);
2719 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2720 return;
2721 };
2722 let initial_snapshot = buffer.text_snapshot();
2723 let worktree_id = file.worktree_id(cx);
2724
2725 let Some(language) = buffer.language().cloned() else {
2726 return;
2727 };
2728 let path: Arc<RelPath> = file
2729 .path()
2730 .parent()
2731 .map(Arc::from)
2732 .unwrap_or_else(|| file.path().clone());
2733 let Some(worktree) = self
2734 .worktree_store
2735 .read(cx)
2736 .worktree_for_id(worktree_id, cx)
2737 else {
2738 return;
2739 };
2740 let language_name = language.name();
2741 let (reused, delegate, servers) = self
2742 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2743 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2744 .unwrap_or_else(|| {
2745 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2746 let delegate: Arc<dyn ManifestDelegate> =
2747 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2748
2749 let servers = self
2750 .lsp_tree
2751 .walk(
2752 ProjectPath { worktree_id, path },
2753 language.name(),
2754 language.manifest(),
2755 &delegate,
2756 cx,
2757 )
2758 .collect::<Vec<_>>();
2759 (false, lsp_delegate, servers)
2760 });
2761 let servers_and_adapters = servers
2762 .into_iter()
2763 .filter_map(|server_node| {
2764 if reused && server_node.server_id().is_none() {
2765 return None;
2766 }
2767 if !only_register_servers.is_empty() {
2768 if let Some(server_id) = server_node.server_id()
2769 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2770 {
2771 return None;
2772 }
2773 if let Some(name) = server_node.name()
2774 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2775 {
2776 return None;
2777 }
2778 }
2779
2780 let server_id = server_node.server_id_or_init(|disposition| {
2781 let path = &disposition.path;
2782
2783 {
2784 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2785
2786 let server_id = self.get_or_insert_language_server(
2787 &worktree,
2788 delegate.clone(),
2789 disposition,
2790 &language_name,
2791 cx,
2792 );
2793
2794 if let Some(state) = self.language_servers.get(&server_id)
2795 && let Ok(uri) = uri
2796 {
2797 state.add_workspace_folder(uri);
2798 };
2799 server_id
2800 }
2801 })?;
2802 let server_state = self.language_servers.get(&server_id)?;
2803 if let LanguageServerState::Running {
2804 server, adapter, ..
2805 } = server_state
2806 {
2807 Some((server.clone(), adapter.clone()))
2808 } else {
2809 None
2810 }
2811 })
2812 .collect::<Vec<_>>();
2813 for (server, adapter) in servers_and_adapters {
2814 buffer_handle.update(cx, |buffer, cx| {
2815 buffer.set_completion_triggers(
2816 server.server_id(),
2817 server
2818 .capabilities()
2819 .completion_provider
2820 .as_ref()
2821 .and_then(|provider| {
2822 provider
2823 .trigger_characters
2824 .as_ref()
2825 .map(|characters| characters.iter().cloned().collect())
2826 })
2827 .unwrap_or_default(),
2828 cx,
2829 );
2830 });
2831
2832 let snapshot = LspBufferSnapshot {
2833 version: 0,
2834 snapshot: initial_snapshot.clone(),
2835 };
2836
2837 let mut registered = false;
2838 self.buffer_snapshots
2839 .entry(buffer_id)
2840 .or_default()
2841 .entry(server.server_id())
2842 .or_insert_with(|| {
2843 registered = true;
2844 server.register_buffer(
2845 uri.clone(),
2846 adapter.language_id(&language.name()),
2847 0,
2848 initial_snapshot.text(),
2849 );
2850
2851 vec![snapshot]
2852 });
2853
2854 self.buffers_opened_in_servers
2855 .entry(buffer_id)
2856 .or_default()
2857 .insert(server.server_id());
2858 if registered {
2859 cx.emit(LspStoreEvent::LanguageServerUpdate {
2860 language_server_id: server.server_id(),
2861 name: None,
2862 message: proto::update_language_server::Variant::RegisteredForBuffer(
2863 proto::RegisteredForBuffer {
2864 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2865 buffer_id: buffer_id.to_proto(),
2866 },
2867 ),
2868 });
2869 }
2870 }
2871 }
2872
2873 fn reuse_existing_language_server<'lang_name>(
2874 &self,
2875 server_tree: &LanguageServerTree,
2876 worktree: &Entity<Worktree>,
2877 language_name: &'lang_name LanguageName,
2878 cx: &mut App,
2879 ) -> Option<(
2880 Arc<LocalLspAdapterDelegate>,
2881 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2882 )> {
2883 if worktree.read(cx).is_visible() {
2884 return None;
2885 }
2886
2887 let worktree_store = self.worktree_store.read(cx);
2888 let servers = server_tree
2889 .instances
2890 .iter()
2891 .filter(|(worktree_id, _)| {
2892 worktree_store
2893 .worktree_for_id(**worktree_id, cx)
2894 .is_some_and(|worktree| worktree.read(cx).is_visible())
2895 })
2896 .flat_map(|(worktree_id, servers)| {
2897 servers
2898 .roots
2899 .iter()
2900 .flat_map(|(_, language_servers)| language_servers)
2901 .map(move |(_, (server_node, server_languages))| {
2902 (worktree_id, server_node, server_languages)
2903 })
2904 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2905 .map(|(worktree_id, server_node, _)| {
2906 (
2907 *worktree_id,
2908 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2909 )
2910 })
2911 })
2912 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2913 acc.entry(worktree_id)
2914 .or_insert_with(Vec::new)
2915 .push(server_node);
2916 acc
2917 })
2918 .into_values()
2919 .max_by_key(|servers| servers.len())?;
2920
2921 let worktree_id = worktree.read(cx).id();
2922 let apply = move |tree: &mut LanguageServerTree| {
2923 for server_node in &servers {
2924 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2925 }
2926 servers
2927 };
2928
2929 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2930 Some((delegate, apply))
2931 }
2932
2933 pub(crate) fn unregister_old_buffer_from_language_servers(
2934 &mut self,
2935 buffer: &Entity<Buffer>,
2936 old_file: &File,
2937 cx: &mut App,
2938 ) {
2939 let old_path = match old_file.as_local() {
2940 Some(local) => local.abs_path(cx),
2941 None => return,
2942 };
2943
2944 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2945 debug_panic!("{old_path:?} is not parseable as an URI");
2946 return;
2947 };
2948 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2949 }
2950
2951 pub(crate) fn unregister_buffer_from_language_servers(
2952 &mut self,
2953 buffer: &Entity<Buffer>,
2954 file_url: &lsp::Uri,
2955 cx: &mut App,
2956 ) {
2957 buffer.update(cx, |buffer, cx| {
2958 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2959
2960 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2961 if snapshots
2962 .as_mut()
2963 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2964 {
2965 language_server.unregister_buffer(file_url.clone());
2966 }
2967 }
2968 });
2969 }
2970
2971 fn buffer_snapshot_for_lsp_version(
2972 &mut self,
2973 buffer: &Entity<Buffer>,
2974 server_id: LanguageServerId,
2975 version: Option<i32>,
2976 cx: &App,
2977 ) -> Result<TextBufferSnapshot> {
2978 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2979
2980 if let Some(version) = version {
2981 let buffer_id = buffer.read(cx).remote_id();
2982 let snapshots = if let Some(snapshots) = self
2983 .buffer_snapshots
2984 .get_mut(&buffer_id)
2985 .and_then(|m| m.get_mut(&server_id))
2986 {
2987 snapshots
2988 } else if version == 0 {
2989 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2990 // We detect this case and treat it as if the version was `None`.
2991 return Ok(buffer.read(cx).text_snapshot());
2992 } else {
2993 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2994 };
2995
2996 let found_snapshot = snapshots
2997 .binary_search_by_key(&version, |e| e.version)
2998 .map(|ix| snapshots[ix].snapshot.clone())
2999 .map_err(|_| {
3000 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3001 })?;
3002
3003 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3004 Ok(found_snapshot)
3005 } else {
3006 Ok((buffer.read(cx)).text_snapshot())
3007 }
3008 }
3009
3010 async fn get_server_code_actions_from_action_kinds(
3011 lsp_store: &WeakEntity<LspStore>,
3012 language_server_id: LanguageServerId,
3013 code_action_kinds: Vec<lsp::CodeActionKind>,
3014 buffer: &Entity<Buffer>,
3015 cx: &mut AsyncApp,
3016 ) -> Result<Vec<CodeAction>> {
3017 let actions = lsp_store
3018 .update(cx, move |this, cx| {
3019 let request = GetCodeActions {
3020 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3021 kinds: Some(code_action_kinds),
3022 };
3023 let server = LanguageServerToQuery::Other(language_server_id);
3024 this.request_lsp(buffer.clone(), server, request, cx)
3025 })?
3026 .await?;
3027 Ok(actions)
3028 }
3029
3030 pub async fn execute_code_actions_on_server(
3031 lsp_store: &WeakEntity<LspStore>,
3032 language_server: &Arc<LanguageServer>,
3033 actions: Vec<CodeAction>,
3034 push_to_history: bool,
3035 project_transaction: &mut ProjectTransaction,
3036 cx: &mut AsyncApp,
3037 ) -> anyhow::Result<()> {
3038 let request_timeout = cx.update(|app| {
3039 ProjectSettings::get_global(app)
3040 .global_lsp_settings
3041 .get_request_timeout()
3042 });
3043
3044 for mut action in actions {
3045 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3046 .await
3047 .context("resolving a formatting code action")?;
3048
3049 if let Some(edit) = action.lsp_action.edit() {
3050 if edit.changes.is_none() && edit.document_changes.is_none() {
3051 continue;
3052 }
3053
3054 let new = Self::deserialize_workspace_edit(
3055 lsp_store.upgrade().context("project dropped")?,
3056 edit.clone(),
3057 push_to_history,
3058 language_server.clone(),
3059 cx,
3060 )
3061 .await?;
3062 project_transaction.0.extend(new.0);
3063 }
3064
3065 let Some(command) = action.lsp_action.command() else {
3066 continue;
3067 };
3068
3069 let server_capabilities = language_server.capabilities();
3070 let available_commands = server_capabilities
3071 .execute_command_provider
3072 .as_ref()
3073 .map(|options| options.commands.as_slice())
3074 .unwrap_or_default();
3075 if !available_commands.contains(&command.command) {
3076 log::warn!(
3077 "Cannot execute a command {} not listed in the language server capabilities",
3078 command.command
3079 );
3080 continue;
3081 }
3082
3083 lsp_store.update(cx, |lsp_store, _| {
3084 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3085 mode.last_workspace_edits_by_language_server
3086 .remove(&language_server.server_id());
3087 }
3088 })?;
3089
3090 language_server
3091 .request::<lsp::request::ExecuteCommand>(
3092 lsp::ExecuteCommandParams {
3093 command: command.command.clone(),
3094 arguments: command.arguments.clone().unwrap_or_default(),
3095 ..Default::default()
3096 },
3097 request_timeout,
3098 )
3099 .await
3100 .into_response()
3101 .context("execute command")?;
3102
3103 lsp_store.update(cx, |this, _| {
3104 if let LspStoreMode::Local(mode) = &mut this.mode {
3105 project_transaction.0.extend(
3106 mode.last_workspace_edits_by_language_server
3107 .remove(&language_server.server_id())
3108 .unwrap_or_default()
3109 .0,
3110 )
3111 }
3112 })?;
3113 }
3114 Ok(())
3115 }
3116
3117 pub async fn deserialize_text_edits(
3118 this: Entity<LspStore>,
3119 buffer_to_edit: Entity<Buffer>,
3120 edits: Vec<lsp::TextEdit>,
3121 push_to_history: bool,
3122 _: Arc<CachedLspAdapter>,
3123 language_server: Arc<LanguageServer>,
3124 cx: &mut AsyncApp,
3125 ) -> Result<Option<Transaction>> {
3126 let edits = this
3127 .update(cx, |this, cx| {
3128 this.as_local_mut().unwrap().edits_from_lsp(
3129 &buffer_to_edit,
3130 edits,
3131 language_server.server_id(),
3132 None,
3133 cx,
3134 )
3135 })
3136 .await?;
3137
3138 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3139 buffer.finalize_last_transaction();
3140 buffer.start_transaction();
3141 for (range, text) in edits {
3142 buffer.edit([(range, text)], None, cx);
3143 }
3144
3145 if buffer.end_transaction(cx).is_some() {
3146 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3147 if !push_to_history {
3148 buffer.forget_transaction(transaction.id);
3149 }
3150 Some(transaction)
3151 } else {
3152 None
3153 }
3154 });
3155
3156 Ok(transaction)
3157 }
3158
3159 #[allow(clippy::type_complexity)]
3160 pub fn edits_from_lsp(
3161 &mut self,
3162 buffer: &Entity<Buffer>,
3163 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3164 server_id: LanguageServerId,
3165 version: Option<i32>,
3166 cx: &mut Context<LspStore>,
3167 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3168 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3169 cx.background_spawn(async move {
3170 let snapshot = snapshot?;
3171 let mut lsp_edits = lsp_edits
3172 .into_iter()
3173 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3174 .collect::<Vec<_>>();
3175
3176 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3177
3178 let mut lsp_edits = lsp_edits.into_iter().peekable();
3179 let mut edits = Vec::new();
3180 while let Some((range, mut new_text)) = lsp_edits.next() {
3181 // Clip invalid ranges provided by the language server.
3182 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3183 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3184
3185 // Combine any LSP edits that are adjacent.
3186 //
3187 // Also, combine LSP edits that are separated from each other by only
3188 // a newline. This is important because for some code actions,
3189 // Rust-analyzer rewrites the entire buffer via a series of edits that
3190 // are separated by unchanged newline characters.
3191 //
3192 // In order for the diffing logic below to work properly, any edits that
3193 // cancel each other out must be combined into one.
3194 while let Some((next_range, next_text)) = lsp_edits.peek() {
3195 if next_range.start.0 > range.end {
3196 if next_range.start.0.row > range.end.row + 1
3197 || next_range.start.0.column > 0
3198 || snapshot.clip_point_utf16(
3199 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3200 Bias::Left,
3201 ) > range.end
3202 {
3203 break;
3204 }
3205 new_text.push('\n');
3206 }
3207 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3208 new_text.push_str(next_text);
3209 lsp_edits.next();
3210 }
3211
3212 // For multiline edits, perform a diff of the old and new text so that
3213 // we can identify the changes more precisely, preserving the locations
3214 // of any anchors positioned in the unchanged regions.
3215 if range.end.row > range.start.row {
3216 let offset = range.start.to_offset(&snapshot);
3217 let old_text = snapshot.text_for_range(range).collect::<String>();
3218 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3219 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3220 (
3221 snapshot.anchor_after(offset + range.start)
3222 ..snapshot.anchor_before(offset + range.end),
3223 replacement,
3224 )
3225 }));
3226 } else if range.end == range.start {
3227 let anchor = snapshot.anchor_after(range.start);
3228 edits.push((anchor..anchor, new_text.into()));
3229 } else {
3230 let edit_start = snapshot.anchor_after(range.start);
3231 let edit_end = snapshot.anchor_before(range.end);
3232 edits.push((edit_start..edit_end, new_text.into()));
3233 }
3234 }
3235
3236 Ok(edits)
3237 })
3238 }
3239
3240 pub(crate) async fn deserialize_workspace_edit(
3241 this: Entity<LspStore>,
3242 edit: lsp::WorkspaceEdit,
3243 push_to_history: bool,
3244 language_server: Arc<LanguageServer>,
3245 cx: &mut AsyncApp,
3246 ) -> Result<ProjectTransaction> {
3247 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3248
3249 let mut operations = Vec::new();
3250 if let Some(document_changes) = edit.document_changes {
3251 match document_changes {
3252 lsp::DocumentChanges::Edits(edits) => {
3253 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3254 }
3255 lsp::DocumentChanges::Operations(ops) => operations = ops,
3256 }
3257 } else if let Some(changes) = edit.changes {
3258 operations.extend(changes.into_iter().map(|(uri, edits)| {
3259 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3260 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3261 uri,
3262 version: None,
3263 },
3264 edits: edits.into_iter().map(Edit::Plain).collect(),
3265 })
3266 }));
3267 }
3268
3269 let mut project_transaction = ProjectTransaction::default();
3270 for operation in operations {
3271 match operation {
3272 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3273 let abs_path = op
3274 .uri
3275 .to_file_path()
3276 .map_err(|()| anyhow!("can't convert URI to path"))?;
3277
3278 if let Some(parent_path) = abs_path.parent() {
3279 fs.create_dir(parent_path).await?;
3280 }
3281 if abs_path.ends_with("/") {
3282 fs.create_dir(&abs_path).await?;
3283 } else {
3284 fs.create_file(
3285 &abs_path,
3286 op.options
3287 .map(|options| fs::CreateOptions {
3288 overwrite: options.overwrite.unwrap_or(false),
3289 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3290 })
3291 .unwrap_or_default(),
3292 )
3293 .await?;
3294 }
3295 }
3296
3297 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3298 let source_abs_path = op
3299 .old_uri
3300 .to_file_path()
3301 .map_err(|()| anyhow!("can't convert URI to path"))?;
3302 let target_abs_path = op
3303 .new_uri
3304 .to_file_path()
3305 .map_err(|()| anyhow!("can't convert URI to path"))?;
3306
3307 let options = fs::RenameOptions {
3308 overwrite: op
3309 .options
3310 .as_ref()
3311 .and_then(|options| options.overwrite)
3312 .unwrap_or(false),
3313 ignore_if_exists: op
3314 .options
3315 .as_ref()
3316 .and_then(|options| options.ignore_if_exists)
3317 .unwrap_or(false),
3318 create_parents: true,
3319 };
3320
3321 fs.rename(&source_abs_path, &target_abs_path, options)
3322 .await?;
3323 }
3324
3325 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3326 let abs_path = op
3327 .uri
3328 .to_file_path()
3329 .map_err(|()| anyhow!("can't convert URI to path"))?;
3330 let options = op
3331 .options
3332 .map(|options| fs::RemoveOptions {
3333 recursive: options.recursive.unwrap_or(false),
3334 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3335 })
3336 .unwrap_or_default();
3337 if abs_path.ends_with("/") {
3338 fs.remove_dir(&abs_path, options).await?;
3339 } else {
3340 fs.remove_file(&abs_path, options).await?;
3341 }
3342 }
3343
3344 lsp::DocumentChangeOperation::Edit(op) => {
3345 let buffer_to_edit = this
3346 .update(cx, |this, cx| {
3347 this.open_local_buffer_via_lsp(
3348 op.text_document.uri.clone(),
3349 language_server.server_id(),
3350 cx,
3351 )
3352 })
3353 .await?;
3354
3355 let edits = this
3356 .update(cx, |this, cx| {
3357 let path = buffer_to_edit.read(cx).project_path(cx);
3358 let active_entry = this.active_entry;
3359 let is_active_entry = path.is_some_and(|project_path| {
3360 this.worktree_store
3361 .read(cx)
3362 .entry_for_path(&project_path, cx)
3363 .is_some_and(|entry| Some(entry.id) == active_entry)
3364 });
3365 let local = this.as_local_mut().unwrap();
3366
3367 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3368 for edit in op.edits {
3369 match edit {
3370 Edit::Plain(edit) => {
3371 if !edits.contains(&edit) {
3372 edits.push(edit)
3373 }
3374 }
3375 Edit::Annotated(edit) => {
3376 if !edits.contains(&edit.text_edit) {
3377 edits.push(edit.text_edit)
3378 }
3379 }
3380 Edit::Snippet(edit) => {
3381 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3382 else {
3383 continue;
3384 };
3385
3386 if is_active_entry {
3387 snippet_edits.push((edit.range, snippet));
3388 } else {
3389 // Since this buffer is not focused, apply a normal edit.
3390 let new_edit = TextEdit {
3391 range: edit.range,
3392 new_text: snippet.text,
3393 };
3394 if !edits.contains(&new_edit) {
3395 edits.push(new_edit);
3396 }
3397 }
3398 }
3399 }
3400 }
3401 if !snippet_edits.is_empty() {
3402 let buffer_id = buffer_to_edit.read(cx).remote_id();
3403 let version = if let Some(buffer_version) = op.text_document.version
3404 {
3405 local
3406 .buffer_snapshot_for_lsp_version(
3407 &buffer_to_edit,
3408 language_server.server_id(),
3409 Some(buffer_version),
3410 cx,
3411 )
3412 .ok()
3413 .map(|snapshot| snapshot.version)
3414 } else {
3415 Some(buffer_to_edit.read(cx).saved_version().clone())
3416 };
3417
3418 let most_recent_edit =
3419 version.and_then(|version| version.most_recent());
3420 // Check if the edit that triggered that edit has been made by this participant.
3421
3422 if let Some(most_recent_edit) = most_recent_edit {
3423 cx.emit(LspStoreEvent::SnippetEdit {
3424 buffer_id,
3425 edits: snippet_edits,
3426 most_recent_edit,
3427 });
3428 }
3429 }
3430
3431 local.edits_from_lsp(
3432 &buffer_to_edit,
3433 edits,
3434 language_server.server_id(),
3435 op.text_document.version,
3436 cx,
3437 )
3438 })
3439 .await?;
3440
3441 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3442 buffer.finalize_last_transaction();
3443 buffer.start_transaction();
3444 for (range, text) in edits {
3445 buffer.edit([(range, text)], None, cx);
3446 }
3447
3448 buffer.end_transaction(cx).and_then(|transaction_id| {
3449 if push_to_history {
3450 buffer.finalize_last_transaction();
3451 buffer.get_transaction(transaction_id).cloned()
3452 } else {
3453 buffer.forget_transaction(transaction_id)
3454 }
3455 })
3456 });
3457 if let Some(transaction) = transaction {
3458 project_transaction.0.insert(buffer_to_edit, transaction);
3459 }
3460 }
3461 }
3462 }
3463
3464 Ok(project_transaction)
3465 }
3466
3467 async fn on_lsp_workspace_edit(
3468 this: WeakEntity<LspStore>,
3469 params: lsp::ApplyWorkspaceEditParams,
3470 server_id: LanguageServerId,
3471 cx: &mut AsyncApp,
3472 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3473 let this = this.upgrade().context("project project closed")?;
3474 let language_server = this
3475 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3476 .context("language server not found")?;
3477 let transaction = Self::deserialize_workspace_edit(
3478 this.clone(),
3479 params.edit,
3480 true,
3481 language_server.clone(),
3482 cx,
3483 )
3484 .await
3485 .log_err();
3486 this.update(cx, |this, cx| {
3487 if let Some(transaction) = transaction {
3488 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3489
3490 this.as_local_mut()
3491 .unwrap()
3492 .last_workspace_edits_by_language_server
3493 .insert(server_id, transaction);
3494 }
3495 });
3496 Ok(lsp::ApplyWorkspaceEditResponse {
3497 applied: true,
3498 failed_change: None,
3499 failure_reason: None,
3500 })
3501 }
3502
3503 fn remove_worktree(
3504 &mut self,
3505 id_to_remove: WorktreeId,
3506 cx: &mut Context<LspStore>,
3507 ) -> Vec<LanguageServerId> {
3508 self.restricted_worktrees_tasks.remove(&id_to_remove);
3509 self.diagnostics.remove(&id_to_remove);
3510 self.prettier_store.update(cx, |prettier_store, cx| {
3511 prettier_store.remove_worktree(id_to_remove, cx);
3512 });
3513
3514 let mut servers_to_remove = BTreeSet::default();
3515 let mut servers_to_preserve = HashSet::default();
3516 for (seed, state) in &self.language_server_ids {
3517 if seed.worktree_id == id_to_remove {
3518 servers_to_remove.insert(state.id);
3519 } else {
3520 servers_to_preserve.insert(state.id);
3521 }
3522 }
3523 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3524 self.language_server_ids
3525 .retain(|_, state| !servers_to_remove.contains(&state.id));
3526 for server_id_to_remove in &servers_to_remove {
3527 self.language_server_watched_paths
3528 .remove(server_id_to_remove);
3529 self.language_server_paths_watched_for_rename
3530 .remove(server_id_to_remove);
3531 self.last_workspace_edits_by_language_server
3532 .remove(server_id_to_remove);
3533 self.language_servers.remove(server_id_to_remove);
3534 self.buffer_pull_diagnostics_result_ids
3535 .remove(server_id_to_remove);
3536 self.workspace_pull_diagnostics_result_ids
3537 .remove(server_id_to_remove);
3538 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3539 buffer_servers.remove(server_id_to_remove);
3540 }
3541 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3542 }
3543 servers_to_remove.into_iter().collect()
3544 }
3545
3546 fn rebuild_watched_paths_inner<'a>(
3547 &'a self,
3548 language_server_id: LanguageServerId,
3549 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3550 cx: &mut Context<LspStore>,
3551 ) -> LanguageServerWatchedPathsBuilder {
3552 let worktrees = self
3553 .worktree_store
3554 .read(cx)
3555 .worktrees()
3556 .filter_map(|worktree| {
3557 self.language_servers_for_worktree(worktree.read(cx).id())
3558 .find(|server| server.server_id() == language_server_id)
3559 .map(|_| worktree)
3560 })
3561 .collect::<Vec<_>>();
3562
3563 let mut worktree_globs = HashMap::default();
3564 let mut abs_globs = HashMap::default();
3565 log::trace!(
3566 "Processing new watcher paths for language server with id {}",
3567 language_server_id
3568 );
3569
3570 for watcher in watchers {
3571 if let Some((worktree, literal_prefix, pattern)) =
3572 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3573 {
3574 worktree.update(cx, |worktree, _| {
3575 if let Some((tree, glob)) =
3576 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3577 {
3578 tree.add_path_prefix_to_scan(literal_prefix);
3579 worktree_globs
3580 .entry(tree.id())
3581 .or_insert_with(GlobSetBuilder::new)
3582 .add(glob);
3583 }
3584 });
3585 } else {
3586 let (path, pattern) = match &watcher.glob_pattern {
3587 lsp::GlobPattern::String(s) => {
3588 let watcher_path = SanitizedPath::new(s);
3589 let path = glob_literal_prefix(watcher_path.as_path());
3590 let pattern = watcher_path
3591 .as_path()
3592 .strip_prefix(&path)
3593 .map(|p| p.to_string_lossy().into_owned())
3594 .unwrap_or_else(|e| {
3595 debug_panic!(
3596 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3597 s,
3598 path.display(),
3599 e
3600 );
3601 watcher_path.as_path().to_string_lossy().into_owned()
3602 });
3603 (path, pattern)
3604 }
3605 lsp::GlobPattern::Relative(rp) => {
3606 let Ok(mut base_uri) = match &rp.base_uri {
3607 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3608 lsp::OneOf::Right(base_uri) => base_uri,
3609 }
3610 .to_file_path() else {
3611 continue;
3612 };
3613
3614 let path = glob_literal_prefix(Path::new(&rp.pattern));
3615 let pattern = Path::new(&rp.pattern)
3616 .strip_prefix(&path)
3617 .map(|p| p.to_string_lossy().into_owned())
3618 .unwrap_or_else(|e| {
3619 debug_panic!(
3620 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3621 rp.pattern,
3622 path.display(),
3623 e
3624 );
3625 rp.pattern.clone()
3626 });
3627 base_uri.push(path);
3628 (base_uri, pattern)
3629 }
3630 };
3631
3632 if let Some(glob) = Glob::new(&pattern).log_err() {
3633 if !path
3634 .components()
3635 .any(|c| matches!(c, path::Component::Normal(_)))
3636 {
3637 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3638 // rather than adding a new watcher for `/`.
3639 for worktree in &worktrees {
3640 worktree_globs
3641 .entry(worktree.read(cx).id())
3642 .or_insert_with(GlobSetBuilder::new)
3643 .add(glob.clone());
3644 }
3645 } else {
3646 abs_globs
3647 .entry(path.into())
3648 .or_insert_with(GlobSetBuilder::new)
3649 .add(glob);
3650 }
3651 }
3652 }
3653 }
3654
3655 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3656 for (worktree_id, builder) in worktree_globs {
3657 if let Ok(globset) = builder.build() {
3658 watch_builder.watch_worktree(worktree_id, globset);
3659 }
3660 }
3661 for (abs_path, builder) in abs_globs {
3662 if let Ok(globset) = builder.build() {
3663 watch_builder.watch_abs_path(abs_path, globset);
3664 }
3665 }
3666 watch_builder
3667 }
3668
3669 fn worktree_and_path_for_file_watcher(
3670 worktrees: &[Entity<Worktree>],
3671 watcher: &FileSystemWatcher,
3672 cx: &App,
3673 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3674 worktrees.iter().find_map(|worktree| {
3675 let tree = worktree.read(cx);
3676 let worktree_root_path = tree.abs_path();
3677 let path_style = tree.path_style();
3678 match &watcher.glob_pattern {
3679 lsp::GlobPattern::String(s) => {
3680 let watcher_path = SanitizedPath::new(s);
3681 let relative = watcher_path
3682 .as_path()
3683 .strip_prefix(&worktree_root_path)
3684 .ok()?;
3685 let literal_prefix = glob_literal_prefix(relative);
3686 Some((
3687 worktree.clone(),
3688 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3689 relative.to_string_lossy().into_owned(),
3690 ))
3691 }
3692 lsp::GlobPattern::Relative(rp) => {
3693 let base_uri = match &rp.base_uri {
3694 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3695 lsp::OneOf::Right(base_uri) => base_uri,
3696 }
3697 .to_file_path()
3698 .ok()?;
3699 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3700 let mut literal_prefix = relative.to_owned();
3701 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3702 Some((
3703 worktree.clone(),
3704 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3705 rp.pattern.clone(),
3706 ))
3707 }
3708 }
3709 })
3710 }
3711
3712 fn rebuild_watched_paths(
3713 &mut self,
3714 language_server_id: LanguageServerId,
3715 cx: &mut Context<LspStore>,
3716 ) {
3717 let Some(registrations) = self
3718 .language_server_dynamic_registrations
3719 .get(&language_server_id)
3720 else {
3721 return;
3722 };
3723
3724 let watch_builder = self.rebuild_watched_paths_inner(
3725 language_server_id,
3726 registrations.did_change_watched_files.values().flatten(),
3727 cx,
3728 );
3729 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3730 self.language_server_watched_paths
3731 .insert(language_server_id, watcher);
3732
3733 cx.notify();
3734 }
3735
3736 fn on_lsp_did_change_watched_files(
3737 &mut self,
3738 language_server_id: LanguageServerId,
3739 registration_id: &str,
3740 params: DidChangeWatchedFilesRegistrationOptions,
3741 cx: &mut Context<LspStore>,
3742 ) {
3743 let registrations = self
3744 .language_server_dynamic_registrations
3745 .entry(language_server_id)
3746 .or_default();
3747
3748 registrations
3749 .did_change_watched_files
3750 .insert(registration_id.to_string(), params.watchers);
3751
3752 self.rebuild_watched_paths(language_server_id, cx);
3753 }
3754
3755 fn on_lsp_unregister_did_change_watched_files(
3756 &mut self,
3757 language_server_id: LanguageServerId,
3758 registration_id: &str,
3759 cx: &mut Context<LspStore>,
3760 ) {
3761 let registrations = self
3762 .language_server_dynamic_registrations
3763 .entry(language_server_id)
3764 .or_default();
3765
3766 if registrations
3767 .did_change_watched_files
3768 .remove(registration_id)
3769 .is_some()
3770 {
3771 log::info!(
3772 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3773 language_server_id,
3774 registration_id
3775 );
3776 } else {
3777 log::warn!(
3778 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3779 language_server_id,
3780 registration_id
3781 );
3782 }
3783
3784 self.rebuild_watched_paths(language_server_id, cx);
3785 }
3786
3787 async fn initialization_options_for_adapter(
3788 adapter: Arc<dyn LspAdapter>,
3789 delegate: &Arc<dyn LspAdapterDelegate>,
3790 cx: &mut AsyncApp,
3791 ) -> Result<Option<serde_json::Value>> {
3792 let Some(mut initialization_config) =
3793 adapter.clone().initialization_options(delegate, cx).await?
3794 else {
3795 return Ok(None);
3796 };
3797
3798 for other_adapter in delegate.registered_lsp_adapters() {
3799 if other_adapter.name() == adapter.name() {
3800 continue;
3801 }
3802 if let Ok(Some(target_config)) = other_adapter
3803 .clone()
3804 .additional_initialization_options(adapter.name(), delegate)
3805 .await
3806 {
3807 merge_json_value_into(target_config.clone(), &mut initialization_config);
3808 }
3809 }
3810
3811 Ok(Some(initialization_config))
3812 }
3813
3814 async fn workspace_configuration_for_adapter(
3815 adapter: Arc<dyn LspAdapter>,
3816 delegate: &Arc<dyn LspAdapterDelegate>,
3817 toolchain: Option<Toolchain>,
3818 requested_uri: Option<Uri>,
3819 cx: &mut AsyncApp,
3820 ) -> Result<serde_json::Value> {
3821 let mut workspace_config = adapter
3822 .clone()
3823 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3824 .await?;
3825
3826 for other_adapter in delegate.registered_lsp_adapters() {
3827 if other_adapter.name() == adapter.name() {
3828 continue;
3829 }
3830 if let Ok(Some(target_config)) = other_adapter
3831 .clone()
3832 .additional_workspace_configuration(adapter.name(), delegate, cx)
3833 .await
3834 {
3835 merge_json_value_into(target_config.clone(), &mut workspace_config);
3836 }
3837 }
3838
3839 Ok(workspace_config)
3840 }
3841
3842 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3843 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3844 Some(server.clone())
3845 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3846 Some(Arc::clone(server))
3847 } else {
3848 None
3849 }
3850 }
3851}
3852
3853fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3854 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3855 cx.emit(LspStoreEvent::LanguageServerUpdate {
3856 language_server_id: server.server_id(),
3857 name: Some(server.name()),
3858 message: proto::update_language_server::Variant::MetadataUpdated(
3859 proto::ServerMetadataUpdated {
3860 capabilities: Some(capabilities),
3861 binary: Some(proto::LanguageServerBinaryInfo {
3862 path: server.binary().path.to_string_lossy().into_owned(),
3863 arguments: server
3864 .binary()
3865 .arguments
3866 .iter()
3867 .map(|arg| arg.to_string_lossy().into_owned())
3868 .collect(),
3869 }),
3870 configuration: serde_json::to_string(server.configuration()).ok(),
3871 workspace_folders: server
3872 .workspace_folders()
3873 .iter()
3874 .map(|uri| uri.to_string())
3875 .collect(),
3876 },
3877 ),
3878 });
3879 }
3880}
3881
3882#[derive(Debug)]
3883pub struct FormattableBuffer {
3884 handle: Entity<Buffer>,
3885 abs_path: Option<PathBuf>,
3886 env: Option<HashMap<String, String>>,
3887 ranges: Option<Vec<Range<Anchor>>>,
3888}
3889
3890pub struct RemoteLspStore {
3891 upstream_client: Option<AnyProtoClient>,
3892 upstream_project_id: u64,
3893}
3894
3895pub(crate) enum LspStoreMode {
3896 Local(LocalLspStore), // ssh host and collab host
3897 Remote(RemoteLspStore), // collab guest
3898}
3899
3900impl LspStoreMode {
3901 fn is_local(&self) -> bool {
3902 matches!(self, LspStoreMode::Local(_))
3903 }
3904}
3905
3906pub struct LspStore {
3907 mode: LspStoreMode,
3908 last_formatting_failure: Option<String>,
3909 downstream_client: Option<(AnyProtoClient, u64)>,
3910 nonce: u128,
3911 buffer_store: Entity<BufferStore>,
3912 worktree_store: Entity<WorktreeStore>,
3913 pub languages: Arc<LanguageRegistry>,
3914 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3915 active_entry: Option<ProjectEntryId>,
3916 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3917 _maintain_buffer_languages: Task<()>,
3918 diagnostic_summaries:
3919 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3920 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3921 semantic_token_config: SemanticTokenConfig,
3922 lsp_data: HashMap<BufferId, BufferLspData>,
3923 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3924 next_hint_id: Arc<AtomicUsize>,
3925}
3926
3927#[derive(Debug)]
3928pub struct BufferLspData {
3929 buffer_version: Global,
3930 document_colors: Option<DocumentColorData>,
3931 code_lens: Option<CodeLensData>,
3932 semantic_tokens: Option<SemanticTokensData>,
3933 folding_ranges: Option<FoldingRangeData>,
3934 document_symbols: Option<DocumentSymbolsData>,
3935 inlay_hints: BufferInlayHints,
3936 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3937 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3938}
3939
3940#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3941struct LspKey {
3942 request_type: TypeId,
3943 server_queried: Option<LanguageServerId>,
3944}
3945
3946impl BufferLspData {
3947 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3948 Self {
3949 buffer_version: buffer.read(cx).version(),
3950 document_colors: None,
3951 code_lens: None,
3952 semantic_tokens: None,
3953 folding_ranges: None,
3954 document_symbols: None,
3955 inlay_hints: BufferInlayHints::new(buffer, cx),
3956 lsp_requests: HashMap::default(),
3957 chunk_lsp_requests: HashMap::default(),
3958 }
3959 }
3960
3961 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3962 if let Some(document_colors) = &mut self.document_colors {
3963 document_colors.remove_server_data(for_server);
3964 }
3965
3966 if let Some(code_lens) = &mut self.code_lens {
3967 code_lens.remove_server_data(for_server);
3968 }
3969
3970 self.inlay_hints.remove_server_data(for_server);
3971
3972 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3973 semantic_tokens.remove_server_data(for_server);
3974 }
3975
3976 if let Some(folding_ranges) = &mut self.folding_ranges {
3977 folding_ranges.ranges.remove(&for_server);
3978 }
3979
3980 if let Some(document_symbols) = &mut self.document_symbols {
3981 document_symbols.remove_server_data(for_server);
3982 }
3983 }
3984
3985 #[cfg(any(test, feature = "test-support"))]
3986 pub fn inlay_hints(&self) -> &BufferInlayHints {
3987 &self.inlay_hints
3988 }
3989}
3990
3991#[derive(Debug)]
3992pub enum LspStoreEvent {
3993 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3994 LanguageServerRemoved(LanguageServerId),
3995 LanguageServerUpdate {
3996 language_server_id: LanguageServerId,
3997 name: Option<LanguageServerName>,
3998 message: proto::update_language_server::Variant,
3999 },
4000 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4001 LanguageServerPrompt(LanguageServerPromptRequest),
4002 LanguageDetected {
4003 buffer: Entity<Buffer>,
4004 new_language: Option<Arc<Language>>,
4005 },
4006 Notification(String),
4007 RefreshInlayHints {
4008 server_id: LanguageServerId,
4009 request_id: Option<usize>,
4010 },
4011 RefreshSemanticTokens {
4012 server_id: LanguageServerId,
4013 request_id: Option<usize>,
4014 },
4015 RefreshCodeLens,
4016 DiagnosticsUpdated {
4017 server_id: LanguageServerId,
4018 paths: Vec<ProjectPath>,
4019 },
4020 DiskBasedDiagnosticsStarted {
4021 language_server_id: LanguageServerId,
4022 },
4023 DiskBasedDiagnosticsFinished {
4024 language_server_id: LanguageServerId,
4025 },
4026 SnippetEdit {
4027 buffer_id: BufferId,
4028 edits: Vec<(lsp::Range, Snippet)>,
4029 most_recent_edit: clock::Lamport,
4030 },
4031 WorkspaceEditApplied(ProjectTransaction),
4032}
4033
4034#[derive(Clone, Debug, Serialize)]
4035pub struct LanguageServerStatus {
4036 pub name: LanguageServerName,
4037 pub server_version: Option<SharedString>,
4038 pub server_readable_version: Option<SharedString>,
4039 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4040 pub has_pending_diagnostic_updates: bool,
4041 pub progress_tokens: HashSet<ProgressToken>,
4042 pub worktree: Option<WorktreeId>,
4043 pub binary: Option<LanguageServerBinary>,
4044 pub configuration: Option<Value>,
4045 pub workspace_folders: BTreeSet<Uri>,
4046 pub process_id: Option<u32>,
4047}
4048
4049#[derive(Clone, Debug)]
4050struct CoreSymbol {
4051 pub language_server_name: LanguageServerName,
4052 pub source_worktree_id: WorktreeId,
4053 pub source_language_server_id: LanguageServerId,
4054 pub path: SymbolLocation,
4055 pub name: String,
4056 pub kind: lsp::SymbolKind,
4057 pub range: Range<Unclipped<PointUtf16>>,
4058 pub container_name: Option<String>,
4059}
4060
4061#[derive(Clone, Debug, PartialEq, Eq)]
4062pub enum SymbolLocation {
4063 InProject(ProjectPath),
4064 OutsideProject {
4065 abs_path: Arc<Path>,
4066 signature: [u8; 32],
4067 },
4068}
4069
4070impl SymbolLocation {
4071 fn file_name(&self) -> Option<&str> {
4072 match self {
4073 Self::InProject(path) => path.path.file_name(),
4074 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4075 }
4076 }
4077}
4078
4079impl LspStore {
4080 pub fn init(client: &AnyProtoClient) {
4081 client.add_entity_request_handler(Self::handle_lsp_query);
4082 client.add_entity_message_handler(Self::handle_lsp_query_response);
4083 client.add_entity_request_handler(Self::handle_restart_language_servers);
4084 client.add_entity_request_handler(Self::handle_stop_language_servers);
4085 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4086 client.add_entity_message_handler(Self::handle_start_language_server);
4087 client.add_entity_message_handler(Self::handle_update_language_server);
4088 client.add_entity_message_handler(Self::handle_language_server_log);
4089 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4090 client.add_entity_request_handler(Self::handle_format_buffers);
4091 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4092 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4093 client.add_entity_request_handler(Self::handle_apply_code_action);
4094 client.add_entity_request_handler(Self::handle_get_project_symbols);
4095 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4096 client.add_entity_request_handler(Self::handle_get_color_presentation);
4097 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4098 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4099 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4100 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4101 client.add_entity_request_handler(Self::handle_on_type_formatting);
4102 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4103 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4104 client.add_entity_request_handler(Self::handle_rename_project_entry);
4105 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4106 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4107 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4109 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4110 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4111 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4112
4113 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4114 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4115 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4116 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4117 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4118 client.add_entity_request_handler(
4119 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4120 );
4121 client.add_entity_request_handler(
4122 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4123 );
4124 client.add_entity_request_handler(
4125 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4126 );
4127 }
4128
4129 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4130 match &self.mode {
4131 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4132 _ => None,
4133 }
4134 }
4135
4136 pub fn as_local(&self) -> Option<&LocalLspStore> {
4137 match &self.mode {
4138 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4139 _ => None,
4140 }
4141 }
4142
4143 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4144 match &mut self.mode {
4145 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4146 _ => None,
4147 }
4148 }
4149
4150 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4151 match &self.mode {
4152 LspStoreMode::Remote(RemoteLspStore {
4153 upstream_client: Some(upstream_client),
4154 upstream_project_id,
4155 ..
4156 }) => Some((upstream_client.clone(), *upstream_project_id)),
4157
4158 LspStoreMode::Remote(RemoteLspStore {
4159 upstream_client: None,
4160 ..
4161 }) => None,
4162 LspStoreMode::Local(_) => None,
4163 }
4164 }
4165
4166 pub fn new_local(
4167 buffer_store: Entity<BufferStore>,
4168 worktree_store: Entity<WorktreeStore>,
4169 prettier_store: Entity<PrettierStore>,
4170 toolchain_store: Entity<LocalToolchainStore>,
4171 environment: Entity<ProjectEnvironment>,
4172 manifest_tree: Entity<ManifestTree>,
4173 languages: Arc<LanguageRegistry>,
4174 http_client: Arc<dyn HttpClient>,
4175 fs: Arc<dyn Fs>,
4176 cx: &mut Context<Self>,
4177 ) -> Self {
4178 let yarn = YarnPathStore::new(fs.clone(), cx);
4179 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4180 .detach();
4181 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4182 .detach();
4183 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4184 .detach();
4185 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4186 .detach();
4187 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4188 .detach();
4189 subscribe_to_binary_statuses(&languages, cx).detach();
4190
4191 let _maintain_workspace_config = {
4192 let (sender, receiver) = watch::channel();
4193 (Self::maintain_workspace_config(receiver, cx), sender)
4194 };
4195
4196 Self {
4197 mode: LspStoreMode::Local(LocalLspStore {
4198 weak: cx.weak_entity(),
4199 worktree_store: worktree_store.clone(),
4200
4201 supplementary_language_servers: Default::default(),
4202 languages: languages.clone(),
4203 language_server_ids: Default::default(),
4204 language_servers: Default::default(),
4205 last_workspace_edits_by_language_server: Default::default(),
4206 language_server_watched_paths: Default::default(),
4207 language_server_paths_watched_for_rename: Default::default(),
4208 language_server_dynamic_registrations: Default::default(),
4209 buffers_being_formatted: Default::default(),
4210 buffers_to_refresh_hash_set: HashSet::default(),
4211 buffers_to_refresh_queue: VecDeque::new(),
4212 _background_diagnostics_worker: Task::ready(()).shared(),
4213 buffer_snapshots: Default::default(),
4214 prettier_store,
4215 environment,
4216 http_client,
4217 fs,
4218 yarn,
4219 next_diagnostic_group_id: Default::default(),
4220 diagnostics: Default::default(),
4221 _subscription: cx.on_app_quit(|this, _| {
4222 this.as_local_mut()
4223 .unwrap()
4224 .shutdown_language_servers_on_quit()
4225 }),
4226 lsp_tree: LanguageServerTree::new(
4227 manifest_tree,
4228 languages.clone(),
4229 toolchain_store.clone(),
4230 ),
4231 toolchain_store,
4232 registered_buffers: HashMap::default(),
4233 buffers_opened_in_servers: HashMap::default(),
4234 buffer_pull_diagnostics_result_ids: HashMap::default(),
4235 workspace_pull_diagnostics_result_ids: HashMap::default(),
4236 restricted_worktrees_tasks: HashMap::default(),
4237 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4238 .manifest_file_names(),
4239 }),
4240 last_formatting_failure: None,
4241 downstream_client: None,
4242 buffer_store,
4243 worktree_store,
4244 languages: languages.clone(),
4245 language_server_statuses: Default::default(),
4246 nonce: StdRng::from_os_rng().random(),
4247 diagnostic_summaries: HashMap::default(),
4248 lsp_server_capabilities: HashMap::default(),
4249 semantic_token_config: SemanticTokenConfig::new(cx),
4250 lsp_data: HashMap::default(),
4251 buffer_reload_tasks: HashMap::default(),
4252 next_hint_id: Arc::default(),
4253 active_entry: None,
4254 _maintain_workspace_config,
4255 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4256 }
4257 }
4258
4259 fn send_lsp_proto_request<R: LspCommand>(
4260 &self,
4261 buffer: Entity<Buffer>,
4262 client: AnyProtoClient,
4263 upstream_project_id: u64,
4264 request: R,
4265 cx: &mut Context<LspStore>,
4266 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4267 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4268 return Task::ready(Ok(R::Response::default()));
4269 }
4270 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4271 cx.spawn(async move |this, cx| {
4272 let response = client.request(message).await?;
4273 let this = this.upgrade().context("project dropped")?;
4274 request
4275 .response_from_proto(response, this, buffer, cx.clone())
4276 .await
4277 })
4278 }
4279
4280 pub(super) fn new_remote(
4281 buffer_store: Entity<BufferStore>,
4282 worktree_store: Entity<WorktreeStore>,
4283 languages: Arc<LanguageRegistry>,
4284 upstream_client: AnyProtoClient,
4285 project_id: u64,
4286 cx: &mut Context<Self>,
4287 ) -> Self {
4288 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4289 .detach();
4290 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4291 .detach();
4292 subscribe_to_binary_statuses(&languages, cx).detach();
4293 let _maintain_workspace_config = {
4294 let (sender, receiver) = watch::channel();
4295 (Self::maintain_workspace_config(receiver, cx), sender)
4296 };
4297 Self {
4298 mode: LspStoreMode::Remote(RemoteLspStore {
4299 upstream_client: Some(upstream_client),
4300 upstream_project_id: project_id,
4301 }),
4302 downstream_client: None,
4303 last_formatting_failure: None,
4304 buffer_store,
4305 worktree_store,
4306 languages: languages.clone(),
4307 language_server_statuses: Default::default(),
4308 nonce: StdRng::from_os_rng().random(),
4309 diagnostic_summaries: HashMap::default(),
4310 lsp_server_capabilities: HashMap::default(),
4311 semantic_token_config: SemanticTokenConfig::new(cx),
4312 next_hint_id: Arc::default(),
4313 lsp_data: HashMap::default(),
4314 buffer_reload_tasks: HashMap::default(),
4315 active_entry: None,
4316
4317 _maintain_workspace_config,
4318 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4319 }
4320 }
4321
4322 fn on_buffer_store_event(
4323 &mut self,
4324 _: Entity<BufferStore>,
4325 event: &BufferStoreEvent,
4326 cx: &mut Context<Self>,
4327 ) {
4328 match event {
4329 BufferStoreEvent::BufferAdded(buffer) => {
4330 self.on_buffer_added(buffer, cx).log_err();
4331 }
4332 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4333 let buffer_id = buffer.read(cx).remote_id();
4334 if let Some(local) = self.as_local_mut()
4335 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4336 {
4337 local.reset_buffer(buffer, old_file, cx);
4338
4339 if local.registered_buffers.contains_key(&buffer_id) {
4340 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4341 }
4342 }
4343
4344 self.detect_language_for_buffer(buffer, cx);
4345 if let Some(local) = self.as_local_mut() {
4346 local.initialize_buffer(buffer, cx);
4347 if local.registered_buffers.contains_key(&buffer_id) {
4348 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4349 }
4350 }
4351 }
4352 _ => {}
4353 }
4354 }
4355
4356 fn on_worktree_store_event(
4357 &mut self,
4358 _: Entity<WorktreeStore>,
4359 event: &WorktreeStoreEvent,
4360 cx: &mut Context<Self>,
4361 ) {
4362 match event {
4363 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4364 if !worktree.read(cx).is_local() {
4365 return;
4366 }
4367 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4368 worktree::Event::UpdatedEntries(changes) => {
4369 this.update_local_worktree_language_servers(&worktree, changes, cx);
4370 }
4371 worktree::Event::UpdatedGitRepositories(_)
4372 | worktree::Event::DeletedEntry(_) => {}
4373 })
4374 .detach()
4375 }
4376 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4377 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4378 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4379 }
4380 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4381 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4382 }
4383 WorktreeStoreEvent::WorktreeReleased(..)
4384 | WorktreeStoreEvent::WorktreeOrderChanged
4385 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4386 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4387 }
4388 }
4389
4390 fn on_prettier_store_event(
4391 &mut self,
4392 _: Entity<PrettierStore>,
4393 event: &PrettierStoreEvent,
4394 cx: &mut Context<Self>,
4395 ) {
4396 match event {
4397 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4398 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4399 }
4400 PrettierStoreEvent::LanguageServerAdded {
4401 new_server_id,
4402 name,
4403 prettier_server,
4404 } => {
4405 self.register_supplementary_language_server(
4406 *new_server_id,
4407 name.clone(),
4408 prettier_server.clone(),
4409 cx,
4410 );
4411 }
4412 }
4413 }
4414
4415 fn on_toolchain_store_event(
4416 &mut self,
4417 _: Entity<LocalToolchainStore>,
4418 event: &ToolchainStoreEvent,
4419 _: &mut Context<Self>,
4420 ) {
4421 if let ToolchainStoreEvent::ToolchainActivated = event {
4422 self.request_workspace_config_refresh()
4423 }
4424 }
4425
4426 fn request_workspace_config_refresh(&mut self) {
4427 *self._maintain_workspace_config.1.borrow_mut() = ();
4428 }
4429
4430 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4431 self.as_local().map(|local| local.prettier_store.clone())
4432 }
4433
4434 fn on_buffer_event(
4435 &mut self,
4436 buffer: Entity<Buffer>,
4437 event: &language::BufferEvent,
4438 cx: &mut Context<Self>,
4439 ) {
4440 match event {
4441 language::BufferEvent::Edited { .. } => {
4442 self.on_buffer_edited(buffer, cx);
4443 }
4444
4445 language::BufferEvent::Saved => {
4446 self.on_buffer_saved(buffer, cx);
4447 }
4448
4449 language::BufferEvent::Reloaded => {
4450 self.on_buffer_reloaded(buffer, cx);
4451 }
4452
4453 _ => {}
4454 }
4455 }
4456
4457 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4458 buffer
4459 .read(cx)
4460 .set_language_registry(self.languages.clone());
4461
4462 cx.subscribe(buffer, |this, buffer, event, cx| {
4463 this.on_buffer_event(buffer, event, cx);
4464 })
4465 .detach();
4466
4467 self.detect_language_for_buffer(buffer, cx);
4468 if let Some(local) = self.as_local_mut() {
4469 local.initialize_buffer(buffer, cx);
4470 }
4471
4472 Ok(())
4473 }
4474
4475 pub fn refresh_background_diagnostics_for_buffers(
4476 &mut self,
4477 buffers: HashSet<BufferId>,
4478 cx: &mut Context<Self>,
4479 ) -> Shared<Task<()>> {
4480 let Some(local) = self.as_local_mut() else {
4481 return Task::ready(()).shared();
4482 };
4483 for buffer in buffers {
4484 if local.buffers_to_refresh_hash_set.insert(buffer) {
4485 local.buffers_to_refresh_queue.push_back(buffer);
4486 if local.buffers_to_refresh_queue.len() == 1 {
4487 local._background_diagnostics_worker =
4488 Self::background_diagnostics_worker(cx).shared();
4489 }
4490 }
4491 }
4492
4493 local._background_diagnostics_worker.clone()
4494 }
4495
4496 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4497 let buffer_store = self.buffer_store.clone();
4498 let local = self.as_local_mut()?;
4499 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4500 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4501 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4502 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4503 }
4504 }
4505 None
4506 }
4507
4508 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4509 cx.spawn(async move |this, cx| {
4510 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4511 task.await.log_err();
4512 }
4513 })
4514 }
4515
4516 pub(crate) fn register_buffer_with_language_servers(
4517 &mut self,
4518 buffer: &Entity<Buffer>,
4519 only_register_servers: HashSet<LanguageServerSelector>,
4520 ignore_refcounts: bool,
4521 cx: &mut Context<Self>,
4522 ) -> OpenLspBufferHandle {
4523 let buffer_id = buffer.read(cx).remote_id();
4524 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4525 if let Some(local) = self.as_local_mut() {
4526 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4527 if !ignore_refcounts {
4528 *refcount += 1;
4529 }
4530
4531 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4532 // 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
4533 // 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
4534 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4535 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4536 return handle;
4537 };
4538 if !file.is_local() {
4539 return handle;
4540 }
4541
4542 if ignore_refcounts || *refcount == 1 {
4543 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4544 }
4545 if !ignore_refcounts {
4546 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4547 let refcount = {
4548 let local = lsp_store.as_local_mut().unwrap();
4549 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4550 debug_panic!("bad refcounting");
4551 return;
4552 };
4553
4554 *refcount -= 1;
4555 *refcount
4556 };
4557 if refcount == 0 {
4558 lsp_store.lsp_data.remove(&buffer_id);
4559 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4560 let local = lsp_store.as_local_mut().unwrap();
4561 local.registered_buffers.remove(&buffer_id);
4562
4563 local.buffers_opened_in_servers.remove(&buffer_id);
4564 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4565 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4566
4567 let buffer_abs_path = file.abs_path(cx);
4568 for (_, buffer_pull_diagnostics_result_ids) in
4569 &mut local.buffer_pull_diagnostics_result_ids
4570 {
4571 buffer_pull_diagnostics_result_ids.retain(
4572 |_, buffer_result_ids| {
4573 buffer_result_ids.remove(&buffer_abs_path);
4574 !buffer_result_ids.is_empty()
4575 },
4576 );
4577 }
4578
4579 let diagnostic_updates = local
4580 .language_servers
4581 .keys()
4582 .cloned()
4583 .map(|server_id| DocumentDiagnosticsUpdate {
4584 diagnostics: DocumentDiagnostics {
4585 document_abs_path: buffer_abs_path.clone(),
4586 version: None,
4587 diagnostics: Vec::new(),
4588 },
4589 result_id: None,
4590 registration_id: None,
4591 server_id,
4592 disk_based_sources: Cow::Borrowed(&[]),
4593 })
4594 .collect::<Vec<_>>();
4595
4596 lsp_store
4597 .merge_diagnostic_entries(
4598 diagnostic_updates,
4599 |_, diagnostic, _| {
4600 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4601 },
4602 cx,
4603 )
4604 .context("Clearing diagnostics for the closed buffer")
4605 .log_err();
4606 }
4607 }
4608 })
4609 .detach();
4610 }
4611 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4612 let buffer_id = buffer.read(cx).remote_id().to_proto();
4613 cx.background_spawn(async move {
4614 upstream_client
4615 .request(proto::RegisterBufferWithLanguageServers {
4616 project_id: upstream_project_id,
4617 buffer_id,
4618 only_servers: only_register_servers
4619 .into_iter()
4620 .map(|selector| {
4621 let selector = match selector {
4622 LanguageServerSelector::Id(language_server_id) => {
4623 proto::language_server_selector::Selector::ServerId(
4624 language_server_id.to_proto(),
4625 )
4626 }
4627 LanguageServerSelector::Name(language_server_name) => {
4628 proto::language_server_selector::Selector::Name(
4629 language_server_name.to_string(),
4630 )
4631 }
4632 };
4633 proto::LanguageServerSelector {
4634 selector: Some(selector),
4635 }
4636 })
4637 .collect(),
4638 })
4639 .await
4640 })
4641 .detach();
4642 } else {
4643 // Our remote connection got closed
4644 }
4645 handle
4646 }
4647
4648 fn maintain_buffer_languages(
4649 languages: Arc<LanguageRegistry>,
4650 cx: &mut Context<Self>,
4651 ) -> Task<()> {
4652 let mut subscription = languages.subscribe();
4653 let mut prev_reload_count = languages.reload_count();
4654 cx.spawn(async move |this, cx| {
4655 while let Some(()) = subscription.next().await {
4656 if let Some(this) = this.upgrade() {
4657 // If the language registry has been reloaded, then remove and
4658 // re-assign the languages on all open buffers.
4659 let reload_count = languages.reload_count();
4660 if reload_count > prev_reload_count {
4661 prev_reload_count = reload_count;
4662 this.update(cx, |this, cx| {
4663 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4664 for buffer in buffer_store.buffers() {
4665 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4666 {
4667 buffer.update(cx, |buffer, cx| {
4668 buffer.set_language_async(None, cx)
4669 });
4670 if let Some(local) = this.as_local_mut() {
4671 local.reset_buffer(&buffer, &f, cx);
4672
4673 if local
4674 .registered_buffers
4675 .contains_key(&buffer.read(cx).remote_id())
4676 && let Some(file_url) =
4677 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4678 {
4679 local.unregister_buffer_from_language_servers(
4680 &buffer, &file_url, cx,
4681 );
4682 }
4683 }
4684 }
4685 }
4686 });
4687 });
4688 }
4689
4690 this.update(cx, |this, cx| {
4691 let mut plain_text_buffers = Vec::new();
4692 let mut buffers_with_unknown_injections = Vec::new();
4693 for handle in this.buffer_store.read(cx).buffers() {
4694 let buffer = handle.read(cx);
4695 if buffer.language().is_none()
4696 || buffer.language() == Some(&*language::PLAIN_TEXT)
4697 {
4698 plain_text_buffers.push(handle);
4699 } else if buffer.contains_unknown_injections() {
4700 buffers_with_unknown_injections.push(handle);
4701 }
4702 }
4703
4704 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4705 // and reused later in the invisible worktrees.
4706 plain_text_buffers.sort_by_key(|buffer| {
4707 Reverse(
4708 File::from_dyn(buffer.read(cx).file())
4709 .map(|file| file.worktree.read(cx).is_visible()),
4710 )
4711 });
4712
4713 for buffer in plain_text_buffers {
4714 this.detect_language_for_buffer(&buffer, cx);
4715 if let Some(local) = this.as_local_mut() {
4716 local.initialize_buffer(&buffer, cx);
4717 if local
4718 .registered_buffers
4719 .contains_key(&buffer.read(cx).remote_id())
4720 {
4721 local.register_buffer_with_language_servers(
4722 &buffer,
4723 HashSet::default(),
4724 cx,
4725 );
4726 }
4727 }
4728 }
4729
4730 for buffer in buffers_with_unknown_injections {
4731 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4732 }
4733 });
4734 }
4735 }
4736 })
4737 }
4738
4739 fn detect_language_for_buffer(
4740 &mut self,
4741 buffer_handle: &Entity<Buffer>,
4742 cx: &mut Context<Self>,
4743 ) -> Option<language::AvailableLanguage> {
4744 // If the buffer has a language, set it and start the language server if we haven't already.
4745 let buffer = buffer_handle.read(cx);
4746 let file = buffer.file()?;
4747
4748 let content = buffer.as_rope();
4749 let available_language = self.languages.language_for_file(file, Some(content), cx);
4750 if let Some(available_language) = &available_language {
4751 if let Some(Ok(Ok(new_language))) = self
4752 .languages
4753 .load_language(available_language)
4754 .now_or_never()
4755 {
4756 self.set_language_for_buffer(buffer_handle, new_language, cx);
4757 }
4758 } else {
4759 cx.emit(LspStoreEvent::LanguageDetected {
4760 buffer: buffer_handle.clone(),
4761 new_language: None,
4762 });
4763 }
4764
4765 available_language
4766 }
4767
4768 pub(crate) fn set_language_for_buffer(
4769 &mut self,
4770 buffer_entity: &Entity<Buffer>,
4771 new_language: Arc<Language>,
4772 cx: &mut Context<Self>,
4773 ) {
4774 let buffer = buffer_entity.read(cx);
4775 let buffer_file = buffer.file().cloned();
4776 let buffer_id = buffer.remote_id();
4777 if let Some(local_store) = self.as_local_mut()
4778 && local_store.registered_buffers.contains_key(&buffer_id)
4779 && let Some(abs_path) =
4780 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4781 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4782 {
4783 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4784 }
4785 buffer_entity.update(cx, |buffer, cx| {
4786 if buffer
4787 .language()
4788 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4789 {
4790 buffer.set_language_async(Some(new_language.clone()), cx);
4791 }
4792 });
4793
4794 let settings =
4795 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4796 let buffer_file = File::from_dyn(buffer_file.as_ref());
4797
4798 let worktree_id = if let Some(file) = buffer_file {
4799 let worktree = file.worktree.clone();
4800
4801 if let Some(local) = self.as_local_mut()
4802 && local.registered_buffers.contains_key(&buffer_id)
4803 {
4804 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4805 }
4806 Some(worktree.read(cx).id())
4807 } else {
4808 None
4809 };
4810
4811 if settings.prettier.allowed
4812 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4813 {
4814 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4815 if let Some(prettier_store) = prettier_store {
4816 prettier_store.update(cx, |prettier_store, cx| {
4817 prettier_store.install_default_prettier(
4818 worktree_id,
4819 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4820 cx,
4821 )
4822 })
4823 }
4824 }
4825
4826 cx.emit(LspStoreEvent::LanguageDetected {
4827 buffer: buffer_entity.clone(),
4828 new_language: Some(new_language),
4829 })
4830 }
4831
4832 pub fn buffer_store(&self) -> Entity<BufferStore> {
4833 self.buffer_store.clone()
4834 }
4835
4836 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4837 self.active_entry = active_entry;
4838 }
4839
4840 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4841 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4842 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4843 {
4844 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4845 summaries
4846 .iter()
4847 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4848 });
4849 if let Some(summary) = summaries.next() {
4850 client
4851 .send(proto::UpdateDiagnosticSummary {
4852 project_id: downstream_project_id,
4853 worktree_id: worktree.id().to_proto(),
4854 summary: Some(summary),
4855 more_summaries: summaries.collect(),
4856 })
4857 .log_err();
4858 }
4859 }
4860 }
4861
4862 fn is_capable_for_proto_request<R>(
4863 &self,
4864 buffer: &Entity<Buffer>,
4865 request: &R,
4866 cx: &App,
4867 ) -> bool
4868 where
4869 R: LspCommand,
4870 {
4871 self.check_if_capable_for_proto_request(
4872 buffer,
4873 |capabilities| {
4874 request.check_capabilities(AdapterServerCapabilities {
4875 server_capabilities: capabilities.clone(),
4876 code_action_kinds: None,
4877 })
4878 },
4879 cx,
4880 )
4881 }
4882
4883 fn check_if_capable_for_proto_request<F>(
4884 &self,
4885 buffer: &Entity<Buffer>,
4886 check: F,
4887 cx: &App,
4888 ) -> bool
4889 where
4890 F: FnMut(&lsp::ServerCapabilities) -> bool,
4891 {
4892 let Some(language) = buffer.read(cx).language().cloned() else {
4893 return false;
4894 };
4895 let registered_language_servers = self
4896 .languages
4897 .lsp_adapters(&language.name())
4898 .into_iter()
4899 .map(|lsp_adapter| lsp_adapter.name())
4900 .collect::<HashSet<_>>();
4901 self.language_server_statuses
4902 .iter()
4903 .filter_map(|(server_id, server_status)| {
4904 // Include servers that are either registered for this language OR
4905 // available to be loaded (for SSH remote mode where adapters like
4906 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4907 // but only loaded on the server side)
4908 let is_relevant = registered_language_servers.contains(&server_status.name)
4909 || self.languages.is_lsp_adapter_available(&server_status.name);
4910 is_relevant.then_some(server_id)
4911 })
4912 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4913 .any(check)
4914 }
4915
4916 fn all_capable_for_proto_request<F>(
4917 &self,
4918 buffer: &Entity<Buffer>,
4919 mut check: F,
4920 cx: &App,
4921 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4922 where
4923 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4924 {
4925 let Some(language) = buffer.read(cx).language().cloned() else {
4926 return Vec::default();
4927 };
4928 let registered_language_servers = self
4929 .languages
4930 .lsp_adapters(&language.name())
4931 .into_iter()
4932 .map(|lsp_adapter| lsp_adapter.name())
4933 .collect::<HashSet<_>>();
4934 self.language_server_statuses
4935 .iter()
4936 .filter_map(|(server_id, server_status)| {
4937 // Include servers that are either registered for this language OR
4938 // available to be loaded (for SSH remote mode where adapters like
4939 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4940 // but only loaded on the server side)
4941 let is_relevant = registered_language_servers.contains(&server_status.name)
4942 || self.languages.is_lsp_adapter_available(&server_status.name);
4943 is_relevant.then_some((server_id, &server_status.name))
4944 })
4945 .filter_map(|(server_id, server_name)| {
4946 self.lsp_server_capabilities
4947 .get(server_id)
4948 .map(|c| (server_id, server_name, c))
4949 })
4950 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4951 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4952 .collect()
4953 }
4954
4955 pub fn request_lsp<R>(
4956 &mut self,
4957 buffer: Entity<Buffer>,
4958 server: LanguageServerToQuery,
4959 request: R,
4960 cx: &mut Context<Self>,
4961 ) -> Task<Result<R::Response>>
4962 where
4963 R: LspCommand,
4964 <R::LspRequest as lsp::request::Request>::Result: Send,
4965 <R::LspRequest as lsp::request::Request>::Params: Send,
4966 {
4967 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4968 return self.send_lsp_proto_request(
4969 buffer,
4970 upstream_client,
4971 upstream_project_id,
4972 request,
4973 cx,
4974 );
4975 }
4976
4977 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4978 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4979 local
4980 .language_servers_for_buffer(buffer, cx)
4981 .find(|(_, server)| {
4982 request.check_capabilities(server.adapter_server_capabilities())
4983 })
4984 .map(|(_, server)| server.clone())
4985 }),
4986 LanguageServerToQuery::Other(id) => self
4987 .language_server_for_local_buffer(buffer, id, cx)
4988 .and_then(|(_, server)| {
4989 request
4990 .check_capabilities(server.adapter_server_capabilities())
4991 .then(|| Arc::clone(server))
4992 }),
4993 }) else {
4994 return Task::ready(Ok(Default::default()));
4995 };
4996
4997 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4998
4999 let Some(file) = file else {
5000 return Task::ready(Ok(Default::default()));
5001 };
5002
5003 let lsp_params = match request.to_lsp_params_or_response(
5004 &file.abs_path(cx),
5005 buffer.read(cx),
5006 &language_server,
5007 cx,
5008 ) {
5009 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5010 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5011 Err(err) => {
5012 let message = format!(
5013 "{} via {} failed: {}",
5014 request.display_name(),
5015 language_server.name(),
5016 err
5017 );
5018 // rust-analyzer likes to error with this when its still loading up
5019 if !message.ends_with("content modified") {
5020 log::warn!("{message}");
5021 }
5022 return Task::ready(Err(anyhow!(message)));
5023 }
5024 };
5025
5026 let status = request.status();
5027 let request_timeout = ProjectSettings::get_global(cx)
5028 .global_lsp_settings
5029 .get_request_timeout();
5030
5031 cx.spawn(async move |this, cx| {
5032 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5033
5034 let id = lsp_request.id();
5035 let _cleanup = if status.is_some() {
5036 cx.update(|cx| {
5037 this.update(cx, |this, cx| {
5038 this.on_lsp_work_start(
5039 language_server.server_id(),
5040 ProgressToken::Number(id),
5041 LanguageServerProgress {
5042 is_disk_based_diagnostics_progress: false,
5043 is_cancellable: false,
5044 title: None,
5045 message: status.clone(),
5046 percentage: None,
5047 last_update_at: cx.background_executor().now(),
5048 },
5049 cx,
5050 );
5051 })
5052 })
5053 .log_err();
5054
5055 Some(defer(|| {
5056 cx.update(|cx| {
5057 this.update(cx, |this, cx| {
5058 this.on_lsp_work_end(
5059 language_server.server_id(),
5060 ProgressToken::Number(id),
5061 cx,
5062 );
5063 })
5064 })
5065 .log_err();
5066 }))
5067 } else {
5068 None
5069 };
5070
5071 let result = lsp_request.await.into_response();
5072
5073 let response = result.map_err(|err| {
5074 let message = format!(
5075 "{} via {} failed: {}",
5076 request.display_name(),
5077 language_server.name(),
5078 err
5079 );
5080 // rust-analyzer likes to error with this when its still loading up
5081 if !message.ends_with("content modified") {
5082 log::warn!("{message}");
5083 }
5084 anyhow::anyhow!(message)
5085 })?;
5086
5087 request
5088 .response_from_lsp(
5089 response,
5090 this.upgrade().context("no app context")?,
5091 buffer,
5092 language_server.server_id(),
5093 cx.clone(),
5094 )
5095 .await
5096 })
5097 }
5098
5099 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5100 let mut language_formatters_to_check = Vec::new();
5101 for buffer in self.buffer_store.read(cx).buffers() {
5102 let buffer = buffer.read(cx);
5103 let buffer_file = File::from_dyn(buffer.file());
5104 let buffer_language = buffer.language();
5105 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5106 if buffer_language.is_some() {
5107 language_formatters_to_check.push((
5108 buffer_file.map(|f| f.worktree_id(cx)),
5109 settings.into_owned(),
5110 ));
5111 }
5112 }
5113
5114 self.request_workspace_config_refresh();
5115
5116 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5117 prettier_store.update(cx, |prettier_store, cx| {
5118 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5119 })
5120 }
5121
5122 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5123 .global_lsp_settings
5124 .semantic_token_rules
5125 .clone();
5126 self.semantic_token_config
5127 .update_rules(new_semantic_token_rules);
5128 // Always clear cached stylizers so that changes to language-specific
5129 // semantic token rules (e.g. from extension install/uninstall) are
5130 // picked up. Stylizers are recreated lazily, so this is cheap.
5131 self.semantic_token_config.clear_stylizers();
5132
5133 let new_global_semantic_tokens_mode =
5134 all_language_settings(None, cx).defaults.semantic_tokens;
5135 if self
5136 .semantic_token_config
5137 .update_global_mode(new_global_semantic_tokens_mode)
5138 {
5139 self.restart_all_language_servers(cx);
5140 }
5141
5142 cx.notify();
5143 }
5144
5145 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5146 let buffer_store = self.buffer_store.clone();
5147 let Some(local) = self.as_local_mut() else {
5148 return;
5149 };
5150 let mut adapters = BTreeMap::default();
5151 let get_adapter = {
5152 let languages = local.languages.clone();
5153 let environment = local.environment.clone();
5154 let weak = local.weak.clone();
5155 let worktree_store = local.worktree_store.clone();
5156 let http_client = local.http_client.clone();
5157 let fs = local.fs.clone();
5158 move |worktree_id, cx: &mut App| {
5159 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5160 Some(LocalLspAdapterDelegate::new(
5161 languages.clone(),
5162 &environment,
5163 weak.clone(),
5164 &worktree,
5165 http_client.clone(),
5166 fs.clone(),
5167 cx,
5168 ))
5169 }
5170 };
5171
5172 let mut messages_to_report = Vec::new();
5173 let (new_tree, to_stop) = {
5174 let mut rebase = local.lsp_tree.rebase();
5175 let buffers = buffer_store
5176 .read(cx)
5177 .buffers()
5178 .filter_map(|buffer| {
5179 let raw_buffer = buffer.read(cx);
5180 if !local
5181 .registered_buffers
5182 .contains_key(&raw_buffer.remote_id())
5183 {
5184 return None;
5185 }
5186 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5187 let language = raw_buffer.language().cloned()?;
5188 Some((file, language, raw_buffer.remote_id()))
5189 })
5190 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5191 for (file, language, buffer_id) in buffers {
5192 let worktree_id = file.worktree_id(cx);
5193 let Some(worktree) = local
5194 .worktree_store
5195 .read(cx)
5196 .worktree_for_id(worktree_id, cx)
5197 else {
5198 continue;
5199 };
5200
5201 if let Some((_, apply)) = local.reuse_existing_language_server(
5202 rebase.server_tree(),
5203 &worktree,
5204 &language.name(),
5205 cx,
5206 ) {
5207 (apply)(rebase.server_tree());
5208 } else if let Some(lsp_delegate) = adapters
5209 .entry(worktree_id)
5210 .or_insert_with(|| get_adapter(worktree_id, cx))
5211 .clone()
5212 {
5213 let delegate =
5214 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5215 let path = file
5216 .path()
5217 .parent()
5218 .map(Arc::from)
5219 .unwrap_or_else(|| file.path().clone());
5220 let worktree_path = ProjectPath { worktree_id, path };
5221 let abs_path = file.abs_path(cx);
5222 let nodes = rebase
5223 .walk(
5224 worktree_path,
5225 language.name(),
5226 language.manifest(),
5227 delegate.clone(),
5228 cx,
5229 )
5230 .collect::<Vec<_>>();
5231 for node in nodes {
5232 let server_id = node.server_id_or_init(|disposition| {
5233 let path = &disposition.path;
5234 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5235 let key = LanguageServerSeed {
5236 worktree_id,
5237 name: disposition.server_name.clone(),
5238 settings: LanguageServerSeedSettings {
5239 binary: disposition.settings.binary.clone(),
5240 initialization_options: disposition
5241 .settings
5242 .initialization_options
5243 .clone(),
5244 },
5245 toolchain: local.toolchain_store.read(cx).active_toolchain(
5246 path.worktree_id,
5247 &path.path,
5248 language.name(),
5249 ),
5250 };
5251 local.language_server_ids.remove(&key);
5252
5253 let server_id = local.get_or_insert_language_server(
5254 &worktree,
5255 lsp_delegate.clone(),
5256 disposition,
5257 &language.name(),
5258 cx,
5259 );
5260 if let Some(state) = local.language_servers.get(&server_id)
5261 && let Ok(uri) = uri
5262 {
5263 state.add_workspace_folder(uri);
5264 };
5265 server_id
5266 });
5267
5268 if let Some(language_server_id) = server_id {
5269 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5270 language_server_id,
5271 name: node.name(),
5272 message:
5273 proto::update_language_server::Variant::RegisteredForBuffer(
5274 proto::RegisteredForBuffer {
5275 buffer_abs_path: abs_path
5276 .to_string_lossy()
5277 .into_owned(),
5278 buffer_id: buffer_id.to_proto(),
5279 },
5280 ),
5281 });
5282 }
5283 }
5284 } else {
5285 continue;
5286 }
5287 }
5288 rebase.finish()
5289 };
5290 for message in messages_to_report {
5291 cx.emit(message);
5292 }
5293 local.lsp_tree = new_tree;
5294 for (id, _) in to_stop {
5295 self.stop_local_language_server(id, cx).detach();
5296 }
5297 }
5298
5299 pub fn apply_code_action(
5300 &self,
5301 buffer_handle: Entity<Buffer>,
5302 mut action: CodeAction,
5303 push_to_history: bool,
5304 cx: &mut Context<Self>,
5305 ) -> Task<Result<ProjectTransaction>> {
5306 if let Some((upstream_client, project_id)) = self.upstream_client() {
5307 let request = proto::ApplyCodeAction {
5308 project_id,
5309 buffer_id: buffer_handle.read(cx).remote_id().into(),
5310 action: Some(Self::serialize_code_action(&action)),
5311 };
5312 let buffer_store = self.buffer_store();
5313 cx.spawn(async move |_, cx| {
5314 let response = upstream_client
5315 .request(request)
5316 .await?
5317 .transaction
5318 .context("missing transaction")?;
5319
5320 buffer_store
5321 .update(cx, |buffer_store, cx| {
5322 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5323 })
5324 .await
5325 })
5326 } else if self.mode.is_local() {
5327 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5328 let request_timeout = ProjectSettings::get_global(cx)
5329 .global_lsp_settings
5330 .get_request_timeout();
5331 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5332 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5333 }) else {
5334 return Task::ready(Ok(ProjectTransaction::default()));
5335 };
5336
5337 cx.spawn(async move |this, cx| {
5338 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5339 .await
5340 .context("resolving a code action")?;
5341 if let Some(edit) = action.lsp_action.edit()
5342 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5343 return LocalLspStore::deserialize_workspace_edit(
5344 this.upgrade().context("no app present")?,
5345 edit.clone(),
5346 push_to_history,
5347
5348 lang_server.clone(),
5349 cx,
5350 )
5351 .await;
5352 }
5353
5354 let Some(command) = action.lsp_action.command() else {
5355 return Ok(ProjectTransaction::default())
5356 };
5357
5358 let server_capabilities = lang_server.capabilities();
5359 let available_commands = server_capabilities
5360 .execute_command_provider
5361 .as_ref()
5362 .map(|options| options.commands.as_slice())
5363 .unwrap_or_default();
5364
5365 if !available_commands.contains(&command.command) {
5366 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5367 return Ok(ProjectTransaction::default())
5368 }
5369
5370 let request_timeout = cx.update(|app|
5371 ProjectSettings::get_global(app)
5372 .global_lsp_settings
5373 .get_request_timeout()
5374 );
5375
5376 this.update(cx, |this, _| {
5377 this.as_local_mut()
5378 .unwrap()
5379 .last_workspace_edits_by_language_server
5380 .remove(&lang_server.server_id());
5381 })?;
5382
5383 let _result = lang_server
5384 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5385 command: command.command.clone(),
5386 arguments: command.arguments.clone().unwrap_or_default(),
5387 ..lsp::ExecuteCommandParams::default()
5388 }, request_timeout)
5389 .await.into_response()
5390 .context("execute command")?;
5391
5392 return this.update(cx, |this, _| {
5393 this.as_local_mut()
5394 .unwrap()
5395 .last_workspace_edits_by_language_server
5396 .remove(&lang_server.server_id())
5397 .unwrap_or_default()
5398 });
5399 })
5400 } else {
5401 Task::ready(Err(anyhow!("no upstream client and not local")))
5402 }
5403 }
5404
5405 pub fn apply_code_action_kind(
5406 &mut self,
5407 buffers: HashSet<Entity<Buffer>>,
5408 kind: CodeActionKind,
5409 push_to_history: bool,
5410 cx: &mut Context<Self>,
5411 ) -> Task<anyhow::Result<ProjectTransaction>> {
5412 if self.as_local().is_some() {
5413 cx.spawn(async move |lsp_store, cx| {
5414 let buffers = buffers.into_iter().collect::<Vec<_>>();
5415 let result = LocalLspStore::execute_code_action_kind_locally(
5416 lsp_store.clone(),
5417 buffers,
5418 kind,
5419 push_to_history,
5420 cx,
5421 )
5422 .await;
5423 lsp_store.update(cx, |lsp_store, _| {
5424 lsp_store.update_last_formatting_failure(&result);
5425 })?;
5426 result
5427 })
5428 } else if let Some((client, project_id)) = self.upstream_client() {
5429 let buffer_store = self.buffer_store();
5430 cx.spawn(async move |lsp_store, cx| {
5431 let result = client
5432 .request(proto::ApplyCodeActionKind {
5433 project_id,
5434 kind: kind.as_str().to_owned(),
5435 buffer_ids: buffers
5436 .iter()
5437 .map(|buffer| {
5438 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5439 })
5440 .collect(),
5441 })
5442 .await
5443 .and_then(|result| result.transaction.context("missing transaction"));
5444 lsp_store.update(cx, |lsp_store, _| {
5445 lsp_store.update_last_formatting_failure(&result);
5446 })?;
5447
5448 let transaction_response = result?;
5449 buffer_store
5450 .update(cx, |buffer_store, cx| {
5451 buffer_store.deserialize_project_transaction(
5452 transaction_response,
5453 push_to_history,
5454 cx,
5455 )
5456 })
5457 .await
5458 })
5459 } else {
5460 Task::ready(Ok(ProjectTransaction::default()))
5461 }
5462 }
5463
5464 pub fn resolved_hint(
5465 &mut self,
5466 buffer_id: BufferId,
5467 id: InlayId,
5468 cx: &mut Context<Self>,
5469 ) -> Option<ResolvedHint> {
5470 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5471
5472 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5473 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5474 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5475 let (server_id, resolve_data) = match &hint.resolve_state {
5476 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5477 ResolveState::Resolving => {
5478 return Some(ResolvedHint::Resolving(
5479 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5480 ));
5481 }
5482 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5483 };
5484
5485 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5486 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5487 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5488 id,
5489 cx.spawn(async move |lsp_store, cx| {
5490 let resolved_hint = resolve_task.await;
5491 lsp_store
5492 .update(cx, |lsp_store, _| {
5493 if let Some(old_inlay_hint) = lsp_store
5494 .lsp_data
5495 .get_mut(&buffer_id)
5496 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5497 {
5498 match resolved_hint {
5499 Ok(resolved_hint) => {
5500 *old_inlay_hint = resolved_hint;
5501 }
5502 Err(e) => {
5503 old_inlay_hint.resolve_state =
5504 ResolveState::CanResolve(server_id, resolve_data);
5505 log::error!("Inlay hint resolve failed: {e:#}");
5506 }
5507 }
5508 }
5509 })
5510 .ok();
5511 })
5512 .shared(),
5513 );
5514 debug_assert!(
5515 previous_task.is_none(),
5516 "Did not change hint's resolve state after spawning its resolve"
5517 );
5518 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5519 None
5520 }
5521
5522 pub(crate) fn linked_edits(
5523 &mut self,
5524 buffer: &Entity<Buffer>,
5525 position: Anchor,
5526 cx: &mut Context<Self>,
5527 ) -> Task<Result<Vec<Range<Anchor>>>> {
5528 let snapshot = buffer.read(cx).snapshot();
5529 let scope = snapshot.language_scope_at(position);
5530 let Some(server_id) = self
5531 .as_local()
5532 .and_then(|local| {
5533 buffer.update(cx, |buffer, cx| {
5534 local
5535 .language_servers_for_buffer(buffer, cx)
5536 .filter(|(_, server)| {
5537 LinkedEditingRange::check_server_capabilities(server.capabilities())
5538 })
5539 .filter(|(adapter, _)| {
5540 scope
5541 .as_ref()
5542 .map(|scope| scope.language_allowed(&adapter.name))
5543 .unwrap_or(true)
5544 })
5545 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5546 .next()
5547 })
5548 })
5549 .or_else(|| {
5550 self.upstream_client()
5551 .is_some()
5552 .then_some(LanguageServerToQuery::FirstCapable)
5553 })
5554 .filter(|_| {
5555 maybe!({
5556 let language = buffer.read(cx).language_at(position)?;
5557 Some(
5558 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5559 .linked_edits,
5560 )
5561 }) == Some(true)
5562 })
5563 else {
5564 return Task::ready(Ok(Vec::new()));
5565 };
5566
5567 self.request_lsp(
5568 buffer.clone(),
5569 server_id,
5570 LinkedEditingRange { position },
5571 cx,
5572 )
5573 }
5574
5575 fn apply_on_type_formatting(
5576 &mut self,
5577 buffer: Entity<Buffer>,
5578 position: Anchor,
5579 trigger: String,
5580 cx: &mut Context<Self>,
5581 ) -> Task<Result<Option<Transaction>>> {
5582 if let Some((client, project_id)) = self.upstream_client() {
5583 if !self.check_if_capable_for_proto_request(
5584 &buffer,
5585 |capabilities| {
5586 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5587 },
5588 cx,
5589 ) {
5590 return Task::ready(Ok(None));
5591 }
5592 let request = proto::OnTypeFormatting {
5593 project_id,
5594 buffer_id: buffer.read(cx).remote_id().into(),
5595 position: Some(serialize_anchor(&position)),
5596 trigger,
5597 version: serialize_version(&buffer.read(cx).version()),
5598 };
5599 cx.background_spawn(async move {
5600 client
5601 .request(request)
5602 .await?
5603 .transaction
5604 .map(language::proto::deserialize_transaction)
5605 .transpose()
5606 })
5607 } else if let Some(local) = self.as_local_mut() {
5608 let buffer_id = buffer.read(cx).remote_id();
5609 local.buffers_being_formatted.insert(buffer_id);
5610 cx.spawn(async move |this, cx| {
5611 let _cleanup = defer({
5612 let this = this.clone();
5613 let mut cx = cx.clone();
5614 move || {
5615 this.update(&mut cx, |this, _| {
5616 if let Some(local) = this.as_local_mut() {
5617 local.buffers_being_formatted.remove(&buffer_id);
5618 }
5619 })
5620 .ok();
5621 }
5622 });
5623
5624 buffer
5625 .update(cx, |buffer, _| {
5626 buffer.wait_for_edits(Some(position.timestamp()))
5627 })
5628 .await?;
5629 this.update(cx, |this, cx| {
5630 let position = position.to_point_utf16(buffer.read(cx));
5631 this.on_type_format(buffer, position, trigger, false, cx)
5632 })?
5633 .await
5634 })
5635 } else {
5636 Task::ready(Err(anyhow!("No upstream client or local language server")))
5637 }
5638 }
5639
5640 pub fn on_type_format<T: ToPointUtf16>(
5641 &mut self,
5642 buffer: Entity<Buffer>,
5643 position: T,
5644 trigger: String,
5645 push_to_history: bool,
5646 cx: &mut Context<Self>,
5647 ) -> Task<Result<Option<Transaction>>> {
5648 let position = position.to_point_utf16(buffer.read(cx));
5649 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5650 }
5651
5652 fn on_type_format_impl(
5653 &mut self,
5654 buffer: Entity<Buffer>,
5655 position: PointUtf16,
5656 trigger: String,
5657 push_to_history: bool,
5658 cx: &mut Context<Self>,
5659 ) -> Task<Result<Option<Transaction>>> {
5660 let options = buffer.update(cx, |buffer, cx| {
5661 lsp_command::lsp_formatting_options(
5662 language_settings(
5663 buffer.language_at(position).map(|l| l.name()),
5664 buffer.file(),
5665 cx,
5666 )
5667 .as_ref(),
5668 )
5669 });
5670
5671 cx.spawn(async move |this, cx| {
5672 if let Some(waiter) =
5673 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5674 {
5675 waiter.await?;
5676 }
5677 cx.update(|cx| {
5678 this.update(cx, |this, cx| {
5679 this.request_lsp(
5680 buffer.clone(),
5681 LanguageServerToQuery::FirstCapable,
5682 OnTypeFormatting {
5683 position,
5684 trigger,
5685 options,
5686 push_to_history,
5687 },
5688 cx,
5689 )
5690 })
5691 })?
5692 .await
5693 })
5694 }
5695
5696 pub fn definitions(
5697 &mut self,
5698 buffer: &Entity<Buffer>,
5699 position: PointUtf16,
5700 cx: &mut Context<Self>,
5701 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5702 if let Some((upstream_client, project_id)) = self.upstream_client() {
5703 let request = GetDefinitions { position };
5704 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5705 return Task::ready(Ok(None));
5706 }
5707
5708 let request_timeout = ProjectSettings::get_global(cx)
5709 .global_lsp_settings
5710 .get_request_timeout();
5711
5712 let request_task = upstream_client.request_lsp(
5713 project_id,
5714 None,
5715 request_timeout,
5716 cx.background_executor().clone(),
5717 request.to_proto(project_id, buffer.read(cx)),
5718 );
5719 let buffer = buffer.clone();
5720 cx.spawn(async move |weak_lsp_store, cx| {
5721 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5722 return Ok(None);
5723 };
5724 let Some(responses) = request_task.await? else {
5725 return Ok(None);
5726 };
5727 let actions = join_all(responses.payload.into_iter().map(|response| {
5728 GetDefinitions { position }.response_from_proto(
5729 response.response,
5730 lsp_store.clone(),
5731 buffer.clone(),
5732 cx.clone(),
5733 )
5734 }))
5735 .await;
5736
5737 Ok(Some(
5738 actions
5739 .into_iter()
5740 .collect::<Result<Vec<Vec<_>>>>()?
5741 .into_iter()
5742 .flatten()
5743 .dedup()
5744 .collect(),
5745 ))
5746 })
5747 } else {
5748 let definitions_task = self.request_multiple_lsp_locally(
5749 buffer,
5750 Some(position),
5751 GetDefinitions { position },
5752 cx,
5753 );
5754 cx.background_spawn(async move {
5755 Ok(Some(
5756 definitions_task
5757 .await
5758 .into_iter()
5759 .flat_map(|(_, definitions)| definitions)
5760 .dedup()
5761 .collect(),
5762 ))
5763 })
5764 }
5765 }
5766
5767 pub fn declarations(
5768 &mut self,
5769 buffer: &Entity<Buffer>,
5770 position: PointUtf16,
5771 cx: &mut Context<Self>,
5772 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5773 if let Some((upstream_client, project_id)) = self.upstream_client() {
5774 let request = GetDeclarations { position };
5775 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5776 return Task::ready(Ok(None));
5777 }
5778 let request_timeout = ProjectSettings::get_global(cx)
5779 .global_lsp_settings
5780 .get_request_timeout();
5781 let request_task = upstream_client.request_lsp(
5782 project_id,
5783 None,
5784 request_timeout,
5785 cx.background_executor().clone(),
5786 request.to_proto(project_id, buffer.read(cx)),
5787 );
5788 let buffer = buffer.clone();
5789 cx.spawn(async move |weak_lsp_store, cx| {
5790 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5791 return Ok(None);
5792 };
5793 let Some(responses) = request_task.await? else {
5794 return Ok(None);
5795 };
5796 let actions = join_all(responses.payload.into_iter().map(|response| {
5797 GetDeclarations { position }.response_from_proto(
5798 response.response,
5799 lsp_store.clone(),
5800 buffer.clone(),
5801 cx.clone(),
5802 )
5803 }))
5804 .await;
5805
5806 Ok(Some(
5807 actions
5808 .into_iter()
5809 .collect::<Result<Vec<Vec<_>>>>()?
5810 .into_iter()
5811 .flatten()
5812 .dedup()
5813 .collect(),
5814 ))
5815 })
5816 } else {
5817 let declarations_task = self.request_multiple_lsp_locally(
5818 buffer,
5819 Some(position),
5820 GetDeclarations { position },
5821 cx,
5822 );
5823 cx.background_spawn(async move {
5824 Ok(Some(
5825 declarations_task
5826 .await
5827 .into_iter()
5828 .flat_map(|(_, declarations)| declarations)
5829 .dedup()
5830 .collect(),
5831 ))
5832 })
5833 }
5834 }
5835
5836 pub fn type_definitions(
5837 &mut self,
5838 buffer: &Entity<Buffer>,
5839 position: PointUtf16,
5840 cx: &mut Context<Self>,
5841 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5842 if let Some((upstream_client, project_id)) = self.upstream_client() {
5843 let request = GetTypeDefinitions { position };
5844 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5845 return Task::ready(Ok(None));
5846 }
5847 let request_timeout = ProjectSettings::get_global(cx)
5848 .global_lsp_settings
5849 .get_request_timeout();
5850 let request_task = upstream_client.request_lsp(
5851 project_id,
5852 None,
5853 request_timeout,
5854 cx.background_executor().clone(),
5855 request.to_proto(project_id, buffer.read(cx)),
5856 );
5857 let buffer = buffer.clone();
5858 cx.spawn(async move |weak_lsp_store, cx| {
5859 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5860 return Ok(None);
5861 };
5862 let Some(responses) = request_task.await? else {
5863 return Ok(None);
5864 };
5865 let actions = join_all(responses.payload.into_iter().map(|response| {
5866 GetTypeDefinitions { position }.response_from_proto(
5867 response.response,
5868 lsp_store.clone(),
5869 buffer.clone(),
5870 cx.clone(),
5871 )
5872 }))
5873 .await;
5874
5875 Ok(Some(
5876 actions
5877 .into_iter()
5878 .collect::<Result<Vec<Vec<_>>>>()?
5879 .into_iter()
5880 .flatten()
5881 .dedup()
5882 .collect(),
5883 ))
5884 })
5885 } else {
5886 let type_definitions_task = self.request_multiple_lsp_locally(
5887 buffer,
5888 Some(position),
5889 GetTypeDefinitions { position },
5890 cx,
5891 );
5892 cx.background_spawn(async move {
5893 Ok(Some(
5894 type_definitions_task
5895 .await
5896 .into_iter()
5897 .flat_map(|(_, type_definitions)| type_definitions)
5898 .dedup()
5899 .collect(),
5900 ))
5901 })
5902 }
5903 }
5904
5905 pub fn implementations(
5906 &mut self,
5907 buffer: &Entity<Buffer>,
5908 position: PointUtf16,
5909 cx: &mut Context<Self>,
5910 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5911 if let Some((upstream_client, project_id)) = self.upstream_client() {
5912 let request = GetImplementations { position };
5913 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5914 return Task::ready(Ok(None));
5915 }
5916
5917 let request_timeout = ProjectSettings::get_global(cx)
5918 .global_lsp_settings
5919 .get_request_timeout();
5920 let request_task = upstream_client.request_lsp(
5921 project_id,
5922 None,
5923 request_timeout,
5924 cx.background_executor().clone(),
5925 request.to_proto(project_id, buffer.read(cx)),
5926 );
5927 let buffer = buffer.clone();
5928 cx.spawn(async move |weak_lsp_store, cx| {
5929 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5930 return Ok(None);
5931 };
5932 let Some(responses) = request_task.await? else {
5933 return Ok(None);
5934 };
5935 let actions = join_all(responses.payload.into_iter().map(|response| {
5936 GetImplementations { position }.response_from_proto(
5937 response.response,
5938 lsp_store.clone(),
5939 buffer.clone(),
5940 cx.clone(),
5941 )
5942 }))
5943 .await;
5944
5945 Ok(Some(
5946 actions
5947 .into_iter()
5948 .collect::<Result<Vec<Vec<_>>>>()?
5949 .into_iter()
5950 .flatten()
5951 .dedup()
5952 .collect(),
5953 ))
5954 })
5955 } else {
5956 let implementations_task = self.request_multiple_lsp_locally(
5957 buffer,
5958 Some(position),
5959 GetImplementations { position },
5960 cx,
5961 );
5962 cx.background_spawn(async move {
5963 Ok(Some(
5964 implementations_task
5965 .await
5966 .into_iter()
5967 .flat_map(|(_, implementations)| implementations)
5968 .dedup()
5969 .collect(),
5970 ))
5971 })
5972 }
5973 }
5974
5975 pub fn references(
5976 &mut self,
5977 buffer: &Entity<Buffer>,
5978 position: PointUtf16,
5979 cx: &mut Context<Self>,
5980 ) -> Task<Result<Option<Vec<Location>>>> {
5981 if let Some((upstream_client, project_id)) = self.upstream_client() {
5982 let request = GetReferences { position };
5983 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5984 return Task::ready(Ok(None));
5985 }
5986
5987 let request_timeout = ProjectSettings::get_global(cx)
5988 .global_lsp_settings
5989 .get_request_timeout();
5990 let request_task = upstream_client.request_lsp(
5991 project_id,
5992 None,
5993 request_timeout,
5994 cx.background_executor().clone(),
5995 request.to_proto(project_id, buffer.read(cx)),
5996 );
5997 let buffer = buffer.clone();
5998 cx.spawn(async move |weak_lsp_store, cx| {
5999 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6000 return Ok(None);
6001 };
6002 let Some(responses) = request_task.await? else {
6003 return Ok(None);
6004 };
6005
6006 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6007 GetReferences { position }.response_from_proto(
6008 lsp_response.response,
6009 lsp_store.clone(),
6010 buffer.clone(),
6011 cx.clone(),
6012 )
6013 }))
6014 .await
6015 .into_iter()
6016 .collect::<Result<Vec<Vec<_>>>>()?
6017 .into_iter()
6018 .flatten()
6019 .dedup()
6020 .collect();
6021 Ok(Some(locations))
6022 })
6023 } else {
6024 let references_task = self.request_multiple_lsp_locally(
6025 buffer,
6026 Some(position),
6027 GetReferences { position },
6028 cx,
6029 );
6030 cx.background_spawn(async move {
6031 Ok(Some(
6032 references_task
6033 .await
6034 .into_iter()
6035 .flat_map(|(_, references)| references)
6036 .dedup()
6037 .collect(),
6038 ))
6039 })
6040 }
6041 }
6042
6043 pub fn code_actions(
6044 &mut self,
6045 buffer: &Entity<Buffer>,
6046 range: Range<Anchor>,
6047 kinds: Option<Vec<CodeActionKind>>,
6048 cx: &mut Context<Self>,
6049 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6050 if let Some((upstream_client, project_id)) = self.upstream_client() {
6051 let request = GetCodeActions {
6052 range: range.clone(),
6053 kinds: kinds.clone(),
6054 };
6055 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6056 return Task::ready(Ok(None));
6057 }
6058 let request_timeout = ProjectSettings::get_global(cx)
6059 .global_lsp_settings
6060 .get_request_timeout();
6061 let request_task = upstream_client.request_lsp(
6062 project_id,
6063 None,
6064 request_timeout,
6065 cx.background_executor().clone(),
6066 request.to_proto(project_id, buffer.read(cx)),
6067 );
6068 let buffer = buffer.clone();
6069 cx.spawn(async move |weak_lsp_store, cx| {
6070 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6071 return Ok(None);
6072 };
6073 let Some(responses) = request_task.await? else {
6074 return Ok(None);
6075 };
6076 let actions = join_all(responses.payload.into_iter().map(|response| {
6077 GetCodeActions {
6078 range: range.clone(),
6079 kinds: kinds.clone(),
6080 }
6081 .response_from_proto(
6082 response.response,
6083 lsp_store.clone(),
6084 buffer.clone(),
6085 cx.clone(),
6086 )
6087 }))
6088 .await;
6089
6090 Ok(Some(
6091 actions
6092 .into_iter()
6093 .collect::<Result<Vec<Vec<_>>>>()?
6094 .into_iter()
6095 .flatten()
6096 .collect(),
6097 ))
6098 })
6099 } else {
6100 let all_actions_task = self.request_multiple_lsp_locally(
6101 buffer,
6102 Some(range.start),
6103 GetCodeActions { range, kinds },
6104 cx,
6105 );
6106 cx.background_spawn(async move {
6107 Ok(Some(
6108 all_actions_task
6109 .await
6110 .into_iter()
6111 .flat_map(|(_, actions)| actions)
6112 .collect(),
6113 ))
6114 })
6115 }
6116 }
6117
6118 #[inline(never)]
6119 pub fn completions(
6120 &self,
6121 buffer: &Entity<Buffer>,
6122 position: PointUtf16,
6123 context: CompletionContext,
6124 cx: &mut Context<Self>,
6125 ) -> Task<Result<Vec<CompletionResponse>>> {
6126 let language_registry = self.languages.clone();
6127
6128 if let Some((upstream_client, project_id)) = self.upstream_client() {
6129 let snapshot = buffer.read(cx).snapshot();
6130 let offset = position.to_offset(&snapshot);
6131 let scope = snapshot.language_scope_at(offset);
6132 let capable_lsps = self.all_capable_for_proto_request(
6133 buffer,
6134 |server_name, capabilities| {
6135 capabilities.completion_provider.is_some()
6136 && scope
6137 .as_ref()
6138 .map(|scope| scope.language_allowed(server_name))
6139 .unwrap_or(true)
6140 },
6141 cx,
6142 );
6143 if capable_lsps.is_empty() {
6144 return Task::ready(Ok(Vec::new()));
6145 }
6146
6147 let language = buffer.read(cx).language().cloned();
6148
6149 let buffer = buffer.clone();
6150
6151 cx.spawn(async move |this, cx| {
6152 let requests = join_all(
6153 capable_lsps
6154 .into_iter()
6155 .map(|(id, server_name)| {
6156 let request = GetCompletions {
6157 position,
6158 context: context.clone(),
6159 server_id: Some(id),
6160 };
6161 let buffer = buffer.clone();
6162 let language = language.clone();
6163 let lsp_adapter = language.as_ref().and_then(|language| {
6164 let adapters = language_registry.lsp_adapters(&language.name());
6165 adapters
6166 .iter()
6167 .find(|adapter| adapter.name() == server_name)
6168 .or_else(|| adapters.first())
6169 .cloned()
6170 });
6171 let upstream_client = upstream_client.clone();
6172 let response = this
6173 .update(cx, |this, cx| {
6174 this.send_lsp_proto_request(
6175 buffer,
6176 upstream_client,
6177 project_id,
6178 request,
6179 cx,
6180 )
6181 })
6182 .log_err();
6183 async move {
6184 let response = response?.await.log_err()?;
6185
6186 let completions = populate_labels_for_completions(
6187 response.completions,
6188 language,
6189 lsp_adapter,
6190 )
6191 .await;
6192
6193 Some(CompletionResponse {
6194 completions,
6195 display_options: CompletionDisplayOptions::default(),
6196 is_incomplete: response.is_incomplete,
6197 })
6198 }
6199 })
6200 .collect::<Vec<_>>(),
6201 );
6202 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6203 })
6204 } else if let Some(local) = self.as_local() {
6205 let snapshot = buffer.read(cx).snapshot();
6206 let offset = position.to_offset(&snapshot);
6207 let scope = snapshot.language_scope_at(offset);
6208 let language = snapshot.language().cloned();
6209 let completion_settings = language_settings(
6210 language.as_ref().map(|language| language.name()),
6211 buffer.read(cx).file(),
6212 cx,
6213 )
6214 .completions
6215 .clone();
6216 if !completion_settings.lsp {
6217 return Task::ready(Ok(Vec::new()));
6218 }
6219
6220 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6221 local
6222 .language_servers_for_buffer(buffer, cx)
6223 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6224 .filter(|(adapter, _)| {
6225 scope
6226 .as_ref()
6227 .map(|scope| scope.language_allowed(&adapter.name))
6228 .unwrap_or(true)
6229 })
6230 .map(|(_, server)| server.server_id())
6231 .collect()
6232 });
6233
6234 let buffer = buffer.clone();
6235 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6236 let lsp_timeout = if lsp_timeout > 0 {
6237 Some(Duration::from_millis(lsp_timeout))
6238 } else {
6239 None
6240 };
6241 cx.spawn(async move |this, cx| {
6242 let mut tasks = Vec::with_capacity(server_ids.len());
6243 this.update(cx, |lsp_store, cx| {
6244 for server_id in server_ids {
6245 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6246 let lsp_timeout = lsp_timeout
6247 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6248 let mut timeout = cx.background_spawn(async move {
6249 match lsp_timeout {
6250 Some(lsp_timeout) => {
6251 lsp_timeout.await;
6252 true
6253 },
6254 None => false,
6255 }
6256 }).fuse();
6257 let mut lsp_request = lsp_store.request_lsp(
6258 buffer.clone(),
6259 LanguageServerToQuery::Other(server_id),
6260 GetCompletions {
6261 position,
6262 context: context.clone(),
6263 server_id: Some(server_id),
6264 },
6265 cx,
6266 ).fuse();
6267 let new_task = cx.background_spawn(async move {
6268 select_biased! {
6269 response = lsp_request => anyhow::Ok(Some(response?)),
6270 timeout_happened = timeout => {
6271 if timeout_happened {
6272 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6273 Ok(None)
6274 } else {
6275 let completions = lsp_request.await?;
6276 Ok(Some(completions))
6277 }
6278 },
6279 }
6280 });
6281 tasks.push((lsp_adapter, new_task));
6282 }
6283 })?;
6284
6285 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6286 let completion_response = task.await.ok()??;
6287 let completions = populate_labels_for_completions(
6288 completion_response.completions,
6289 language.clone(),
6290 lsp_adapter,
6291 )
6292 .await;
6293 Some(CompletionResponse {
6294 completions,
6295 display_options: CompletionDisplayOptions::default(),
6296 is_incomplete: completion_response.is_incomplete,
6297 })
6298 });
6299
6300 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6301
6302 Ok(responses.into_iter().flatten().collect())
6303 })
6304 } else {
6305 Task::ready(Err(anyhow!("No upstream client or local language server")))
6306 }
6307 }
6308
6309 pub fn resolve_completions(
6310 &self,
6311 buffer: Entity<Buffer>,
6312 completion_indices: Vec<usize>,
6313 completions: Rc<RefCell<Box<[Completion]>>>,
6314 cx: &mut Context<Self>,
6315 ) -> Task<Result<bool>> {
6316 let client = self.upstream_client();
6317 let buffer_id = buffer.read(cx).remote_id();
6318 let buffer_snapshot = buffer.read(cx).snapshot();
6319
6320 if !self.check_if_capable_for_proto_request(
6321 &buffer,
6322 GetCompletions::can_resolve_completions,
6323 cx,
6324 ) {
6325 return Task::ready(Ok(false));
6326 }
6327 cx.spawn(async move |lsp_store, cx| {
6328 let request_timeout = cx.update(|app| {
6329 ProjectSettings::get_global(app)
6330 .global_lsp_settings
6331 .get_request_timeout()
6332 });
6333
6334 let mut did_resolve = false;
6335 if let Some((client, project_id)) = client {
6336 for completion_index in completion_indices {
6337 let server_id = {
6338 let completion = &completions.borrow()[completion_index];
6339 completion.source.server_id()
6340 };
6341 if let Some(server_id) = server_id {
6342 if Self::resolve_completion_remote(
6343 project_id,
6344 server_id,
6345 buffer_id,
6346 completions.clone(),
6347 completion_index,
6348 client.clone(),
6349 )
6350 .await
6351 .log_err()
6352 .is_some()
6353 {
6354 did_resolve = true;
6355 }
6356 } else {
6357 resolve_word_completion(
6358 &buffer_snapshot,
6359 &mut completions.borrow_mut()[completion_index],
6360 );
6361 }
6362 }
6363 } else {
6364 for completion_index in completion_indices {
6365 let server_id = {
6366 let completion = &completions.borrow()[completion_index];
6367 completion.source.server_id()
6368 };
6369 if let Some(server_id) = server_id {
6370 let server_and_adapter = lsp_store
6371 .read_with(cx, |lsp_store, _| {
6372 let server = lsp_store.language_server_for_id(server_id)?;
6373 let adapter =
6374 lsp_store.language_server_adapter_for_id(server.server_id())?;
6375 Some((server, adapter))
6376 })
6377 .ok()
6378 .flatten();
6379 let Some((server, adapter)) = server_and_adapter else {
6380 continue;
6381 };
6382
6383 let resolved = Self::resolve_completion_local(
6384 server,
6385 completions.clone(),
6386 completion_index,
6387 request_timeout,
6388 )
6389 .await
6390 .log_err()
6391 .is_some();
6392 if resolved {
6393 Self::regenerate_completion_labels(
6394 adapter,
6395 &buffer_snapshot,
6396 completions.clone(),
6397 completion_index,
6398 )
6399 .await
6400 .log_err();
6401 did_resolve = true;
6402 }
6403 } else {
6404 resolve_word_completion(
6405 &buffer_snapshot,
6406 &mut completions.borrow_mut()[completion_index],
6407 );
6408 }
6409 }
6410 }
6411
6412 Ok(did_resolve)
6413 })
6414 }
6415
6416 async fn resolve_completion_local(
6417 server: Arc<lsp::LanguageServer>,
6418 completions: Rc<RefCell<Box<[Completion]>>>,
6419 completion_index: usize,
6420 request_timeout: Duration,
6421 ) -> Result<()> {
6422 let server_id = server.server_id();
6423 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6424 return Ok(());
6425 }
6426
6427 let request = {
6428 let completion = &completions.borrow()[completion_index];
6429 match &completion.source {
6430 CompletionSource::Lsp {
6431 lsp_completion,
6432 resolved,
6433 server_id: completion_server_id,
6434 ..
6435 } => {
6436 if *resolved {
6437 return Ok(());
6438 }
6439 anyhow::ensure!(
6440 server_id == *completion_server_id,
6441 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6442 );
6443 server.request::<lsp::request::ResolveCompletionItem>(
6444 *lsp_completion.clone(),
6445 request_timeout,
6446 )
6447 }
6448 CompletionSource::BufferWord { .. }
6449 | CompletionSource::Dap { .. }
6450 | CompletionSource::Custom => {
6451 return Ok(());
6452 }
6453 }
6454 };
6455 let resolved_completion = request
6456 .await
6457 .into_response()
6458 .context("resolve completion")?;
6459
6460 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6461 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6462
6463 let mut completions = completions.borrow_mut();
6464 let completion = &mut completions[completion_index];
6465 if let CompletionSource::Lsp {
6466 lsp_completion,
6467 resolved,
6468 server_id: completion_server_id,
6469 ..
6470 } = &mut completion.source
6471 {
6472 if *resolved {
6473 return Ok(());
6474 }
6475 anyhow::ensure!(
6476 server_id == *completion_server_id,
6477 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6478 );
6479 **lsp_completion = resolved_completion;
6480 *resolved = true;
6481 }
6482 Ok(())
6483 }
6484
6485 async fn regenerate_completion_labels(
6486 adapter: Arc<CachedLspAdapter>,
6487 snapshot: &BufferSnapshot,
6488 completions: Rc<RefCell<Box<[Completion]>>>,
6489 completion_index: usize,
6490 ) -> Result<()> {
6491 let completion_item = completions.borrow()[completion_index]
6492 .source
6493 .lsp_completion(true)
6494 .map(Cow::into_owned);
6495 if let Some(lsp_documentation) = completion_item
6496 .as_ref()
6497 .and_then(|completion_item| completion_item.documentation.clone())
6498 {
6499 let mut completions = completions.borrow_mut();
6500 let completion = &mut completions[completion_index];
6501 completion.documentation = Some(lsp_documentation.into());
6502 } else {
6503 let mut completions = completions.borrow_mut();
6504 let completion = &mut completions[completion_index];
6505 completion.documentation = Some(CompletionDocumentation::Undocumented);
6506 }
6507
6508 let mut new_label = match completion_item {
6509 Some(completion_item) => {
6510 // Some language servers always return `detail` lazily via resolve, regardless of
6511 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6512 // See: https://github.com/yioneko/vtsls/issues/213
6513 let language = snapshot.language();
6514 match language {
6515 Some(language) => {
6516 adapter
6517 .labels_for_completions(
6518 std::slice::from_ref(&completion_item),
6519 language,
6520 )
6521 .await?
6522 }
6523 None => Vec::new(),
6524 }
6525 .pop()
6526 .flatten()
6527 .unwrap_or_else(|| {
6528 CodeLabel::fallback_for_completion(
6529 &completion_item,
6530 language.map(|language| language.as_ref()),
6531 )
6532 })
6533 }
6534 None => CodeLabel::plain(
6535 completions.borrow()[completion_index].new_text.clone(),
6536 None,
6537 ),
6538 };
6539 ensure_uniform_list_compatible_label(&mut new_label);
6540
6541 let mut completions = completions.borrow_mut();
6542 let completion = &mut completions[completion_index];
6543 if completion.label.filter_text() == new_label.filter_text() {
6544 completion.label = new_label;
6545 } else {
6546 log::error!(
6547 "Resolved completion changed display label from {} to {}. \
6548 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6549 completion.label.text(),
6550 new_label.text(),
6551 completion.label.filter_text(),
6552 new_label.filter_text()
6553 );
6554 }
6555
6556 Ok(())
6557 }
6558
6559 async fn resolve_completion_remote(
6560 project_id: u64,
6561 server_id: LanguageServerId,
6562 buffer_id: BufferId,
6563 completions: Rc<RefCell<Box<[Completion]>>>,
6564 completion_index: usize,
6565 client: AnyProtoClient,
6566 ) -> Result<()> {
6567 let lsp_completion = {
6568 let completion = &completions.borrow()[completion_index];
6569 match &completion.source {
6570 CompletionSource::Lsp {
6571 lsp_completion,
6572 resolved,
6573 server_id: completion_server_id,
6574 ..
6575 } => {
6576 anyhow::ensure!(
6577 server_id == *completion_server_id,
6578 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6579 );
6580 if *resolved {
6581 return Ok(());
6582 }
6583 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6584 }
6585 CompletionSource::Custom
6586 | CompletionSource::Dap { .. }
6587 | CompletionSource::BufferWord { .. } => {
6588 return Ok(());
6589 }
6590 }
6591 };
6592 let request = proto::ResolveCompletionDocumentation {
6593 project_id,
6594 language_server_id: server_id.0 as u64,
6595 lsp_completion,
6596 buffer_id: buffer_id.into(),
6597 };
6598
6599 let response = client
6600 .request(request)
6601 .await
6602 .context("completion documentation resolve proto request")?;
6603 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6604
6605 let documentation = if response.documentation.is_empty() {
6606 CompletionDocumentation::Undocumented
6607 } else if response.documentation_is_markdown {
6608 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6609 } else if response.documentation.lines().count() <= 1 {
6610 CompletionDocumentation::SingleLine(response.documentation.into())
6611 } else {
6612 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6613 };
6614
6615 let mut completions = completions.borrow_mut();
6616 let completion = &mut completions[completion_index];
6617 completion.documentation = Some(documentation);
6618 if let CompletionSource::Lsp {
6619 insert_range,
6620 lsp_completion,
6621 resolved,
6622 server_id: completion_server_id,
6623 lsp_defaults: _,
6624 } = &mut completion.source
6625 {
6626 let completion_insert_range = response
6627 .old_insert_start
6628 .and_then(deserialize_anchor)
6629 .zip(response.old_insert_end.and_then(deserialize_anchor));
6630 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6631
6632 if *resolved {
6633 return Ok(());
6634 }
6635 anyhow::ensure!(
6636 server_id == *completion_server_id,
6637 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6638 );
6639 **lsp_completion = resolved_lsp_completion;
6640 *resolved = true;
6641 }
6642
6643 let replace_range = response
6644 .old_replace_start
6645 .and_then(deserialize_anchor)
6646 .zip(response.old_replace_end.and_then(deserialize_anchor));
6647 if let Some((old_replace_start, old_replace_end)) = replace_range
6648 && !response.new_text.is_empty()
6649 {
6650 completion.new_text = response.new_text;
6651 completion.replace_range = old_replace_start..old_replace_end;
6652 }
6653
6654 Ok(())
6655 }
6656
6657 pub fn apply_additional_edits_for_completion(
6658 &self,
6659 buffer_handle: Entity<Buffer>,
6660 completions: Rc<RefCell<Box<[Completion]>>>,
6661 completion_index: usize,
6662 push_to_history: bool,
6663 all_commit_ranges: Vec<Range<language::Anchor>>,
6664 cx: &mut Context<Self>,
6665 ) -> Task<Result<Option<Transaction>>> {
6666 if let Some((client, project_id)) = self.upstream_client() {
6667 let buffer = buffer_handle.read(cx);
6668 let buffer_id = buffer.remote_id();
6669 cx.spawn(async move |_, cx| {
6670 let request = {
6671 let completion = completions.borrow()[completion_index].clone();
6672 proto::ApplyCompletionAdditionalEdits {
6673 project_id,
6674 buffer_id: buffer_id.into(),
6675 completion: Some(Self::serialize_completion(&CoreCompletion {
6676 replace_range: completion.replace_range,
6677 new_text: completion.new_text,
6678 source: completion.source,
6679 })),
6680 all_commit_ranges: all_commit_ranges
6681 .iter()
6682 .cloned()
6683 .map(language::proto::serialize_anchor_range)
6684 .collect(),
6685 }
6686 };
6687
6688 let Some(transaction) = client.request(request).await?.transaction else {
6689 return Ok(None);
6690 };
6691
6692 let transaction = language::proto::deserialize_transaction(transaction)?;
6693 buffer_handle
6694 .update(cx, |buffer, _| {
6695 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6696 })
6697 .await?;
6698 if push_to_history {
6699 buffer_handle.update(cx, |buffer, _| {
6700 buffer.push_transaction(transaction.clone(), Instant::now());
6701 buffer.finalize_last_transaction();
6702 });
6703 }
6704 Ok(Some(transaction))
6705 })
6706 } else {
6707 let request_timeout = ProjectSettings::get_global(cx)
6708 .global_lsp_settings
6709 .get_request_timeout();
6710
6711 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6712 let completion = &completions.borrow()[completion_index];
6713 let server_id = completion.source.server_id()?;
6714 Some(
6715 self.language_server_for_local_buffer(buffer, server_id, cx)?
6716 .1
6717 .clone(),
6718 )
6719 }) else {
6720 return Task::ready(Ok(None));
6721 };
6722
6723 cx.spawn(async move |this, cx| {
6724 Self::resolve_completion_local(
6725 server.clone(),
6726 completions.clone(),
6727 completion_index,
6728 request_timeout,
6729 )
6730 .await
6731 .context("resolving completion")?;
6732 let completion = completions.borrow()[completion_index].clone();
6733 let additional_text_edits = completion
6734 .source
6735 .lsp_completion(true)
6736 .as_ref()
6737 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6738 if let Some(edits) = additional_text_edits {
6739 let edits = this
6740 .update(cx, |this, cx| {
6741 this.as_local_mut().unwrap().edits_from_lsp(
6742 &buffer_handle,
6743 edits,
6744 server.server_id(),
6745 None,
6746 cx,
6747 )
6748 })?
6749 .await?;
6750
6751 buffer_handle.update(cx, |buffer, cx| {
6752 buffer.finalize_last_transaction();
6753 buffer.start_transaction();
6754
6755 for (range, text) in edits {
6756 let primary = &completion.replace_range;
6757
6758 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6759 // and the primary completion is just an insertion (empty range), then this is likely
6760 // an auto-import scenario and should not be considered overlapping
6761 // https://github.com/zed-industries/zed/issues/26136
6762 let is_file_start_auto_import = {
6763 let snapshot = buffer.snapshot();
6764 let primary_start_point = primary.start.to_point(&snapshot);
6765 let range_start_point = range.start.to_point(&snapshot);
6766
6767 let result = primary_start_point.row == 0
6768 && primary_start_point.column == 0
6769 && range_start_point.row == 0
6770 && range_start_point.column == 0;
6771
6772 result
6773 };
6774
6775 let has_overlap = if is_file_start_auto_import {
6776 false
6777 } else {
6778 all_commit_ranges.iter().any(|commit_range| {
6779 let start_within =
6780 commit_range.start.cmp(&range.start, buffer).is_le()
6781 && commit_range.end.cmp(&range.start, buffer).is_ge();
6782 let end_within =
6783 range.start.cmp(&commit_range.end, buffer).is_le()
6784 && range.end.cmp(&commit_range.end, buffer).is_ge();
6785 start_within || end_within
6786 })
6787 };
6788
6789 //Skip additional edits which overlap with the primary completion edit
6790 //https://github.com/zed-industries/zed/pull/1871
6791 if !has_overlap {
6792 buffer.edit([(range, text)], None, cx);
6793 }
6794 }
6795
6796 let transaction = if buffer.end_transaction(cx).is_some() {
6797 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6798 if !push_to_history {
6799 buffer.forget_transaction(transaction.id);
6800 }
6801 Some(transaction)
6802 } else {
6803 None
6804 };
6805 Ok(transaction)
6806 })
6807 } else {
6808 Ok(None)
6809 }
6810 })
6811 }
6812 }
6813
6814 pub fn pull_diagnostics(
6815 &mut self,
6816 buffer: Entity<Buffer>,
6817 cx: &mut Context<Self>,
6818 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6819 let buffer_id = buffer.read(cx).remote_id();
6820
6821 if let Some((client, upstream_project_id)) = self.upstream_client() {
6822 let mut suitable_capabilities = None;
6823 // Are we capable for proto request?
6824 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6825 &buffer,
6826 |capabilities| {
6827 if let Some(caps) = &capabilities.diagnostic_provider {
6828 suitable_capabilities = Some(caps.clone());
6829 true
6830 } else {
6831 false
6832 }
6833 },
6834 cx,
6835 );
6836 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6837 let Some(dynamic_caps) = suitable_capabilities else {
6838 return Task::ready(Ok(None));
6839 };
6840 assert!(any_server_has_diagnostics_provider);
6841
6842 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6843 let request = GetDocumentDiagnostics {
6844 previous_result_id: None,
6845 identifier,
6846 registration_id: None,
6847 };
6848 let request_timeout = ProjectSettings::get_global(cx)
6849 .global_lsp_settings
6850 .get_request_timeout();
6851 let request_task = client.request_lsp(
6852 upstream_project_id,
6853 None,
6854 request_timeout,
6855 cx.background_executor().clone(),
6856 request.to_proto(upstream_project_id, buffer.read(cx)),
6857 );
6858 cx.background_spawn(async move {
6859 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6860 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6861 // Do not attempt to further process the dummy responses here.
6862 let _response = request_task.await?;
6863 Ok(None)
6864 })
6865 } else {
6866 let servers = buffer.update(cx, |buffer, cx| {
6867 self.running_language_servers_for_local_buffer(buffer, cx)
6868 .map(|(_, server)| server.clone())
6869 .collect::<Vec<_>>()
6870 });
6871
6872 let pull_diagnostics = servers
6873 .into_iter()
6874 .flat_map(|server| {
6875 let result = maybe!({
6876 let local = self.as_local()?;
6877 let server_id = server.server_id();
6878 let providers_with_identifiers = local
6879 .language_server_dynamic_registrations
6880 .get(&server_id)
6881 .into_iter()
6882 .flat_map(|registrations| registrations.diagnostics.clone())
6883 .collect::<Vec<_>>();
6884 Some(
6885 providers_with_identifiers
6886 .into_iter()
6887 .map(|(registration_id, dynamic_caps)| {
6888 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6889 let registration_id = registration_id.map(SharedString::from);
6890 let result_id = self.result_id_for_buffer_pull(
6891 server_id,
6892 buffer_id,
6893 ®istration_id,
6894 cx,
6895 );
6896 self.request_lsp(
6897 buffer.clone(),
6898 LanguageServerToQuery::Other(server_id),
6899 GetDocumentDiagnostics {
6900 previous_result_id: result_id,
6901 registration_id,
6902 identifier,
6903 },
6904 cx,
6905 )
6906 })
6907 .collect::<Vec<_>>(),
6908 )
6909 });
6910
6911 result.unwrap_or_default()
6912 })
6913 .collect::<Vec<_>>();
6914
6915 cx.background_spawn(async move {
6916 let mut responses = Vec::new();
6917 for diagnostics in join_all(pull_diagnostics).await {
6918 responses.extend(diagnostics?);
6919 }
6920 Ok(Some(responses))
6921 })
6922 }
6923 }
6924
6925 pub fn applicable_inlay_chunks(
6926 &mut self,
6927 buffer: &Entity<Buffer>,
6928 ranges: &[Range<text::Anchor>],
6929 cx: &mut Context<Self>,
6930 ) -> Vec<Range<BufferRow>> {
6931 let buffer_snapshot = buffer.read(cx).snapshot();
6932 let ranges = ranges
6933 .iter()
6934 .map(|range| range.to_point(&buffer_snapshot))
6935 .collect::<Vec<_>>();
6936
6937 self.latest_lsp_data(buffer, cx)
6938 .inlay_hints
6939 .applicable_chunks(ranges.as_slice())
6940 .map(|chunk| chunk.row_range())
6941 .collect()
6942 }
6943
6944 pub fn invalidate_inlay_hints<'a>(
6945 &'a mut self,
6946 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6947 ) {
6948 for buffer_id in for_buffers {
6949 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6950 lsp_data.inlay_hints.clear();
6951 }
6952 }
6953 }
6954
6955 pub fn inlay_hints(
6956 &mut self,
6957 invalidate: InvalidationStrategy,
6958 buffer: Entity<Buffer>,
6959 ranges: Vec<Range<text::Anchor>>,
6960 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6961 cx: &mut Context<Self>,
6962 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6963 let next_hint_id = self.next_hint_id.clone();
6964 let lsp_data = self.latest_lsp_data(&buffer, cx);
6965 let query_version = lsp_data.buffer_version.clone();
6966 let mut lsp_refresh_requested = false;
6967 let for_server = if let InvalidationStrategy::RefreshRequested {
6968 server_id,
6969 request_id,
6970 } = invalidate
6971 {
6972 let invalidated = lsp_data
6973 .inlay_hints
6974 .invalidate_for_server_refresh(server_id, request_id);
6975 lsp_refresh_requested = invalidated;
6976 Some(server_id)
6977 } else {
6978 None
6979 };
6980 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6981 let known_chunks = known_chunks
6982 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6983 .map(|(_, known_chunks)| known_chunks)
6984 .unwrap_or_default();
6985
6986 let buffer_snapshot = buffer.read(cx).snapshot();
6987 let ranges = ranges
6988 .iter()
6989 .map(|range| range.to_point(&buffer_snapshot))
6990 .collect::<Vec<_>>();
6991
6992 let mut hint_fetch_tasks = Vec::new();
6993 let mut cached_inlay_hints = None;
6994 let mut ranges_to_query = None;
6995 let applicable_chunks = existing_inlay_hints
6996 .applicable_chunks(ranges.as_slice())
6997 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6998 .collect::<Vec<_>>();
6999 if applicable_chunks.is_empty() {
7000 return HashMap::default();
7001 }
7002
7003 for row_chunk in applicable_chunks {
7004 match (
7005 existing_inlay_hints
7006 .cached_hints(&row_chunk)
7007 .filter(|_| !lsp_refresh_requested)
7008 .cloned(),
7009 existing_inlay_hints
7010 .fetched_hints(&row_chunk)
7011 .as_ref()
7012 .filter(|_| !lsp_refresh_requested)
7013 .cloned(),
7014 ) {
7015 (None, None) => {
7016 let chunk_range = row_chunk.anchor_range();
7017 ranges_to_query
7018 .get_or_insert_with(Vec::new)
7019 .push((row_chunk, chunk_range));
7020 }
7021 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7022 (Some(cached_hints), None) => {
7023 for (server_id, cached_hints) in cached_hints {
7024 if for_server.is_none_or(|for_server| for_server == server_id) {
7025 cached_inlay_hints
7026 .get_or_insert_with(HashMap::default)
7027 .entry(row_chunk.row_range())
7028 .or_insert_with(HashMap::default)
7029 .entry(server_id)
7030 .or_insert_with(Vec::new)
7031 .extend(cached_hints);
7032 }
7033 }
7034 }
7035 (Some(cached_hints), Some(fetched_hints)) => {
7036 hint_fetch_tasks.push((row_chunk, fetched_hints));
7037 for (server_id, cached_hints) in cached_hints {
7038 if for_server.is_none_or(|for_server| for_server == server_id) {
7039 cached_inlay_hints
7040 .get_or_insert_with(HashMap::default)
7041 .entry(row_chunk.row_range())
7042 .or_insert_with(HashMap::default)
7043 .entry(server_id)
7044 .or_insert_with(Vec::new)
7045 .extend(cached_hints);
7046 }
7047 }
7048 }
7049 }
7050 }
7051
7052 if hint_fetch_tasks.is_empty()
7053 && ranges_to_query
7054 .as_ref()
7055 .is_none_or(|ranges| ranges.is_empty())
7056 && let Some(cached_inlay_hints) = cached_inlay_hints
7057 {
7058 cached_inlay_hints
7059 .into_iter()
7060 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7061 .collect()
7062 } else {
7063 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7064 // When a server refresh was requested, other servers' cached hints
7065 // are unaffected by the refresh and must be included in the result.
7066 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7067 // removes all visible hints but only adds back the requesting
7068 // server's new hints, permanently losing other servers' hints.
7069 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7070 lsp_data
7071 .inlay_hints
7072 .cached_hints(&chunk)
7073 .cloned()
7074 .unwrap_or_default()
7075 } else {
7076 HashMap::default()
7077 };
7078
7079 let next_hint_id = next_hint_id.clone();
7080 let buffer = buffer.clone();
7081 let query_version = query_version.clone();
7082 let new_inlay_hints = cx
7083 .spawn(async move |lsp_store, cx| {
7084 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7085 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7086 })?;
7087 new_fetch_task
7088 .await
7089 .and_then(|new_hints_by_server| {
7090 lsp_store.update(cx, |lsp_store, cx| {
7091 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7092 let update_cache = lsp_data.buffer_version == query_version;
7093 if new_hints_by_server.is_empty() {
7094 if update_cache {
7095 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7096 }
7097 other_servers_cached
7098 } else {
7099 let mut result = other_servers_cached;
7100 for (server_id, new_hints) in new_hints_by_server {
7101 let new_hints = new_hints
7102 .into_iter()
7103 .map(|new_hint| {
7104 (
7105 InlayId::Hint(next_hint_id.fetch_add(
7106 1,
7107 atomic::Ordering::AcqRel,
7108 )),
7109 new_hint,
7110 )
7111 })
7112 .collect::<Vec<_>>();
7113 if update_cache {
7114 lsp_data.inlay_hints.insert_new_hints(
7115 chunk,
7116 server_id,
7117 new_hints.clone(),
7118 );
7119 }
7120 result.insert(server_id, new_hints);
7121 }
7122 result
7123 }
7124 })
7125 })
7126 .map_err(Arc::new)
7127 })
7128 .shared();
7129
7130 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7131 *fetch_task = Some(new_inlay_hints.clone());
7132 hint_fetch_tasks.push((chunk, new_inlay_hints));
7133 }
7134
7135 cached_inlay_hints
7136 .unwrap_or_default()
7137 .into_iter()
7138 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7139 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7140 (
7141 chunk.row_range(),
7142 cx.spawn(async move |_, _| {
7143 hints_fetch.await.map_err(|e| {
7144 if e.error_code() != ErrorCode::Internal {
7145 anyhow!(e.error_code())
7146 } else {
7147 anyhow!("{e:#}")
7148 }
7149 })
7150 }),
7151 )
7152 }))
7153 .collect()
7154 }
7155 }
7156
7157 fn fetch_inlay_hints(
7158 &mut self,
7159 for_server: Option<LanguageServerId>,
7160 buffer: &Entity<Buffer>,
7161 range: Range<Anchor>,
7162 cx: &mut Context<Self>,
7163 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7164 let request = InlayHints {
7165 range: range.clone(),
7166 };
7167 if let Some((upstream_client, project_id)) = self.upstream_client() {
7168 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7169 return Task::ready(Ok(HashMap::default()));
7170 }
7171 let request_timeout = ProjectSettings::get_global(cx)
7172 .global_lsp_settings
7173 .get_request_timeout();
7174 let request_task = upstream_client.request_lsp(
7175 project_id,
7176 for_server.map(|id| id.to_proto()),
7177 request_timeout,
7178 cx.background_executor().clone(),
7179 request.to_proto(project_id, buffer.read(cx)),
7180 );
7181 let buffer = buffer.clone();
7182 cx.spawn(async move |weak_lsp_store, cx| {
7183 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7184 return Ok(HashMap::default());
7185 };
7186 let Some(responses) = request_task.await? else {
7187 return Ok(HashMap::default());
7188 };
7189
7190 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7191 let lsp_store = lsp_store.clone();
7192 let buffer = buffer.clone();
7193 let cx = cx.clone();
7194 let request = request.clone();
7195 async move {
7196 (
7197 LanguageServerId::from_proto(response.server_id),
7198 request
7199 .response_from_proto(response.response, lsp_store, buffer, cx)
7200 .await,
7201 )
7202 }
7203 }))
7204 .await;
7205
7206 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7207 let mut has_errors = false;
7208 let inlay_hints = inlay_hints
7209 .into_iter()
7210 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7211 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7212 Err(e) => {
7213 has_errors = true;
7214 log::error!("{e:#}");
7215 None
7216 }
7217 })
7218 .map(|(server_id, mut new_hints)| {
7219 new_hints.retain(|hint| {
7220 hint.position.is_valid(&buffer_snapshot)
7221 && range.start.is_valid(&buffer_snapshot)
7222 && range.end.is_valid(&buffer_snapshot)
7223 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7224 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7225 });
7226 (server_id, new_hints)
7227 })
7228 .collect::<HashMap<_, _>>();
7229 anyhow::ensure!(
7230 !has_errors || !inlay_hints.is_empty(),
7231 "Failed to fetch inlay hints"
7232 );
7233 Ok(inlay_hints)
7234 })
7235 } else {
7236 let inlay_hints_task = match for_server {
7237 Some(server_id) => {
7238 let server_task = self.request_lsp(
7239 buffer.clone(),
7240 LanguageServerToQuery::Other(server_id),
7241 request,
7242 cx,
7243 );
7244 cx.background_spawn(async move {
7245 let mut responses = Vec::new();
7246 match server_task.await {
7247 Ok(response) => responses.push((server_id, response)),
7248 // rust-analyzer likes to error with this when its still loading up
7249 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7250 Err(e) => log::error!(
7251 "Error handling response for inlay hints request: {e:#}"
7252 ),
7253 }
7254 responses
7255 })
7256 }
7257 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7258 };
7259 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7260 cx.background_spawn(async move {
7261 Ok(inlay_hints_task
7262 .await
7263 .into_iter()
7264 .map(|(server_id, mut new_hints)| {
7265 new_hints.retain(|hint| {
7266 hint.position.is_valid(&buffer_snapshot)
7267 && range.start.is_valid(&buffer_snapshot)
7268 && range.end.is_valid(&buffer_snapshot)
7269 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7270 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7271 });
7272 (server_id, new_hints)
7273 })
7274 .collect())
7275 })
7276 }
7277 }
7278
7279 fn diagnostic_registration_exists(
7280 &self,
7281 server_id: LanguageServerId,
7282 registration_id: &Option<SharedString>,
7283 ) -> bool {
7284 let Some(local) = self.as_local() else {
7285 return false;
7286 };
7287 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7288 else {
7289 return false;
7290 };
7291 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7292 registrations.diagnostics.contains_key(®istration_key)
7293 }
7294
7295 pub fn pull_diagnostics_for_buffer(
7296 &mut self,
7297 buffer: Entity<Buffer>,
7298 cx: &mut Context<Self>,
7299 ) -> Task<anyhow::Result<()>> {
7300 let diagnostics = self.pull_diagnostics(buffer, cx);
7301 cx.spawn(async move |lsp_store, cx| {
7302 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7303 return Ok(());
7304 };
7305 lsp_store.update(cx, |lsp_store, cx| {
7306 if lsp_store.as_local().is_none() {
7307 return;
7308 }
7309
7310 let mut unchanged_buffers = HashMap::default();
7311 let server_diagnostics_updates = diagnostics
7312 .into_iter()
7313 .filter_map(|diagnostics_set| match diagnostics_set {
7314 LspPullDiagnostics::Response {
7315 server_id,
7316 uri,
7317 diagnostics,
7318 registration_id,
7319 } => Some((server_id, uri, diagnostics, registration_id)),
7320 LspPullDiagnostics::Default => None,
7321 })
7322 .filter(|(server_id, _, _, registration_id)| {
7323 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7324 })
7325 .fold(
7326 HashMap::default(),
7327 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7328 let (result_id, diagnostics) = match diagnostics {
7329 PulledDiagnostics::Unchanged { result_id } => {
7330 unchanged_buffers
7331 .entry(new_registration_id.clone())
7332 .or_insert_with(HashSet::default)
7333 .insert(uri.clone());
7334 (Some(result_id), Vec::new())
7335 }
7336 PulledDiagnostics::Changed {
7337 result_id,
7338 diagnostics,
7339 } => (result_id, diagnostics),
7340 };
7341 let disk_based_sources = Cow::Owned(
7342 lsp_store
7343 .language_server_adapter_for_id(server_id)
7344 .as_ref()
7345 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7346 .unwrap_or(&[])
7347 .to_vec(),
7348 );
7349 acc.entry(server_id)
7350 .or_insert_with(HashMap::default)
7351 .entry(new_registration_id.clone())
7352 .or_insert_with(Vec::new)
7353 .push(DocumentDiagnosticsUpdate {
7354 server_id,
7355 diagnostics: lsp::PublishDiagnosticsParams {
7356 uri,
7357 diagnostics,
7358 version: None,
7359 },
7360 result_id: result_id.map(SharedString::new),
7361 disk_based_sources,
7362 registration_id: new_registration_id,
7363 });
7364 acc
7365 },
7366 );
7367
7368 for diagnostic_updates in server_diagnostics_updates.into_values() {
7369 for (registration_id, diagnostic_updates) in diagnostic_updates {
7370 lsp_store
7371 .merge_lsp_diagnostics(
7372 DiagnosticSourceKind::Pulled,
7373 diagnostic_updates,
7374 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7375 DiagnosticSourceKind::Pulled => {
7376 old_diagnostic.registration_id != registration_id
7377 || unchanged_buffers
7378 .get(&old_diagnostic.registration_id)
7379 .is_some_and(|unchanged_buffers| {
7380 unchanged_buffers.contains(&document_uri)
7381 })
7382 }
7383 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7384 true
7385 }
7386 },
7387 cx,
7388 )
7389 .log_err();
7390 }
7391 }
7392 })
7393 })
7394 }
7395
7396 pub fn signature_help<T: ToPointUtf16>(
7397 &mut self,
7398 buffer: &Entity<Buffer>,
7399 position: T,
7400 cx: &mut Context<Self>,
7401 ) -> Task<Option<Vec<SignatureHelp>>> {
7402 let position = position.to_point_utf16(buffer.read(cx));
7403
7404 if let Some((client, upstream_project_id)) = self.upstream_client() {
7405 let request = GetSignatureHelp { position };
7406 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7407 return Task::ready(None);
7408 }
7409 let request_timeout = ProjectSettings::get_global(cx)
7410 .global_lsp_settings
7411 .get_request_timeout();
7412 let request_task = client.request_lsp(
7413 upstream_project_id,
7414 None,
7415 request_timeout,
7416 cx.background_executor().clone(),
7417 request.to_proto(upstream_project_id, buffer.read(cx)),
7418 );
7419 let buffer = buffer.clone();
7420 cx.spawn(async move |weak_lsp_store, cx| {
7421 let lsp_store = weak_lsp_store.upgrade()?;
7422 let signatures = join_all(
7423 request_task
7424 .await
7425 .log_err()
7426 .flatten()
7427 .map(|response| response.payload)
7428 .unwrap_or_default()
7429 .into_iter()
7430 .map(|response| {
7431 let response = GetSignatureHelp { position }.response_from_proto(
7432 response.response,
7433 lsp_store.clone(),
7434 buffer.clone(),
7435 cx.clone(),
7436 );
7437 async move { response.await.log_err().flatten() }
7438 }),
7439 )
7440 .await
7441 .into_iter()
7442 .flatten()
7443 .collect();
7444 Some(signatures)
7445 })
7446 } else {
7447 let all_actions_task = self.request_multiple_lsp_locally(
7448 buffer,
7449 Some(position),
7450 GetSignatureHelp { position },
7451 cx,
7452 );
7453 cx.background_spawn(async move {
7454 Some(
7455 all_actions_task
7456 .await
7457 .into_iter()
7458 .flat_map(|(_, actions)| actions)
7459 .collect::<Vec<_>>(),
7460 )
7461 })
7462 }
7463 }
7464
7465 pub fn hover(
7466 &mut self,
7467 buffer: &Entity<Buffer>,
7468 position: PointUtf16,
7469 cx: &mut Context<Self>,
7470 ) -> Task<Option<Vec<Hover>>> {
7471 if let Some((client, upstream_project_id)) = self.upstream_client() {
7472 let request = GetHover { position };
7473 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7474 return Task::ready(None);
7475 }
7476 let request_timeout = ProjectSettings::get_global(cx)
7477 .global_lsp_settings
7478 .get_request_timeout();
7479 let request_task = client.request_lsp(
7480 upstream_project_id,
7481 None,
7482 request_timeout,
7483 cx.background_executor().clone(),
7484 request.to_proto(upstream_project_id, buffer.read(cx)),
7485 );
7486 let buffer = buffer.clone();
7487 cx.spawn(async move |weak_lsp_store, cx| {
7488 let lsp_store = weak_lsp_store.upgrade()?;
7489 let hovers = join_all(
7490 request_task
7491 .await
7492 .log_err()
7493 .flatten()
7494 .map(|response| response.payload)
7495 .unwrap_or_default()
7496 .into_iter()
7497 .map(|response| {
7498 let response = GetHover { position }.response_from_proto(
7499 response.response,
7500 lsp_store.clone(),
7501 buffer.clone(),
7502 cx.clone(),
7503 );
7504 async move {
7505 response
7506 .await
7507 .log_err()
7508 .flatten()
7509 .and_then(remove_empty_hover_blocks)
7510 }
7511 }),
7512 )
7513 .await
7514 .into_iter()
7515 .flatten()
7516 .collect();
7517 Some(hovers)
7518 })
7519 } else {
7520 let all_actions_task = self.request_multiple_lsp_locally(
7521 buffer,
7522 Some(position),
7523 GetHover { position },
7524 cx,
7525 );
7526 cx.background_spawn(async move {
7527 Some(
7528 all_actions_task
7529 .await
7530 .into_iter()
7531 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7532 .collect::<Vec<Hover>>(),
7533 )
7534 })
7535 }
7536 }
7537
7538 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7539 let language_registry = self.languages.clone();
7540
7541 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7542 let request = upstream_client.request(proto::GetProjectSymbols {
7543 project_id: *project_id,
7544 query: query.to_string(),
7545 });
7546 cx.foreground_executor().spawn(async move {
7547 let response = request.await?;
7548 let mut symbols = Vec::new();
7549 let core_symbols = response
7550 .symbols
7551 .into_iter()
7552 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7553 .collect::<Vec<_>>();
7554 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7555 .await;
7556 Ok(symbols)
7557 })
7558 } else if let Some(local) = self.as_local() {
7559 struct WorkspaceSymbolsResult {
7560 server_id: LanguageServerId,
7561 lsp_adapter: Arc<CachedLspAdapter>,
7562 worktree: WeakEntity<Worktree>,
7563 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7564 }
7565
7566 let mut requests = Vec::new();
7567 let mut requested_servers = BTreeSet::new();
7568 let request_timeout = ProjectSettings::get_global(cx)
7569 .global_lsp_settings
7570 .get_request_timeout();
7571
7572 for (seed, state) in local.language_server_ids.iter() {
7573 let Some(worktree_handle) = self
7574 .worktree_store
7575 .read(cx)
7576 .worktree_for_id(seed.worktree_id, cx)
7577 else {
7578 continue;
7579 };
7580
7581 let worktree = worktree_handle.read(cx);
7582 if !worktree.is_visible() {
7583 continue;
7584 }
7585
7586 if !requested_servers.insert(state.id) {
7587 continue;
7588 }
7589
7590 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7591 Some(LanguageServerState::Running {
7592 adapter, server, ..
7593 }) => (adapter.clone(), server),
7594
7595 _ => continue,
7596 };
7597
7598 let supports_workspace_symbol_request =
7599 match server.capabilities().workspace_symbol_provider {
7600 Some(OneOf::Left(supported)) => supported,
7601 Some(OneOf::Right(_)) => true,
7602 None => false,
7603 };
7604
7605 if !supports_workspace_symbol_request {
7606 continue;
7607 }
7608
7609 let worktree_handle = worktree_handle.clone();
7610 let server_id = server.server_id();
7611 requests.push(
7612 server
7613 .request::<lsp::request::WorkspaceSymbolRequest>(
7614 lsp::WorkspaceSymbolParams {
7615 query: query.to_string(),
7616 ..Default::default()
7617 },
7618 request_timeout,
7619 )
7620 .map(move |response| {
7621 let lsp_symbols = response
7622 .into_response()
7623 .context("workspace symbols request")
7624 .log_err()
7625 .flatten()
7626 .map(|symbol_response| match symbol_response {
7627 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7628 flat_responses
7629 .into_iter()
7630 .map(|lsp_symbol| {
7631 (
7632 lsp_symbol.name,
7633 lsp_symbol.kind,
7634 lsp_symbol.location,
7635 lsp_symbol.container_name,
7636 )
7637 })
7638 .collect::<Vec<_>>()
7639 }
7640 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7641 nested_responses
7642 .into_iter()
7643 .filter_map(|lsp_symbol| {
7644 let location = match lsp_symbol.location {
7645 OneOf::Left(location) => location,
7646 OneOf::Right(_) => {
7647 log::error!(
7648 "Unexpected: client capabilities \
7649 forbid symbol resolutions in \
7650 workspace.symbol.resolveSupport"
7651 );
7652 return None;
7653 }
7654 };
7655 Some((
7656 lsp_symbol.name,
7657 lsp_symbol.kind,
7658 location,
7659 lsp_symbol.container_name,
7660 ))
7661 })
7662 .collect::<Vec<_>>()
7663 }
7664 })
7665 .unwrap_or_default();
7666
7667 WorkspaceSymbolsResult {
7668 server_id,
7669 lsp_adapter,
7670 worktree: worktree_handle.downgrade(),
7671 lsp_symbols,
7672 }
7673 }),
7674 );
7675 }
7676
7677 cx.spawn(async move |this, cx| {
7678 let responses = futures::future::join_all(requests).await;
7679 let this = match this.upgrade() {
7680 Some(this) => this,
7681 None => return Ok(Vec::new()),
7682 };
7683
7684 let mut symbols = Vec::new();
7685 for result in responses {
7686 let core_symbols = this.update(cx, |this, cx| {
7687 result
7688 .lsp_symbols
7689 .into_iter()
7690 .filter_map(
7691 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7692 let abs_path = symbol_location.uri.to_file_path().ok()?;
7693 let source_worktree = result.worktree.upgrade()?;
7694 let source_worktree_id = source_worktree.read(cx).id();
7695
7696 let path = if let Some((tree, rel_path)) =
7697 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7698 {
7699 let worktree_id = tree.read(cx).id();
7700 SymbolLocation::InProject(ProjectPath {
7701 worktree_id,
7702 path: rel_path,
7703 })
7704 } else {
7705 SymbolLocation::OutsideProject {
7706 signature: this.symbol_signature(&abs_path),
7707 abs_path: abs_path.into(),
7708 }
7709 };
7710
7711 Some(CoreSymbol {
7712 source_language_server_id: result.server_id,
7713 language_server_name: result.lsp_adapter.name.clone(),
7714 source_worktree_id,
7715 path,
7716 kind: symbol_kind,
7717 name: collapse_newlines(&symbol_name, "↵ "),
7718 range: range_from_lsp(symbol_location.range),
7719 container_name: container_name
7720 .map(|c| collapse_newlines(&c, "↵ ")),
7721 })
7722 },
7723 )
7724 .collect::<Vec<_>>()
7725 });
7726
7727 populate_labels_for_symbols(
7728 core_symbols,
7729 &language_registry,
7730 Some(result.lsp_adapter),
7731 &mut symbols,
7732 )
7733 .await;
7734 }
7735
7736 Ok(symbols)
7737 })
7738 } else {
7739 Task::ready(Err(anyhow!("No upstream client or local language server")))
7740 }
7741 }
7742
7743 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7744 let mut summary = DiagnosticSummary::default();
7745 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7746 summary.error_count += path_summary.error_count;
7747 summary.warning_count += path_summary.warning_count;
7748 }
7749 summary
7750 }
7751
7752 /// Returns the diagnostic summary for a specific project path.
7753 pub fn diagnostic_summary_for_path(
7754 &self,
7755 project_path: &ProjectPath,
7756 _: &App,
7757 ) -> DiagnosticSummary {
7758 if let Some(summaries) = self
7759 .diagnostic_summaries
7760 .get(&project_path.worktree_id)
7761 .and_then(|map| map.get(&project_path.path))
7762 {
7763 let (error_count, warning_count) = summaries.iter().fold(
7764 (0, 0),
7765 |(error_count, warning_count), (_language_server_id, summary)| {
7766 (
7767 error_count + summary.error_count,
7768 warning_count + summary.warning_count,
7769 )
7770 },
7771 );
7772
7773 DiagnosticSummary {
7774 error_count,
7775 warning_count,
7776 }
7777 } else {
7778 DiagnosticSummary::default()
7779 }
7780 }
7781
7782 pub fn diagnostic_summaries<'a>(
7783 &'a self,
7784 include_ignored: bool,
7785 cx: &'a App,
7786 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7787 self.worktree_store
7788 .read(cx)
7789 .visible_worktrees(cx)
7790 .filter_map(|worktree| {
7791 let worktree = worktree.read(cx);
7792 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7793 })
7794 .flat_map(move |(worktree, summaries)| {
7795 let worktree_id = worktree.id();
7796 summaries
7797 .iter()
7798 .filter(move |(path, _)| {
7799 include_ignored
7800 || worktree
7801 .entry_for_path(path.as_ref())
7802 .is_some_and(|entry| !entry.is_ignored)
7803 })
7804 .flat_map(move |(path, summaries)| {
7805 summaries.iter().map(move |(server_id, summary)| {
7806 (
7807 ProjectPath {
7808 worktree_id,
7809 path: path.clone(),
7810 },
7811 *server_id,
7812 *summary,
7813 )
7814 })
7815 })
7816 })
7817 }
7818
7819 pub fn on_buffer_edited(
7820 &mut self,
7821 buffer: Entity<Buffer>,
7822 cx: &mut Context<Self>,
7823 ) -> Option<()> {
7824 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7825 Some(
7826 self.as_local()?
7827 .language_servers_for_buffer(buffer, cx)
7828 .map(|i| i.1.clone())
7829 .collect(),
7830 )
7831 })?;
7832
7833 let buffer = buffer.read(cx);
7834 let file = File::from_dyn(buffer.file())?;
7835 let abs_path = file.as_local()?.abs_path(cx);
7836 let uri = lsp::Uri::from_file_path(&abs_path)
7837 .ok()
7838 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7839 .log_err()?;
7840 let next_snapshot = buffer.text_snapshot();
7841 for language_server in language_servers {
7842 let language_server = language_server.clone();
7843
7844 let buffer_snapshots = self
7845 .as_local_mut()?
7846 .buffer_snapshots
7847 .get_mut(&buffer.remote_id())
7848 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7849 let previous_snapshot = buffer_snapshots.last()?;
7850
7851 let build_incremental_change = || {
7852 buffer
7853 .edits_since::<Dimensions<PointUtf16, usize>>(
7854 previous_snapshot.snapshot.version(),
7855 )
7856 .map(|edit| {
7857 let edit_start = edit.new.start.0;
7858 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7859 let new_text = next_snapshot
7860 .text_for_range(edit.new.start.1..edit.new.end.1)
7861 .collect();
7862 lsp::TextDocumentContentChangeEvent {
7863 range: Some(lsp::Range::new(
7864 point_to_lsp(edit_start),
7865 point_to_lsp(edit_end),
7866 )),
7867 range_length: None,
7868 text: new_text,
7869 }
7870 })
7871 .collect()
7872 };
7873
7874 let document_sync_kind = language_server
7875 .capabilities()
7876 .text_document_sync
7877 .as_ref()
7878 .and_then(|sync| match sync {
7879 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7880 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7881 });
7882
7883 let content_changes: Vec<_> = match document_sync_kind {
7884 Some(lsp::TextDocumentSyncKind::FULL) => {
7885 vec![lsp::TextDocumentContentChangeEvent {
7886 range: None,
7887 range_length: None,
7888 text: next_snapshot.text(),
7889 }]
7890 }
7891 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7892 _ => {
7893 #[cfg(any(test, feature = "test-support"))]
7894 {
7895 build_incremental_change()
7896 }
7897
7898 #[cfg(not(any(test, feature = "test-support")))]
7899 {
7900 continue;
7901 }
7902 }
7903 };
7904
7905 let next_version = previous_snapshot.version + 1;
7906 buffer_snapshots.push(LspBufferSnapshot {
7907 version: next_version,
7908 snapshot: next_snapshot.clone(),
7909 });
7910
7911 language_server
7912 .notify::<lsp::notification::DidChangeTextDocument>(
7913 lsp::DidChangeTextDocumentParams {
7914 text_document: lsp::VersionedTextDocumentIdentifier::new(
7915 uri.clone(),
7916 next_version,
7917 ),
7918 content_changes,
7919 },
7920 )
7921 .ok();
7922 self.pull_workspace_diagnostics(language_server.server_id());
7923 }
7924
7925 None
7926 }
7927
7928 pub fn on_buffer_saved(
7929 &mut self,
7930 buffer: Entity<Buffer>,
7931 cx: &mut Context<Self>,
7932 ) -> Option<()> {
7933 let file = File::from_dyn(buffer.read(cx).file())?;
7934 let worktree_id = file.worktree_id(cx);
7935 let abs_path = file.as_local()?.abs_path(cx);
7936 let text_document = lsp::TextDocumentIdentifier {
7937 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7938 };
7939 let local = self.as_local()?;
7940
7941 for server in local.language_servers_for_worktree(worktree_id) {
7942 if let Some(include_text) = include_text(server.as_ref()) {
7943 let text = if include_text {
7944 Some(buffer.read(cx).text())
7945 } else {
7946 None
7947 };
7948 server
7949 .notify::<lsp::notification::DidSaveTextDocument>(
7950 lsp::DidSaveTextDocumentParams {
7951 text_document: text_document.clone(),
7952 text,
7953 },
7954 )
7955 .ok();
7956 }
7957 }
7958
7959 let language_servers = buffer.update(cx, |buffer, cx| {
7960 local.language_server_ids_for_buffer(buffer, cx)
7961 });
7962 for language_server_id in language_servers {
7963 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7964 }
7965
7966 None
7967 }
7968
7969 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
7970 let buffer_id = buffer.read(cx).remote_id();
7971 let task = self.pull_diagnostics_for_buffer(buffer, cx);
7972 self.buffer_reload_tasks.insert(buffer_id, task);
7973 }
7974
7975 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7976 maybe!(async move {
7977 let mut refreshed_servers = HashSet::default();
7978 let servers = lsp_store
7979 .update(cx, |lsp_store, cx| {
7980 let local = lsp_store.as_local()?;
7981
7982 let servers = local
7983 .language_server_ids
7984 .iter()
7985 .filter_map(|(seed, state)| {
7986 let worktree = lsp_store
7987 .worktree_store
7988 .read(cx)
7989 .worktree_for_id(seed.worktree_id, cx);
7990 let delegate: Arc<dyn LspAdapterDelegate> =
7991 worktree.map(|worktree| {
7992 LocalLspAdapterDelegate::new(
7993 local.languages.clone(),
7994 &local.environment,
7995 cx.weak_entity(),
7996 &worktree,
7997 local.http_client.clone(),
7998 local.fs.clone(),
7999 cx,
8000 )
8001 })?;
8002 let server_id = state.id;
8003
8004 let states = local.language_servers.get(&server_id)?;
8005
8006 match states {
8007 LanguageServerState::Starting { .. } => None,
8008 LanguageServerState::Running {
8009 adapter, server, ..
8010 } => {
8011 let adapter = adapter.clone();
8012 let server = server.clone();
8013 refreshed_servers.insert(server.name());
8014 let toolchain = seed.toolchain.clone();
8015 Some(cx.spawn(async move |_, cx| {
8016 let settings =
8017 LocalLspStore::workspace_configuration_for_adapter(
8018 adapter.adapter.clone(),
8019 &delegate,
8020 toolchain,
8021 None,
8022 cx,
8023 )
8024 .await
8025 .ok()?;
8026 server
8027 .notify::<lsp::notification::DidChangeConfiguration>(
8028 lsp::DidChangeConfigurationParams { settings },
8029 )
8030 .ok()?;
8031 Some(())
8032 }))
8033 }
8034 }
8035 })
8036 .collect::<Vec<_>>();
8037
8038 Some(servers)
8039 })
8040 .ok()
8041 .flatten()?;
8042
8043 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8044 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8045 // to stop and unregister its language server wrapper.
8046 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8047 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8048 let _: Vec<Option<()>> = join_all(servers).await;
8049
8050 Some(())
8051 })
8052 .await;
8053 }
8054
8055 fn maintain_workspace_config(
8056 external_refresh_requests: watch::Receiver<()>,
8057 cx: &mut Context<Self>,
8058 ) -> Task<Result<()>> {
8059 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8060 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8061
8062 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8063 *settings_changed_tx.borrow_mut() = ();
8064 });
8065
8066 let mut joint_future =
8067 futures::stream::select(settings_changed_rx, external_refresh_requests);
8068 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8069 // - 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).
8070 // - 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.
8071 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8072 // - 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,
8073 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8074 cx.spawn(async move |this, cx| {
8075 while let Some(()) = joint_future.next().await {
8076 this.update(cx, |this, cx| {
8077 this.refresh_server_tree(cx);
8078 })
8079 .ok();
8080
8081 Self::refresh_workspace_configurations(&this, cx).await;
8082 }
8083
8084 drop(settings_observation);
8085 anyhow::Ok(())
8086 })
8087 }
8088
8089 pub fn running_language_servers_for_local_buffer<'a>(
8090 &'a self,
8091 buffer: &Buffer,
8092 cx: &mut App,
8093 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8094 let local = self.as_local();
8095 let language_server_ids = local
8096 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8097 .unwrap_or_default();
8098
8099 language_server_ids
8100 .into_iter()
8101 .filter_map(
8102 move |server_id| match local?.language_servers.get(&server_id)? {
8103 LanguageServerState::Running {
8104 adapter, server, ..
8105 } => Some((adapter, server)),
8106 _ => None,
8107 },
8108 )
8109 }
8110
8111 pub fn language_servers_for_local_buffer(
8112 &self,
8113 buffer: &Buffer,
8114 cx: &mut App,
8115 ) -> Vec<LanguageServerId> {
8116 let local = self.as_local();
8117 local
8118 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8119 .unwrap_or_default()
8120 }
8121
8122 pub fn language_server_for_local_buffer<'a>(
8123 &'a self,
8124 buffer: &'a Buffer,
8125 server_id: LanguageServerId,
8126 cx: &'a mut App,
8127 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8128 self.as_local()?
8129 .language_servers_for_buffer(buffer, cx)
8130 .find(|(_, s)| s.server_id() == server_id)
8131 }
8132
8133 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8134 self.diagnostic_summaries.remove(&id_to_remove);
8135 if let Some(local) = self.as_local_mut() {
8136 let to_remove = local.remove_worktree(id_to_remove, cx);
8137 for server in to_remove {
8138 self.language_server_statuses.remove(&server);
8139 }
8140 }
8141 }
8142
8143 fn invalidate_diagnostic_summaries_for_removed_entries(
8144 &mut self,
8145 worktree_id: WorktreeId,
8146 changes: &UpdatedEntriesSet,
8147 cx: &mut Context<Self>,
8148 ) {
8149 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8150 return;
8151 };
8152
8153 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8154 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8155 let downstream = self.downstream_client.clone();
8156
8157 for (path, _, _) in changes
8158 .iter()
8159 .filter(|(_, _, change)| *change == PathChange::Removed)
8160 {
8161 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8162 for (server_id, _) in &summaries_by_server_id {
8163 cleared_server_ids.insert(*server_id);
8164 if let Some((client, project_id)) = &downstream {
8165 client
8166 .send(proto::UpdateDiagnosticSummary {
8167 project_id: *project_id,
8168 worktree_id: worktree_id.to_proto(),
8169 summary: Some(proto::DiagnosticSummary {
8170 path: path.as_ref().to_proto(),
8171 language_server_id: server_id.0 as u64,
8172 error_count: 0,
8173 warning_count: 0,
8174 }),
8175 more_summaries: Vec::new(),
8176 })
8177 .ok();
8178 }
8179 }
8180 cleared_paths.push(ProjectPath {
8181 worktree_id,
8182 path: path.clone(),
8183 });
8184 }
8185 }
8186
8187 if !cleared_paths.is_empty() {
8188 for server_id in cleared_server_ids {
8189 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8190 server_id,
8191 paths: cleared_paths.clone(),
8192 });
8193 }
8194 }
8195 }
8196
8197 pub fn shared(
8198 &mut self,
8199 project_id: u64,
8200 downstream_client: AnyProtoClient,
8201 _: &mut Context<Self>,
8202 ) {
8203 self.downstream_client = Some((downstream_client.clone(), project_id));
8204
8205 for (server_id, status) in &self.language_server_statuses {
8206 if let Some(server) = self.language_server_for_id(*server_id) {
8207 downstream_client
8208 .send(proto::StartLanguageServer {
8209 project_id,
8210 server: Some(proto::LanguageServer {
8211 id: server_id.to_proto(),
8212 name: status.name.to_string(),
8213 worktree_id: status.worktree.map(|id| id.to_proto()),
8214 }),
8215 capabilities: serde_json::to_string(&server.capabilities())
8216 .expect("serializing server LSP capabilities"),
8217 })
8218 .log_err();
8219 }
8220 }
8221 }
8222
8223 pub fn disconnected_from_host(&mut self) {
8224 self.downstream_client.take();
8225 }
8226
8227 pub fn disconnected_from_ssh_remote(&mut self) {
8228 if let LspStoreMode::Remote(RemoteLspStore {
8229 upstream_client, ..
8230 }) = &mut self.mode
8231 {
8232 upstream_client.take();
8233 }
8234 }
8235
8236 pub(crate) fn set_language_server_statuses_from_proto(
8237 &mut self,
8238 project: WeakEntity<Project>,
8239 language_servers: Vec<proto::LanguageServer>,
8240 server_capabilities: Vec<String>,
8241 cx: &mut Context<Self>,
8242 ) {
8243 let lsp_logs = cx
8244 .try_global::<GlobalLogStore>()
8245 .map(|lsp_store| lsp_store.0.clone());
8246
8247 self.language_server_statuses = language_servers
8248 .into_iter()
8249 .zip(server_capabilities)
8250 .map(|(server, server_capabilities)| {
8251 let server_id = LanguageServerId(server.id as usize);
8252 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8253 self.lsp_server_capabilities
8254 .insert(server_id, server_capabilities);
8255 }
8256
8257 let name = LanguageServerName::from_proto(server.name);
8258 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8259
8260 if let Some(lsp_logs) = &lsp_logs {
8261 lsp_logs.update(cx, |lsp_logs, cx| {
8262 lsp_logs.add_language_server(
8263 // Only remote clients get their language servers set from proto
8264 LanguageServerKind::Remote {
8265 project: project.clone(),
8266 },
8267 server_id,
8268 Some(name.clone()),
8269 worktree,
8270 None,
8271 cx,
8272 );
8273 });
8274 }
8275
8276 (
8277 server_id,
8278 LanguageServerStatus {
8279 name,
8280 server_version: None,
8281 server_readable_version: None,
8282 pending_work: Default::default(),
8283 has_pending_diagnostic_updates: false,
8284 progress_tokens: Default::default(),
8285 worktree,
8286 binary: None,
8287 configuration: None,
8288 workspace_folders: BTreeSet::new(),
8289 process_id: None,
8290 },
8291 )
8292 })
8293 .collect();
8294 }
8295
8296 #[cfg(feature = "test-support")]
8297 pub fn update_diagnostic_entries(
8298 &mut self,
8299 server_id: LanguageServerId,
8300 abs_path: PathBuf,
8301 result_id: Option<SharedString>,
8302 version: Option<i32>,
8303 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8304 cx: &mut Context<Self>,
8305 ) -> anyhow::Result<()> {
8306 self.merge_diagnostic_entries(
8307 vec![DocumentDiagnosticsUpdate {
8308 diagnostics: DocumentDiagnostics {
8309 diagnostics,
8310 document_abs_path: abs_path,
8311 version,
8312 },
8313 result_id,
8314 server_id,
8315 disk_based_sources: Cow::Borrowed(&[]),
8316 registration_id: None,
8317 }],
8318 |_, _, _| false,
8319 cx,
8320 )?;
8321 Ok(())
8322 }
8323
8324 pub fn merge_diagnostic_entries<'a>(
8325 &mut self,
8326 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8327 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8328 cx: &mut Context<Self>,
8329 ) -> anyhow::Result<()> {
8330 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8331 let mut updated_diagnostics_paths = HashMap::default();
8332 for mut update in diagnostic_updates {
8333 let abs_path = &update.diagnostics.document_abs_path;
8334 let server_id = update.server_id;
8335 let Some((worktree, relative_path)) =
8336 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8337 else {
8338 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8339 return Ok(());
8340 };
8341
8342 let worktree_id = worktree.read(cx).id();
8343 let project_path = ProjectPath {
8344 worktree_id,
8345 path: relative_path,
8346 };
8347
8348 let document_uri = lsp::Uri::from_file_path(abs_path)
8349 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8350 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8351 let snapshot = buffer_handle.read(cx).snapshot();
8352 let buffer = buffer_handle.read(cx);
8353 let reused_diagnostics = buffer
8354 .buffer_diagnostics(Some(server_id))
8355 .iter()
8356 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8357 .map(|v| {
8358 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8359 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8360 DiagnosticEntry {
8361 range: start..end,
8362 diagnostic: v.diagnostic.clone(),
8363 }
8364 })
8365 .collect::<Vec<_>>();
8366
8367 self.as_local_mut()
8368 .context("cannot merge diagnostics on a remote LspStore")?
8369 .update_buffer_diagnostics(
8370 &buffer_handle,
8371 server_id,
8372 Some(update.registration_id),
8373 update.result_id,
8374 update.diagnostics.version,
8375 update.diagnostics.diagnostics.clone(),
8376 reused_diagnostics.clone(),
8377 cx,
8378 )?;
8379
8380 update.diagnostics.diagnostics.extend(reused_diagnostics);
8381 } else if let Some(local) = self.as_local() {
8382 let reused_diagnostics = local
8383 .diagnostics
8384 .get(&worktree_id)
8385 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8386 .and_then(|diagnostics_by_server_id| {
8387 diagnostics_by_server_id
8388 .binary_search_by_key(&server_id, |e| e.0)
8389 .ok()
8390 .map(|ix| &diagnostics_by_server_id[ix].1)
8391 })
8392 .into_iter()
8393 .flatten()
8394 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8395
8396 update
8397 .diagnostics
8398 .diagnostics
8399 .extend(reused_diagnostics.cloned());
8400 }
8401
8402 let updated = worktree.update(cx, |worktree, cx| {
8403 self.update_worktree_diagnostics(
8404 worktree.id(),
8405 server_id,
8406 project_path.path.clone(),
8407 update.diagnostics.diagnostics,
8408 cx,
8409 )
8410 })?;
8411 match updated {
8412 ControlFlow::Continue(new_summary) => {
8413 if let Some((project_id, new_summary)) = new_summary {
8414 match &mut diagnostics_summary {
8415 Some(diagnostics_summary) => {
8416 diagnostics_summary
8417 .more_summaries
8418 .push(proto::DiagnosticSummary {
8419 path: project_path.path.as_ref().to_proto(),
8420 language_server_id: server_id.0 as u64,
8421 error_count: new_summary.error_count,
8422 warning_count: new_summary.warning_count,
8423 })
8424 }
8425 None => {
8426 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8427 project_id,
8428 worktree_id: worktree_id.to_proto(),
8429 summary: Some(proto::DiagnosticSummary {
8430 path: project_path.path.as_ref().to_proto(),
8431 language_server_id: server_id.0 as u64,
8432 error_count: new_summary.error_count,
8433 warning_count: new_summary.warning_count,
8434 }),
8435 more_summaries: Vec::new(),
8436 })
8437 }
8438 }
8439 }
8440 updated_diagnostics_paths
8441 .entry(server_id)
8442 .or_insert_with(Vec::new)
8443 .push(project_path);
8444 }
8445 ControlFlow::Break(()) => {}
8446 }
8447 }
8448
8449 if let Some((diagnostics_summary, (downstream_client, _))) =
8450 diagnostics_summary.zip(self.downstream_client.as_ref())
8451 {
8452 downstream_client.send(diagnostics_summary).log_err();
8453 }
8454 for (server_id, paths) in updated_diagnostics_paths {
8455 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8456 }
8457 Ok(())
8458 }
8459
8460 fn update_worktree_diagnostics(
8461 &mut self,
8462 worktree_id: WorktreeId,
8463 server_id: LanguageServerId,
8464 path_in_worktree: Arc<RelPath>,
8465 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8466 _: &mut Context<Worktree>,
8467 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8468 let local = match &mut self.mode {
8469 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8470 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8471 };
8472
8473 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8474 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8475 let summaries_by_server_id = summaries_for_tree
8476 .entry(path_in_worktree.clone())
8477 .or_default();
8478
8479 let old_summary = summaries_by_server_id
8480 .remove(&server_id)
8481 .unwrap_or_default();
8482
8483 let new_summary = DiagnosticSummary::new(&diagnostics);
8484 if diagnostics.is_empty() {
8485 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8486 {
8487 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8488 diagnostics_by_server_id.remove(ix);
8489 }
8490 if diagnostics_by_server_id.is_empty() {
8491 diagnostics_for_tree.remove(&path_in_worktree);
8492 }
8493 }
8494 } else {
8495 summaries_by_server_id.insert(server_id, new_summary);
8496 let diagnostics_by_server_id = diagnostics_for_tree
8497 .entry(path_in_worktree.clone())
8498 .or_default();
8499 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8500 Ok(ix) => {
8501 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8502 }
8503 Err(ix) => {
8504 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8505 }
8506 }
8507 }
8508
8509 if !old_summary.is_empty() || !new_summary.is_empty() {
8510 if let Some((_, project_id)) = &self.downstream_client {
8511 Ok(ControlFlow::Continue(Some((
8512 *project_id,
8513 proto::DiagnosticSummary {
8514 path: path_in_worktree.to_proto(),
8515 language_server_id: server_id.0 as u64,
8516 error_count: new_summary.error_count as u32,
8517 warning_count: new_summary.warning_count as u32,
8518 },
8519 ))))
8520 } else {
8521 Ok(ControlFlow::Continue(None))
8522 }
8523 } else {
8524 Ok(ControlFlow::Break(()))
8525 }
8526 }
8527
8528 pub fn open_buffer_for_symbol(
8529 &mut self,
8530 symbol: &Symbol,
8531 cx: &mut Context<Self>,
8532 ) -> Task<Result<Entity<Buffer>>> {
8533 if let Some((client, project_id)) = self.upstream_client() {
8534 let request = client.request(proto::OpenBufferForSymbol {
8535 project_id,
8536 symbol: Some(Self::serialize_symbol(symbol)),
8537 });
8538 cx.spawn(async move |this, cx| {
8539 let response = request.await?;
8540 let buffer_id = BufferId::new(response.buffer_id)?;
8541 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8542 .await
8543 })
8544 } else if let Some(local) = self.as_local() {
8545 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8546 seed.worktree_id == symbol.source_worktree_id
8547 && state.id == symbol.source_language_server_id
8548 && symbol.language_server_name == seed.name
8549 });
8550 if !is_valid {
8551 return Task::ready(Err(anyhow!(
8552 "language server for worktree and language not found"
8553 )));
8554 };
8555
8556 let symbol_abs_path = match &symbol.path {
8557 SymbolLocation::InProject(project_path) => self
8558 .worktree_store
8559 .read(cx)
8560 .absolutize(&project_path, cx)
8561 .context("no such worktree"),
8562 SymbolLocation::OutsideProject {
8563 abs_path,
8564 signature: _,
8565 } => Ok(abs_path.to_path_buf()),
8566 };
8567 let symbol_abs_path = match symbol_abs_path {
8568 Ok(abs_path) => abs_path,
8569 Err(err) => return Task::ready(Err(err)),
8570 };
8571 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8572 uri
8573 } else {
8574 return Task::ready(Err(anyhow!("invalid symbol path")));
8575 };
8576
8577 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8578 } else {
8579 Task::ready(Err(anyhow!("no upstream client or local store")))
8580 }
8581 }
8582
8583 pub(crate) fn open_local_buffer_via_lsp(
8584 &mut self,
8585 abs_path: lsp::Uri,
8586 language_server_id: LanguageServerId,
8587 cx: &mut Context<Self>,
8588 ) -> Task<Result<Entity<Buffer>>> {
8589 let path_style = self.worktree_store.read(cx).path_style();
8590 cx.spawn(async move |lsp_store, cx| {
8591 // Escape percent-encoded string.
8592 let current_scheme = abs_path.scheme().to_owned();
8593 // Uri is immutable, so we can't modify the scheme
8594
8595 let abs_path = abs_path
8596 .to_file_path_ext(path_style)
8597 .map_err(|()| anyhow!("can't convert URI to path"))?;
8598 let p = abs_path.clone();
8599 let yarn_worktree = lsp_store
8600 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8601 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8602 cx.spawn(async move |this, cx| {
8603 let t = this
8604 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8605 .ok()?;
8606 t.await
8607 })
8608 }),
8609 None => Task::ready(None),
8610 })?
8611 .await;
8612 let (worktree_root_target, known_relative_path) =
8613 if let Some((zip_root, relative_path)) = yarn_worktree {
8614 (zip_root, Some(relative_path))
8615 } else {
8616 (Arc::<Path>::from(abs_path.as_path()), None)
8617 };
8618 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8619 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8620 worktree_store.find_worktree(&worktree_root_target, cx)
8621 })
8622 })?;
8623 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8624 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8625 (result.0, relative_path, None)
8626 } else {
8627 let worktree = lsp_store
8628 .update(cx, |lsp_store, cx| {
8629 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8630 worktree_store.create_worktree(&worktree_root_target, false, cx)
8631 })
8632 })?
8633 .await?;
8634 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8635 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8636 lsp_store
8637 .update(cx, |lsp_store, cx| {
8638 if let Some(local) = lsp_store.as_local_mut() {
8639 local.register_language_server_for_invisible_worktree(
8640 &worktree,
8641 language_server_id,
8642 cx,
8643 )
8644 }
8645 match lsp_store.language_server_statuses.get(&language_server_id) {
8646 Some(status) => status.worktree,
8647 None => None,
8648 }
8649 })
8650 .ok()
8651 .flatten()
8652 .zip(Some(worktree_root.clone()))
8653 } else {
8654 None
8655 };
8656 let relative_path = if let Some(known_path) = known_relative_path {
8657 known_path
8658 } else {
8659 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8660 .into_arc()
8661 };
8662 (worktree, relative_path, source_ws)
8663 };
8664 let project_path = ProjectPath {
8665 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8666 path: relative_path,
8667 };
8668 let buffer = lsp_store
8669 .update(cx, |lsp_store, cx| {
8670 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8671 buffer_store.open_buffer(project_path, cx)
8672 })
8673 })?
8674 .await?;
8675 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8676 if let Some((source_ws, worktree_root)) = source_ws {
8677 buffer.update(cx, |buffer, cx| {
8678 let settings = WorktreeSettings::get(
8679 Some(
8680 (&ProjectPath {
8681 worktree_id: source_ws,
8682 path: Arc::from(RelPath::empty()),
8683 })
8684 .into(),
8685 ),
8686 cx,
8687 );
8688 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8689 if is_read_only {
8690 buffer.set_capability(Capability::ReadOnly, cx);
8691 }
8692 });
8693 }
8694 Ok(buffer)
8695 })
8696 }
8697
8698 fn local_lsp_servers_for_buffer(
8699 &self,
8700 buffer: &Entity<Buffer>,
8701 cx: &mut Context<Self>,
8702 ) -> Vec<LanguageServerId> {
8703 let Some(local) = self.as_local() else {
8704 return Vec::new();
8705 };
8706
8707 let snapshot = buffer.read(cx).snapshot();
8708
8709 buffer.update(cx, |buffer, cx| {
8710 local
8711 .language_servers_for_buffer(buffer, cx)
8712 .map(|(_, server)| server.server_id())
8713 .filter(|server_id| {
8714 self.as_local().is_none_or(|local| {
8715 local
8716 .buffers_opened_in_servers
8717 .get(&snapshot.remote_id())
8718 .is_some_and(|servers| servers.contains(server_id))
8719 })
8720 })
8721 .collect()
8722 })
8723 }
8724
8725 fn request_multiple_lsp_locally<P, R>(
8726 &mut self,
8727 buffer: &Entity<Buffer>,
8728 position: Option<P>,
8729 request: R,
8730 cx: &mut Context<Self>,
8731 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8732 where
8733 P: ToOffset,
8734 R: LspCommand + Clone,
8735 <R::LspRequest as lsp::request::Request>::Result: Send,
8736 <R::LspRequest as lsp::request::Request>::Params: Send,
8737 {
8738 let Some(local) = self.as_local() else {
8739 return Task::ready(Vec::new());
8740 };
8741
8742 let snapshot = buffer.read(cx).snapshot();
8743 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8744
8745 let server_ids = buffer.update(cx, |buffer, cx| {
8746 local
8747 .language_servers_for_buffer(buffer, cx)
8748 .filter(|(adapter, _)| {
8749 scope
8750 .as_ref()
8751 .map(|scope| scope.language_allowed(&adapter.name))
8752 .unwrap_or(true)
8753 })
8754 .map(|(_, server)| server.server_id())
8755 .filter(|server_id| {
8756 self.as_local().is_none_or(|local| {
8757 local
8758 .buffers_opened_in_servers
8759 .get(&snapshot.remote_id())
8760 .is_some_and(|servers| servers.contains(server_id))
8761 })
8762 })
8763 .collect::<Vec<_>>()
8764 });
8765
8766 let mut response_results = server_ids
8767 .into_iter()
8768 .map(|server_id| {
8769 let task = self.request_lsp(
8770 buffer.clone(),
8771 LanguageServerToQuery::Other(server_id),
8772 request.clone(),
8773 cx,
8774 );
8775 async move { (server_id, task.await) }
8776 })
8777 .collect::<FuturesUnordered<_>>();
8778
8779 cx.background_spawn(async move {
8780 let mut responses = Vec::with_capacity(response_results.len());
8781 while let Some((server_id, response_result)) = response_results.next().await {
8782 match response_result {
8783 Ok(response) => responses.push((server_id, response)),
8784 // rust-analyzer likes to error with this when its still loading up
8785 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8786 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8787 }
8788 }
8789 responses
8790 })
8791 }
8792
8793 async fn handle_lsp_get_completions(
8794 this: Entity<Self>,
8795 envelope: TypedEnvelope<proto::GetCompletions>,
8796 mut cx: AsyncApp,
8797 ) -> Result<proto::GetCompletionsResponse> {
8798 let sender_id = envelope.original_sender_id().unwrap_or_default();
8799
8800 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8801 let buffer_handle = this.update(&mut cx, |this, cx| {
8802 this.buffer_store.read(cx).get_existing(buffer_id)
8803 })?;
8804 let request = GetCompletions::from_proto(
8805 envelope.payload,
8806 this.clone(),
8807 buffer_handle.clone(),
8808 cx.clone(),
8809 )
8810 .await?;
8811
8812 let server_to_query = match request.server_id {
8813 Some(server_id) => LanguageServerToQuery::Other(server_id),
8814 None => LanguageServerToQuery::FirstCapable,
8815 };
8816
8817 let response = this
8818 .update(&mut cx, |this, cx| {
8819 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8820 })
8821 .await?;
8822 this.update(&mut cx, |this, cx| {
8823 Ok(GetCompletions::response_to_proto(
8824 response,
8825 this,
8826 sender_id,
8827 &buffer_handle.read(cx).version(),
8828 cx,
8829 ))
8830 })
8831 }
8832
8833 async fn handle_lsp_command<T: LspCommand>(
8834 this: Entity<Self>,
8835 envelope: TypedEnvelope<T::ProtoRequest>,
8836 mut cx: AsyncApp,
8837 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8838 where
8839 <T::LspRequest as lsp::request::Request>::Params: Send,
8840 <T::LspRequest as lsp::request::Request>::Result: Send,
8841 {
8842 let sender_id = envelope.original_sender_id().unwrap_or_default();
8843 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8844 let buffer_handle = this.update(&mut cx, |this, cx| {
8845 this.buffer_store.read(cx).get_existing(buffer_id)
8846 })?;
8847 let request = T::from_proto(
8848 envelope.payload,
8849 this.clone(),
8850 buffer_handle.clone(),
8851 cx.clone(),
8852 )
8853 .await?;
8854 let response = this
8855 .update(&mut cx, |this, cx| {
8856 this.request_lsp(
8857 buffer_handle.clone(),
8858 LanguageServerToQuery::FirstCapable,
8859 request,
8860 cx,
8861 )
8862 })
8863 .await?;
8864 this.update(&mut cx, |this, cx| {
8865 Ok(T::response_to_proto(
8866 response,
8867 this,
8868 sender_id,
8869 &buffer_handle.read(cx).version(),
8870 cx,
8871 ))
8872 })
8873 }
8874
8875 async fn handle_lsp_query(
8876 lsp_store: Entity<Self>,
8877 envelope: TypedEnvelope<proto::LspQuery>,
8878 mut cx: AsyncApp,
8879 ) -> Result<proto::Ack> {
8880 use proto::lsp_query::Request;
8881 let sender_id = envelope.original_sender_id().unwrap_or_default();
8882 let lsp_query = envelope.payload;
8883 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8884 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8885 match lsp_query.request.context("invalid LSP query request")? {
8886 Request::GetReferences(get_references) => {
8887 let position = get_references.position.clone().and_then(deserialize_anchor);
8888 Self::query_lsp_locally::<GetReferences>(
8889 lsp_store,
8890 server_id,
8891 sender_id,
8892 lsp_request_id,
8893 get_references,
8894 position,
8895 &mut cx,
8896 )
8897 .await?;
8898 }
8899 Request::GetDocumentColor(get_document_color) => {
8900 Self::query_lsp_locally::<GetDocumentColor>(
8901 lsp_store,
8902 server_id,
8903 sender_id,
8904 lsp_request_id,
8905 get_document_color,
8906 None,
8907 &mut cx,
8908 )
8909 .await?;
8910 }
8911 Request::GetFoldingRanges(get_folding_ranges) => {
8912 Self::query_lsp_locally::<GetFoldingRanges>(
8913 lsp_store,
8914 server_id,
8915 sender_id,
8916 lsp_request_id,
8917 get_folding_ranges,
8918 None,
8919 &mut cx,
8920 )
8921 .await?;
8922 }
8923 Request::GetDocumentSymbols(get_document_symbols) => {
8924 Self::query_lsp_locally::<GetDocumentSymbols>(
8925 lsp_store,
8926 server_id,
8927 sender_id,
8928 lsp_request_id,
8929 get_document_symbols,
8930 None,
8931 &mut cx,
8932 )
8933 .await?;
8934 }
8935 Request::GetHover(get_hover) => {
8936 let position = get_hover.position.clone().and_then(deserialize_anchor);
8937 Self::query_lsp_locally::<GetHover>(
8938 lsp_store,
8939 server_id,
8940 sender_id,
8941 lsp_request_id,
8942 get_hover,
8943 position,
8944 &mut cx,
8945 )
8946 .await?;
8947 }
8948 Request::GetCodeActions(get_code_actions) => {
8949 Self::query_lsp_locally::<GetCodeActions>(
8950 lsp_store,
8951 server_id,
8952 sender_id,
8953 lsp_request_id,
8954 get_code_actions,
8955 None,
8956 &mut cx,
8957 )
8958 .await?;
8959 }
8960 Request::GetSignatureHelp(get_signature_help) => {
8961 let position = get_signature_help
8962 .position
8963 .clone()
8964 .and_then(deserialize_anchor);
8965 Self::query_lsp_locally::<GetSignatureHelp>(
8966 lsp_store,
8967 server_id,
8968 sender_id,
8969 lsp_request_id,
8970 get_signature_help,
8971 position,
8972 &mut cx,
8973 )
8974 .await?;
8975 }
8976 Request::GetCodeLens(get_code_lens) => {
8977 Self::query_lsp_locally::<GetCodeLens>(
8978 lsp_store,
8979 server_id,
8980 sender_id,
8981 lsp_request_id,
8982 get_code_lens,
8983 None,
8984 &mut cx,
8985 )
8986 .await?;
8987 }
8988 Request::GetDefinition(get_definition) => {
8989 let position = get_definition.position.clone().and_then(deserialize_anchor);
8990 Self::query_lsp_locally::<GetDefinitions>(
8991 lsp_store,
8992 server_id,
8993 sender_id,
8994 lsp_request_id,
8995 get_definition,
8996 position,
8997 &mut cx,
8998 )
8999 .await?;
9000 }
9001 Request::GetDeclaration(get_declaration) => {
9002 let position = get_declaration
9003 .position
9004 .clone()
9005 .and_then(deserialize_anchor);
9006 Self::query_lsp_locally::<GetDeclarations>(
9007 lsp_store,
9008 server_id,
9009 sender_id,
9010 lsp_request_id,
9011 get_declaration,
9012 position,
9013 &mut cx,
9014 )
9015 .await?;
9016 }
9017 Request::GetTypeDefinition(get_type_definition) => {
9018 let position = get_type_definition
9019 .position
9020 .clone()
9021 .and_then(deserialize_anchor);
9022 Self::query_lsp_locally::<GetTypeDefinitions>(
9023 lsp_store,
9024 server_id,
9025 sender_id,
9026 lsp_request_id,
9027 get_type_definition,
9028 position,
9029 &mut cx,
9030 )
9031 .await?;
9032 }
9033 Request::GetImplementation(get_implementation) => {
9034 let position = get_implementation
9035 .position
9036 .clone()
9037 .and_then(deserialize_anchor);
9038 Self::query_lsp_locally::<GetImplementations>(
9039 lsp_store,
9040 server_id,
9041 sender_id,
9042 lsp_request_id,
9043 get_implementation,
9044 position,
9045 &mut cx,
9046 )
9047 .await?;
9048 }
9049 Request::InlayHints(inlay_hints) => {
9050 let query_start = inlay_hints
9051 .start
9052 .clone()
9053 .and_then(deserialize_anchor)
9054 .context("invalid inlay hints range start")?;
9055 let query_end = inlay_hints
9056 .end
9057 .clone()
9058 .and_then(deserialize_anchor)
9059 .context("invalid inlay hints range end")?;
9060 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9061 &lsp_store,
9062 server_id,
9063 lsp_request_id,
9064 &inlay_hints,
9065 query_start..query_end,
9066 &mut cx,
9067 )
9068 .await
9069 .context("preparing inlay hints request")?;
9070 Self::query_lsp_locally::<InlayHints>(
9071 lsp_store,
9072 server_id,
9073 sender_id,
9074 lsp_request_id,
9075 inlay_hints,
9076 None,
9077 &mut cx,
9078 )
9079 .await
9080 .context("querying for inlay hints")?
9081 }
9082 //////////////////////////////
9083 // Below are LSP queries that need to fetch more data,
9084 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9085 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9086 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9087 &lsp_store,
9088 &get_document_diagnostics,
9089 &mut cx,
9090 )
9091 .await?;
9092 lsp_store.update(&mut cx, |lsp_store, cx| {
9093 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9094 let key = LspKey {
9095 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9096 server_queried: server_id,
9097 };
9098 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9099 ) {
9100 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9101 lsp_requests.clear();
9102 };
9103 }
9104
9105 lsp_data.lsp_requests.entry(key).or_default().insert(
9106 lsp_request_id,
9107 cx.spawn(async move |lsp_store, cx| {
9108 let diagnostics_pull = lsp_store
9109 .update(cx, |lsp_store, cx| {
9110 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9111 })
9112 .ok();
9113 if let Some(diagnostics_pull) = diagnostics_pull {
9114 match diagnostics_pull.await {
9115 Ok(()) => {}
9116 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9117 };
9118 }
9119 }),
9120 );
9121 });
9122 }
9123 Request::SemanticTokens(semantic_tokens) => {
9124 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9125 &lsp_store,
9126 &semantic_tokens,
9127 &mut cx,
9128 )
9129 .await?;
9130 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9131 lsp_store.update(&mut cx, |lsp_store, cx| {
9132 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9133 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9134 let key = LspKey {
9135 request_type: TypeId::of::<SemanticTokensFull>(),
9136 server_queried: server_id,
9137 };
9138 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9139 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9140 lsp_requests.clear();
9141 };
9142 }
9143
9144 lsp_data.lsp_requests.entry(key).or_default().insert(
9145 lsp_request_id,
9146 cx.spawn(async move |lsp_store, cx| {
9147 let tokens_fetch = lsp_store
9148 .update(cx, |lsp_store, cx| {
9149 lsp_store
9150 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9151 })
9152 .ok();
9153 if let Some(tokens_fetch) = tokens_fetch {
9154 let new_tokens = tokens_fetch.await;
9155 if let Some(new_tokens) = new_tokens {
9156 lsp_store
9157 .update(cx, |lsp_store, cx| {
9158 let response = new_tokens
9159 .into_iter()
9160 .map(|(server_id, response)| {
9161 (
9162 server_id.to_proto(),
9163 SemanticTokensFull::response_to_proto(
9164 response,
9165 lsp_store,
9166 sender_id,
9167 &buffer_version,
9168 cx,
9169 ),
9170 )
9171 })
9172 .collect::<HashMap<_, _>>();
9173 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9174 project_id,
9175 lsp_request_id,
9176 response,
9177 ) {
9178 Ok(()) => {}
9179 Err(e) => {
9180 log::error!(
9181 "Failed to send semantic tokens LSP response: {e:#}",
9182 )
9183 }
9184 }
9185 })
9186 .ok();
9187 }
9188 }
9189 }),
9190 );
9191 }
9192 });
9193 }
9194 }
9195 Ok(proto::Ack {})
9196 }
9197
9198 async fn handle_lsp_query_response(
9199 lsp_store: Entity<Self>,
9200 envelope: TypedEnvelope<proto::LspQueryResponse>,
9201 cx: AsyncApp,
9202 ) -> Result<()> {
9203 lsp_store.read_with(&cx, |lsp_store, _| {
9204 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9205 upstream_client.handle_lsp_response(envelope.clone());
9206 }
9207 });
9208 Ok(())
9209 }
9210
9211 async fn handle_apply_code_action(
9212 this: Entity<Self>,
9213 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9214 mut cx: AsyncApp,
9215 ) -> Result<proto::ApplyCodeActionResponse> {
9216 let sender_id = envelope.original_sender_id().unwrap_or_default();
9217 let action =
9218 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9219 let apply_code_action = this.update(&mut cx, |this, cx| {
9220 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9221 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9222 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9223 })?;
9224
9225 let project_transaction = apply_code_action.await?;
9226 let project_transaction = this.update(&mut cx, |this, cx| {
9227 this.buffer_store.update(cx, |buffer_store, cx| {
9228 buffer_store.serialize_project_transaction_for_peer(
9229 project_transaction,
9230 sender_id,
9231 cx,
9232 )
9233 })
9234 });
9235 Ok(proto::ApplyCodeActionResponse {
9236 transaction: Some(project_transaction),
9237 })
9238 }
9239
9240 async fn handle_register_buffer_with_language_servers(
9241 this: Entity<Self>,
9242 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9243 mut cx: AsyncApp,
9244 ) -> Result<proto::Ack> {
9245 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9246 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9247 this.update(&mut cx, |this, cx| {
9248 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9249 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9250 project_id: upstream_project_id,
9251 buffer_id: buffer_id.to_proto(),
9252 only_servers: envelope.payload.only_servers,
9253 });
9254 }
9255
9256 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9257 anyhow::bail!("buffer is not open");
9258 };
9259
9260 let handle = this.register_buffer_with_language_servers(
9261 &buffer,
9262 envelope
9263 .payload
9264 .only_servers
9265 .into_iter()
9266 .filter_map(|selector| {
9267 Some(match selector.selector? {
9268 proto::language_server_selector::Selector::ServerId(server_id) => {
9269 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9270 }
9271 proto::language_server_selector::Selector::Name(name) => {
9272 LanguageServerSelector::Name(LanguageServerName(
9273 SharedString::from(name),
9274 ))
9275 }
9276 })
9277 })
9278 .collect(),
9279 false,
9280 cx,
9281 );
9282 // Pull diagnostics for the buffer even if it was already registered.
9283 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9284 // but it's unclear if we need it.
9285 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9286 .detach();
9287 this.buffer_store().update(cx, |buffer_store, _| {
9288 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9289 });
9290
9291 Ok(())
9292 })?;
9293 Ok(proto::Ack {})
9294 }
9295
9296 async fn handle_rename_project_entry(
9297 this: Entity<Self>,
9298 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9299 mut cx: AsyncApp,
9300 ) -> Result<proto::ProjectEntryResponse> {
9301 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9302 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9303 let new_path =
9304 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9305
9306 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9307 .update(&mut cx, |this, cx| {
9308 let (worktree, entry) = this
9309 .worktree_store
9310 .read(cx)
9311 .worktree_and_entry_for_id(entry_id, cx)?;
9312 let new_worktree = this
9313 .worktree_store
9314 .read(cx)
9315 .worktree_for_id(new_worktree_id, cx)?;
9316 Some((
9317 this.worktree_store.clone(),
9318 worktree,
9319 new_worktree,
9320 entry.clone(),
9321 ))
9322 })
9323 .context("worktree not found")?;
9324 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9325 (worktree.absolutize(&old_entry.path), worktree.id())
9326 });
9327 let new_abs_path =
9328 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9329
9330 let _transaction = Self::will_rename_entry(
9331 this.downgrade(),
9332 old_worktree_id,
9333 &old_abs_path,
9334 &new_abs_path,
9335 old_entry.is_dir(),
9336 cx.clone(),
9337 )
9338 .await;
9339 let response = WorktreeStore::handle_rename_project_entry(
9340 worktree_store,
9341 envelope.payload,
9342 cx.clone(),
9343 )
9344 .await;
9345 this.read_with(&cx, |this, _| {
9346 this.did_rename_entry(
9347 old_worktree_id,
9348 &old_abs_path,
9349 &new_abs_path,
9350 old_entry.is_dir(),
9351 );
9352 });
9353 response
9354 }
9355
9356 async fn handle_update_diagnostic_summary(
9357 this: Entity<Self>,
9358 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9359 mut cx: AsyncApp,
9360 ) -> Result<()> {
9361 this.update(&mut cx, |lsp_store, cx| {
9362 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9363 let mut updated_diagnostics_paths = HashMap::default();
9364 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9365 for message_summary in envelope
9366 .payload
9367 .summary
9368 .into_iter()
9369 .chain(envelope.payload.more_summaries)
9370 {
9371 let project_path = ProjectPath {
9372 worktree_id,
9373 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9374 };
9375 let path = project_path.path.clone();
9376 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9377 let summary = DiagnosticSummary {
9378 error_count: message_summary.error_count as usize,
9379 warning_count: message_summary.warning_count as usize,
9380 };
9381
9382 if summary.is_empty() {
9383 if let Some(worktree_summaries) =
9384 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9385 && let Some(summaries) = worktree_summaries.get_mut(&path)
9386 {
9387 summaries.remove(&server_id);
9388 if summaries.is_empty() {
9389 worktree_summaries.remove(&path);
9390 }
9391 }
9392 } else {
9393 lsp_store
9394 .diagnostic_summaries
9395 .entry(worktree_id)
9396 .or_default()
9397 .entry(path)
9398 .or_default()
9399 .insert(server_id, summary);
9400 }
9401
9402 if let Some((_, project_id)) = &lsp_store.downstream_client {
9403 match &mut diagnostics_summary {
9404 Some(diagnostics_summary) => {
9405 diagnostics_summary
9406 .more_summaries
9407 .push(proto::DiagnosticSummary {
9408 path: project_path.path.as_ref().to_proto(),
9409 language_server_id: server_id.0 as u64,
9410 error_count: summary.error_count as u32,
9411 warning_count: summary.warning_count as u32,
9412 })
9413 }
9414 None => {
9415 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9416 project_id: *project_id,
9417 worktree_id: worktree_id.to_proto(),
9418 summary: Some(proto::DiagnosticSummary {
9419 path: project_path.path.as_ref().to_proto(),
9420 language_server_id: server_id.0 as u64,
9421 error_count: summary.error_count as u32,
9422 warning_count: summary.warning_count as u32,
9423 }),
9424 more_summaries: Vec::new(),
9425 })
9426 }
9427 }
9428 }
9429 updated_diagnostics_paths
9430 .entry(server_id)
9431 .or_insert_with(Vec::new)
9432 .push(project_path);
9433 }
9434
9435 if let Some((diagnostics_summary, (downstream_client, _))) =
9436 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9437 {
9438 downstream_client.send(diagnostics_summary).log_err();
9439 }
9440 for (server_id, paths) in updated_diagnostics_paths {
9441 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9442 }
9443 Ok(())
9444 })
9445 }
9446
9447 async fn handle_start_language_server(
9448 lsp_store: Entity<Self>,
9449 envelope: TypedEnvelope<proto::StartLanguageServer>,
9450 mut cx: AsyncApp,
9451 ) -> Result<()> {
9452 let server = envelope.payload.server.context("invalid server")?;
9453 let server_capabilities =
9454 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9455 .with_context(|| {
9456 format!(
9457 "incorrect server capabilities {}",
9458 envelope.payload.capabilities
9459 )
9460 })?;
9461 lsp_store.update(&mut cx, |lsp_store, cx| {
9462 let server_id = LanguageServerId(server.id as usize);
9463 let server_name = LanguageServerName::from_proto(server.name.clone());
9464 lsp_store
9465 .lsp_server_capabilities
9466 .insert(server_id, server_capabilities);
9467 lsp_store.language_server_statuses.insert(
9468 server_id,
9469 LanguageServerStatus {
9470 name: server_name.clone(),
9471 server_version: None,
9472 server_readable_version: None,
9473 pending_work: Default::default(),
9474 has_pending_diagnostic_updates: false,
9475 progress_tokens: Default::default(),
9476 worktree: server.worktree_id.map(WorktreeId::from_proto),
9477 binary: None,
9478 configuration: None,
9479 workspace_folders: BTreeSet::new(),
9480 process_id: None,
9481 },
9482 );
9483 cx.emit(LspStoreEvent::LanguageServerAdded(
9484 server_id,
9485 server_name,
9486 server.worktree_id.map(WorktreeId::from_proto),
9487 ));
9488 cx.notify();
9489 });
9490 Ok(())
9491 }
9492
9493 async fn handle_update_language_server(
9494 lsp_store: Entity<Self>,
9495 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9496 mut cx: AsyncApp,
9497 ) -> Result<()> {
9498 lsp_store.update(&mut cx, |lsp_store, cx| {
9499 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9500
9501 match envelope.payload.variant.context("invalid variant")? {
9502 proto::update_language_server::Variant::WorkStart(payload) => {
9503 lsp_store.on_lsp_work_start(
9504 language_server_id,
9505 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9506 .context("invalid progress token value")?,
9507 LanguageServerProgress {
9508 title: payload.title,
9509 is_disk_based_diagnostics_progress: false,
9510 is_cancellable: payload.is_cancellable.unwrap_or(false),
9511 message: payload.message,
9512 percentage: payload.percentage.map(|p| p as usize),
9513 last_update_at: cx.background_executor().now(),
9514 },
9515 cx,
9516 );
9517 }
9518 proto::update_language_server::Variant::WorkProgress(payload) => {
9519 lsp_store.on_lsp_work_progress(
9520 language_server_id,
9521 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9522 .context("invalid progress token value")?,
9523 LanguageServerProgress {
9524 title: None,
9525 is_disk_based_diagnostics_progress: false,
9526 is_cancellable: payload.is_cancellable.unwrap_or(false),
9527 message: payload.message,
9528 percentage: payload.percentage.map(|p| p as usize),
9529 last_update_at: cx.background_executor().now(),
9530 },
9531 cx,
9532 );
9533 }
9534
9535 proto::update_language_server::Variant::WorkEnd(payload) => {
9536 lsp_store.on_lsp_work_end(
9537 language_server_id,
9538 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9539 .context("invalid progress token value")?,
9540 cx,
9541 );
9542 }
9543
9544 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9545 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9546 }
9547
9548 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9549 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9550 }
9551
9552 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9553 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9554 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9555 cx.emit(LspStoreEvent::LanguageServerUpdate {
9556 language_server_id,
9557 name: envelope
9558 .payload
9559 .server_name
9560 .map(SharedString::new)
9561 .map(LanguageServerName),
9562 message: non_lsp,
9563 });
9564 }
9565 }
9566
9567 Ok(())
9568 })
9569 }
9570
9571 async fn handle_language_server_log(
9572 this: Entity<Self>,
9573 envelope: TypedEnvelope<proto::LanguageServerLog>,
9574 mut cx: AsyncApp,
9575 ) -> Result<()> {
9576 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9577 let log_type = envelope
9578 .payload
9579 .log_type
9580 .map(LanguageServerLogType::from_proto)
9581 .context("invalid language server log type")?;
9582
9583 let message = envelope.payload.message;
9584
9585 this.update(&mut cx, |_, cx| {
9586 cx.emit(LspStoreEvent::LanguageServerLog(
9587 language_server_id,
9588 log_type,
9589 message,
9590 ));
9591 });
9592 Ok(())
9593 }
9594
9595 async fn handle_lsp_ext_cancel_flycheck(
9596 lsp_store: Entity<Self>,
9597 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9598 cx: AsyncApp,
9599 ) -> Result<proto::Ack> {
9600 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9601 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9602 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9603 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9604 } else {
9605 None
9606 }
9607 });
9608 if let Some(task) = task {
9609 task.context("handling lsp ext cancel flycheck")?;
9610 }
9611
9612 Ok(proto::Ack {})
9613 }
9614
9615 async fn handle_lsp_ext_run_flycheck(
9616 lsp_store: Entity<Self>,
9617 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9618 mut cx: AsyncApp,
9619 ) -> Result<proto::Ack> {
9620 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9621 lsp_store.update(&mut cx, |lsp_store, cx| {
9622 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9623 let text_document = if envelope.payload.current_file_only {
9624 let buffer_id = envelope
9625 .payload
9626 .buffer_id
9627 .map(|id| BufferId::new(id))
9628 .transpose()?;
9629 buffer_id
9630 .and_then(|buffer_id| {
9631 lsp_store
9632 .buffer_store()
9633 .read(cx)
9634 .get(buffer_id)
9635 .and_then(|buffer| {
9636 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9637 })
9638 .map(|path| make_text_document_identifier(&path))
9639 })
9640 .transpose()?
9641 } else {
9642 None
9643 };
9644 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9645 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9646 )?;
9647 }
9648 anyhow::Ok(())
9649 })?;
9650
9651 Ok(proto::Ack {})
9652 }
9653
9654 async fn handle_lsp_ext_clear_flycheck(
9655 lsp_store: Entity<Self>,
9656 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9657 cx: AsyncApp,
9658 ) -> Result<proto::Ack> {
9659 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9660 lsp_store.read_with(&cx, |lsp_store, _| {
9661 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9662 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9663 } else {
9664 None
9665 }
9666 });
9667
9668 Ok(proto::Ack {})
9669 }
9670
9671 pub fn disk_based_diagnostics_started(
9672 &mut self,
9673 language_server_id: LanguageServerId,
9674 cx: &mut Context<Self>,
9675 ) {
9676 if let Some(language_server_status) =
9677 self.language_server_statuses.get_mut(&language_server_id)
9678 {
9679 language_server_status.has_pending_diagnostic_updates = true;
9680 }
9681
9682 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9683 cx.emit(LspStoreEvent::LanguageServerUpdate {
9684 language_server_id,
9685 name: self
9686 .language_server_adapter_for_id(language_server_id)
9687 .map(|adapter| adapter.name()),
9688 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9689 Default::default(),
9690 ),
9691 })
9692 }
9693
9694 pub fn disk_based_diagnostics_finished(
9695 &mut self,
9696 language_server_id: LanguageServerId,
9697 cx: &mut Context<Self>,
9698 ) {
9699 if let Some(language_server_status) =
9700 self.language_server_statuses.get_mut(&language_server_id)
9701 {
9702 language_server_status.has_pending_diagnostic_updates = false;
9703 }
9704
9705 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9706 cx.emit(LspStoreEvent::LanguageServerUpdate {
9707 language_server_id,
9708 name: self
9709 .language_server_adapter_for_id(language_server_id)
9710 .map(|adapter| adapter.name()),
9711 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9712 Default::default(),
9713 ),
9714 })
9715 }
9716
9717 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9718 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9719 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9720 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9721 // the language server might take some time to publish diagnostics.
9722 fn simulate_disk_based_diagnostics_events_if_needed(
9723 &mut self,
9724 language_server_id: LanguageServerId,
9725 cx: &mut Context<Self>,
9726 ) {
9727 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9728
9729 let Some(LanguageServerState::Running {
9730 simulate_disk_based_diagnostics_completion,
9731 adapter,
9732 ..
9733 }) = self
9734 .as_local_mut()
9735 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9736 else {
9737 return;
9738 };
9739
9740 if adapter.disk_based_diagnostics_progress_token.is_some() {
9741 return;
9742 }
9743
9744 let prev_task =
9745 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9746 cx.background_executor()
9747 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9748 .await;
9749
9750 this.update(cx, |this, cx| {
9751 this.disk_based_diagnostics_finished(language_server_id, cx);
9752
9753 if let Some(LanguageServerState::Running {
9754 simulate_disk_based_diagnostics_completion,
9755 ..
9756 }) = this.as_local_mut().and_then(|local_store| {
9757 local_store.language_servers.get_mut(&language_server_id)
9758 }) {
9759 *simulate_disk_based_diagnostics_completion = None;
9760 }
9761 })
9762 .ok();
9763 }));
9764
9765 if prev_task.is_none() {
9766 self.disk_based_diagnostics_started(language_server_id, cx);
9767 }
9768 }
9769
9770 pub fn language_server_statuses(
9771 &self,
9772 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9773 self.language_server_statuses
9774 .iter()
9775 .map(|(key, value)| (*key, value))
9776 }
9777
9778 pub(super) fn did_rename_entry(
9779 &self,
9780 worktree_id: WorktreeId,
9781 old_path: &Path,
9782 new_path: &Path,
9783 is_dir: bool,
9784 ) {
9785 maybe!({
9786 let local_store = self.as_local()?;
9787
9788 let old_uri = lsp::Uri::from_file_path(old_path)
9789 .ok()
9790 .map(|uri| uri.to_string())?;
9791 let new_uri = lsp::Uri::from_file_path(new_path)
9792 .ok()
9793 .map(|uri| uri.to_string())?;
9794
9795 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9796 let Some(filter) = local_store
9797 .language_server_paths_watched_for_rename
9798 .get(&language_server.server_id())
9799 else {
9800 continue;
9801 };
9802
9803 if filter.should_send_did_rename(&old_uri, is_dir) {
9804 language_server
9805 .notify::<DidRenameFiles>(RenameFilesParams {
9806 files: vec![FileRename {
9807 old_uri: old_uri.clone(),
9808 new_uri: new_uri.clone(),
9809 }],
9810 })
9811 .ok();
9812 }
9813 }
9814 Some(())
9815 });
9816 }
9817
9818 pub(super) fn will_rename_entry(
9819 this: WeakEntity<Self>,
9820 worktree_id: WorktreeId,
9821 old_path: &Path,
9822 new_path: &Path,
9823 is_dir: bool,
9824 cx: AsyncApp,
9825 ) -> Task<ProjectTransaction> {
9826 let old_uri = lsp::Uri::from_file_path(old_path)
9827 .ok()
9828 .map(|uri| uri.to_string());
9829 let new_uri = lsp::Uri::from_file_path(new_path)
9830 .ok()
9831 .map(|uri| uri.to_string());
9832 cx.spawn(async move |cx| {
9833 let mut tasks = vec![];
9834 this.update(cx, |this, cx| {
9835 let local_store = this.as_local()?;
9836 let old_uri = old_uri?;
9837 let new_uri = new_uri?;
9838 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9839 let Some(filter) = local_store
9840 .language_server_paths_watched_for_rename
9841 .get(&language_server.server_id())
9842 else {
9843 continue;
9844 };
9845
9846 if !filter.should_send_will_rename(&old_uri, is_dir) {
9847 continue;
9848 }
9849 let request_timeout = ProjectSettings::get_global(cx)
9850 .global_lsp_settings
9851 .get_request_timeout();
9852
9853 let apply_edit = cx.spawn({
9854 let old_uri = old_uri.clone();
9855 let new_uri = new_uri.clone();
9856 let language_server = language_server.clone();
9857 async move |this, cx| {
9858 let edit = language_server
9859 .request::<WillRenameFiles>(
9860 RenameFilesParams {
9861 files: vec![FileRename { old_uri, new_uri }],
9862 },
9863 request_timeout,
9864 )
9865 .await
9866 .into_response()
9867 .context("will rename files")
9868 .log_err()
9869 .flatten()?;
9870
9871 LocalLspStore::deserialize_workspace_edit(
9872 this.upgrade()?,
9873 edit,
9874 false,
9875 language_server.clone(),
9876 cx,
9877 )
9878 .await
9879 .ok()
9880 }
9881 });
9882 tasks.push(apply_edit);
9883 }
9884 Some(())
9885 })
9886 .ok()
9887 .flatten();
9888 let mut merged_transaction = ProjectTransaction::default();
9889 for task in tasks {
9890 // Await on tasks sequentially so that the order of application of edits is deterministic
9891 // (at least with regards to the order of registration of language servers)
9892 if let Some(transaction) = task.await {
9893 for (buffer, buffer_transaction) in transaction.0 {
9894 merged_transaction.0.insert(buffer, buffer_transaction);
9895 }
9896 }
9897 }
9898 merged_transaction
9899 })
9900 }
9901
9902 fn lsp_notify_abs_paths_changed(
9903 &mut self,
9904 server_id: LanguageServerId,
9905 changes: Vec<PathEvent>,
9906 ) {
9907 maybe!({
9908 let server = self.language_server_for_id(server_id)?;
9909 let changes = changes
9910 .into_iter()
9911 .filter_map(|event| {
9912 let typ = match event.kind? {
9913 PathEventKind::Created => lsp::FileChangeType::CREATED,
9914 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9915 PathEventKind::Changed | PathEventKind::Rescan => {
9916 lsp::FileChangeType::CHANGED
9917 }
9918 };
9919 Some(lsp::FileEvent {
9920 uri: file_path_to_lsp_url(&event.path).log_err()?,
9921 typ,
9922 })
9923 })
9924 .collect::<Vec<_>>();
9925 if !changes.is_empty() {
9926 server
9927 .notify::<lsp::notification::DidChangeWatchedFiles>(
9928 lsp::DidChangeWatchedFilesParams { changes },
9929 )
9930 .ok();
9931 }
9932 Some(())
9933 });
9934 }
9935
9936 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9937 self.as_local()?.language_server_for_id(id)
9938 }
9939
9940 fn on_lsp_progress(
9941 &mut self,
9942 progress_params: lsp::ProgressParams,
9943 language_server_id: LanguageServerId,
9944 disk_based_diagnostics_progress_token: Option<String>,
9945 cx: &mut Context<Self>,
9946 ) {
9947 match progress_params.value {
9948 lsp::ProgressParamsValue::WorkDone(progress) => {
9949 self.handle_work_done_progress(
9950 progress,
9951 language_server_id,
9952 disk_based_diagnostics_progress_token,
9953 ProgressToken::from_lsp(progress_params.token),
9954 cx,
9955 );
9956 }
9957 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9958 let registration_id = match progress_params.token {
9959 lsp::NumberOrString::Number(_) => None,
9960 lsp::NumberOrString::String(token) => token
9961 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9962 .map(|(_, id)| id.to_owned()),
9963 };
9964 if let Some(LanguageServerState::Running {
9965 workspace_diagnostics_refresh_tasks,
9966 ..
9967 }) = self
9968 .as_local_mut()
9969 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9970 && let Some(workspace_diagnostics) =
9971 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9972 {
9973 workspace_diagnostics.progress_tx.try_send(()).ok();
9974 self.apply_workspace_diagnostic_report(
9975 language_server_id,
9976 report,
9977 registration_id.map(SharedString::from),
9978 cx,
9979 )
9980 }
9981 }
9982 }
9983 }
9984
9985 fn handle_work_done_progress(
9986 &mut self,
9987 progress: lsp::WorkDoneProgress,
9988 language_server_id: LanguageServerId,
9989 disk_based_diagnostics_progress_token: Option<String>,
9990 token: ProgressToken,
9991 cx: &mut Context<Self>,
9992 ) {
9993 let language_server_status =
9994 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9995 status
9996 } else {
9997 return;
9998 };
9999
10000 if !language_server_status.progress_tokens.contains(&token) {
10001 return;
10002 }
10003
10004 let is_disk_based_diagnostics_progress =
10005 if let (Some(disk_based_token), ProgressToken::String(token)) =
10006 (&disk_based_diagnostics_progress_token, &token)
10007 {
10008 token.starts_with(disk_based_token)
10009 } else {
10010 false
10011 };
10012
10013 match progress {
10014 lsp::WorkDoneProgress::Begin(report) => {
10015 if is_disk_based_diagnostics_progress {
10016 self.disk_based_diagnostics_started(language_server_id, cx);
10017 }
10018 self.on_lsp_work_start(
10019 language_server_id,
10020 token.clone(),
10021 LanguageServerProgress {
10022 title: Some(report.title),
10023 is_disk_based_diagnostics_progress,
10024 is_cancellable: report.cancellable.unwrap_or(false),
10025 message: report.message.clone(),
10026 percentage: report.percentage.map(|p| p as usize),
10027 last_update_at: cx.background_executor().now(),
10028 },
10029 cx,
10030 );
10031 }
10032 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10033 language_server_id,
10034 token,
10035 LanguageServerProgress {
10036 title: None,
10037 is_disk_based_diagnostics_progress,
10038 is_cancellable: report.cancellable.unwrap_or(false),
10039 message: report.message,
10040 percentage: report.percentage.map(|p| p as usize),
10041 last_update_at: cx.background_executor().now(),
10042 },
10043 cx,
10044 ),
10045 lsp::WorkDoneProgress::End(_) => {
10046 language_server_status.progress_tokens.remove(&token);
10047 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10048 if is_disk_based_diagnostics_progress {
10049 self.disk_based_diagnostics_finished(language_server_id, cx);
10050 }
10051 }
10052 }
10053 }
10054
10055 fn on_lsp_work_start(
10056 &mut self,
10057 language_server_id: LanguageServerId,
10058 token: ProgressToken,
10059 progress: LanguageServerProgress,
10060 cx: &mut Context<Self>,
10061 ) {
10062 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10063 status.pending_work.insert(token.clone(), progress.clone());
10064 cx.notify();
10065 }
10066 cx.emit(LspStoreEvent::LanguageServerUpdate {
10067 language_server_id,
10068 name: self
10069 .language_server_adapter_for_id(language_server_id)
10070 .map(|adapter| adapter.name()),
10071 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10072 token: Some(token.to_proto()),
10073 title: progress.title,
10074 message: progress.message,
10075 percentage: progress.percentage.map(|p| p as u32),
10076 is_cancellable: Some(progress.is_cancellable),
10077 }),
10078 })
10079 }
10080
10081 fn on_lsp_work_progress(
10082 &mut self,
10083 language_server_id: LanguageServerId,
10084 token: ProgressToken,
10085 progress: LanguageServerProgress,
10086 cx: &mut Context<Self>,
10087 ) {
10088 let mut did_update = false;
10089 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10090 match status.pending_work.entry(token.clone()) {
10091 btree_map::Entry::Vacant(entry) => {
10092 entry.insert(progress.clone());
10093 did_update = true;
10094 }
10095 btree_map::Entry::Occupied(mut entry) => {
10096 let entry = entry.get_mut();
10097 if (progress.last_update_at - entry.last_update_at)
10098 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10099 {
10100 entry.last_update_at = progress.last_update_at;
10101 if progress.message.is_some() {
10102 entry.message = progress.message.clone();
10103 }
10104 if progress.percentage.is_some() {
10105 entry.percentage = progress.percentage;
10106 }
10107 if progress.is_cancellable != entry.is_cancellable {
10108 entry.is_cancellable = progress.is_cancellable;
10109 }
10110 did_update = true;
10111 }
10112 }
10113 }
10114 }
10115
10116 if did_update {
10117 cx.emit(LspStoreEvent::LanguageServerUpdate {
10118 language_server_id,
10119 name: self
10120 .language_server_adapter_for_id(language_server_id)
10121 .map(|adapter| adapter.name()),
10122 message: proto::update_language_server::Variant::WorkProgress(
10123 proto::LspWorkProgress {
10124 token: Some(token.to_proto()),
10125 message: progress.message,
10126 percentage: progress.percentage.map(|p| p as u32),
10127 is_cancellable: Some(progress.is_cancellable),
10128 },
10129 ),
10130 })
10131 }
10132 }
10133
10134 fn on_lsp_work_end(
10135 &mut self,
10136 language_server_id: LanguageServerId,
10137 token: ProgressToken,
10138 cx: &mut Context<Self>,
10139 ) {
10140 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10141 if let Some(work) = status.pending_work.remove(&token)
10142 && !work.is_disk_based_diagnostics_progress
10143 {
10144 cx.emit(LspStoreEvent::RefreshInlayHints {
10145 server_id: language_server_id,
10146 request_id: None,
10147 });
10148 }
10149 cx.notify();
10150 }
10151
10152 cx.emit(LspStoreEvent::LanguageServerUpdate {
10153 language_server_id,
10154 name: self
10155 .language_server_adapter_for_id(language_server_id)
10156 .map(|adapter| adapter.name()),
10157 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10158 token: Some(token.to_proto()),
10159 }),
10160 })
10161 }
10162
10163 pub async fn handle_resolve_completion_documentation(
10164 this: Entity<Self>,
10165 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10166 mut cx: AsyncApp,
10167 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10168 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10169
10170 let completion = this
10171 .read_with(&cx, |this, cx| {
10172 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10173 let server = this
10174 .language_server_for_id(id)
10175 .with_context(|| format!("No language server {id}"))?;
10176
10177 let request_timeout = ProjectSettings::get_global(cx)
10178 .global_lsp_settings
10179 .get_request_timeout();
10180
10181 anyhow::Ok(cx.background_spawn(async move {
10182 let can_resolve = server
10183 .capabilities()
10184 .completion_provider
10185 .as_ref()
10186 .and_then(|options| options.resolve_provider)
10187 .unwrap_or(false);
10188 if can_resolve {
10189 server
10190 .request::<lsp::request::ResolveCompletionItem>(
10191 lsp_completion,
10192 request_timeout,
10193 )
10194 .await
10195 .into_response()
10196 .context("resolve completion item")
10197 } else {
10198 anyhow::Ok(lsp_completion)
10199 }
10200 }))
10201 })?
10202 .await?;
10203
10204 let mut documentation_is_markdown = false;
10205 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10206 let documentation = match completion.documentation {
10207 Some(lsp::Documentation::String(text)) => text,
10208
10209 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10210 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10211 value
10212 }
10213
10214 _ => String::new(),
10215 };
10216
10217 // If we have a new buffer_id, that means we're talking to a new client
10218 // and want to check for new text_edits in the completion too.
10219 let mut old_replace_start = None;
10220 let mut old_replace_end = None;
10221 let mut old_insert_start = None;
10222 let mut old_insert_end = None;
10223 let mut new_text = String::default();
10224 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10225 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10226 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10227 anyhow::Ok(buffer.read(cx).snapshot())
10228 })?;
10229
10230 if let Some(text_edit) = completion.text_edit.as_ref() {
10231 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10232
10233 if let Some(mut edit) = edit {
10234 LineEnding::normalize(&mut edit.new_text);
10235
10236 new_text = edit.new_text;
10237 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10238 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10239 if let Some(insert_range) = edit.insert_range {
10240 old_insert_start = Some(serialize_anchor(&insert_range.start));
10241 old_insert_end = Some(serialize_anchor(&insert_range.end));
10242 }
10243 }
10244 }
10245 }
10246
10247 Ok(proto::ResolveCompletionDocumentationResponse {
10248 documentation,
10249 documentation_is_markdown,
10250 old_replace_start,
10251 old_replace_end,
10252 new_text,
10253 lsp_completion,
10254 old_insert_start,
10255 old_insert_end,
10256 })
10257 }
10258
10259 async fn handle_on_type_formatting(
10260 this: Entity<Self>,
10261 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10262 mut cx: AsyncApp,
10263 ) -> Result<proto::OnTypeFormattingResponse> {
10264 let on_type_formatting = this.update(&mut cx, |this, cx| {
10265 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10266 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10267 let position = envelope
10268 .payload
10269 .position
10270 .and_then(deserialize_anchor)
10271 .context("invalid position")?;
10272 anyhow::Ok(this.apply_on_type_formatting(
10273 buffer,
10274 position,
10275 envelope.payload.trigger.clone(),
10276 cx,
10277 ))
10278 })?;
10279
10280 let transaction = on_type_formatting
10281 .await?
10282 .as_ref()
10283 .map(language::proto::serialize_transaction);
10284 Ok(proto::OnTypeFormattingResponse { transaction })
10285 }
10286
10287 async fn handle_pull_workspace_diagnostics(
10288 lsp_store: Entity<Self>,
10289 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10290 mut cx: AsyncApp,
10291 ) -> Result<proto::Ack> {
10292 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10293 lsp_store.update(&mut cx, |lsp_store, _| {
10294 lsp_store.pull_workspace_diagnostics(server_id);
10295 });
10296 Ok(proto::Ack {})
10297 }
10298
10299 async fn handle_open_buffer_for_symbol(
10300 this: Entity<Self>,
10301 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10302 mut cx: AsyncApp,
10303 ) -> Result<proto::OpenBufferForSymbolResponse> {
10304 let peer_id = envelope.original_sender_id().unwrap_or_default();
10305 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10306 let symbol = Self::deserialize_symbol(symbol)?;
10307 this.read_with(&cx, |this, _| {
10308 if let SymbolLocation::OutsideProject {
10309 abs_path,
10310 signature,
10311 } = &symbol.path
10312 {
10313 let new_signature = this.symbol_signature(&abs_path);
10314 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10315 }
10316 Ok(())
10317 })?;
10318 let buffer = this
10319 .update(&mut cx, |this, cx| {
10320 this.open_buffer_for_symbol(
10321 &Symbol {
10322 language_server_name: symbol.language_server_name,
10323 source_worktree_id: symbol.source_worktree_id,
10324 source_language_server_id: symbol.source_language_server_id,
10325 path: symbol.path,
10326 name: symbol.name,
10327 kind: symbol.kind,
10328 range: symbol.range,
10329 label: CodeLabel::default(),
10330 container_name: symbol.container_name,
10331 },
10332 cx,
10333 )
10334 })
10335 .await?;
10336
10337 this.update(&mut cx, |this, cx| {
10338 let is_private = buffer
10339 .read(cx)
10340 .file()
10341 .map(|f| f.is_private())
10342 .unwrap_or_default();
10343 if is_private {
10344 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10345 } else {
10346 this.buffer_store
10347 .update(cx, |buffer_store, cx| {
10348 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10349 })
10350 .detach_and_log_err(cx);
10351 let buffer_id = buffer.read(cx).remote_id().to_proto();
10352 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10353 }
10354 })
10355 }
10356
10357 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10358 let mut hasher = Sha256::new();
10359 hasher.update(abs_path.to_string_lossy().as_bytes());
10360 hasher.update(self.nonce.to_be_bytes());
10361 hasher.finalize().as_slice().try_into().unwrap()
10362 }
10363
10364 pub async fn handle_get_project_symbols(
10365 this: Entity<Self>,
10366 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10367 mut cx: AsyncApp,
10368 ) -> Result<proto::GetProjectSymbolsResponse> {
10369 let symbols = this
10370 .update(&mut cx, |this, cx| {
10371 this.symbols(&envelope.payload.query, cx)
10372 })
10373 .await?;
10374
10375 Ok(proto::GetProjectSymbolsResponse {
10376 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10377 })
10378 }
10379
10380 pub async fn handle_restart_language_servers(
10381 this: Entity<Self>,
10382 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10383 mut cx: AsyncApp,
10384 ) -> Result<proto::Ack> {
10385 this.update(&mut cx, |lsp_store, cx| {
10386 let buffers =
10387 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10388 lsp_store.restart_language_servers_for_buffers(
10389 buffers,
10390 envelope
10391 .payload
10392 .only_servers
10393 .into_iter()
10394 .filter_map(|selector| {
10395 Some(match selector.selector? {
10396 proto::language_server_selector::Selector::ServerId(server_id) => {
10397 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10398 }
10399 proto::language_server_selector::Selector::Name(name) => {
10400 LanguageServerSelector::Name(LanguageServerName(
10401 SharedString::from(name),
10402 ))
10403 }
10404 })
10405 })
10406 .collect(),
10407 cx,
10408 );
10409 });
10410
10411 Ok(proto::Ack {})
10412 }
10413
10414 pub async fn handle_stop_language_servers(
10415 lsp_store: Entity<Self>,
10416 envelope: TypedEnvelope<proto::StopLanguageServers>,
10417 mut cx: AsyncApp,
10418 ) -> Result<proto::Ack> {
10419 lsp_store.update(&mut cx, |lsp_store, cx| {
10420 if envelope.payload.all
10421 && envelope.payload.also_servers.is_empty()
10422 && envelope.payload.buffer_ids.is_empty()
10423 {
10424 lsp_store.stop_all_language_servers(cx);
10425 } else {
10426 let buffers =
10427 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10428 lsp_store
10429 .stop_language_servers_for_buffers(
10430 buffers,
10431 envelope
10432 .payload
10433 .also_servers
10434 .into_iter()
10435 .filter_map(|selector| {
10436 Some(match selector.selector? {
10437 proto::language_server_selector::Selector::ServerId(
10438 server_id,
10439 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10440 server_id,
10441 )),
10442 proto::language_server_selector::Selector::Name(name) => {
10443 LanguageServerSelector::Name(LanguageServerName(
10444 SharedString::from(name),
10445 ))
10446 }
10447 })
10448 })
10449 .collect(),
10450 cx,
10451 )
10452 .detach_and_log_err(cx);
10453 }
10454 });
10455
10456 Ok(proto::Ack {})
10457 }
10458
10459 pub async fn handle_cancel_language_server_work(
10460 lsp_store: Entity<Self>,
10461 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10462 mut cx: AsyncApp,
10463 ) -> Result<proto::Ack> {
10464 lsp_store.update(&mut cx, |lsp_store, cx| {
10465 if let Some(work) = envelope.payload.work {
10466 match work {
10467 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10468 let buffers =
10469 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10470 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10471 }
10472 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10473 let server_id = LanguageServerId::from_proto(work.language_server_id);
10474 let token = work
10475 .token
10476 .map(|token| {
10477 ProgressToken::from_proto(token)
10478 .context("invalid work progress token")
10479 })
10480 .transpose()?;
10481 lsp_store.cancel_language_server_work(server_id, token, cx);
10482 }
10483 }
10484 }
10485 anyhow::Ok(())
10486 })?;
10487
10488 Ok(proto::Ack {})
10489 }
10490
10491 fn buffer_ids_to_buffers(
10492 &mut self,
10493 buffer_ids: impl Iterator<Item = u64>,
10494 cx: &mut Context<Self>,
10495 ) -> Vec<Entity<Buffer>> {
10496 buffer_ids
10497 .into_iter()
10498 .flat_map(|buffer_id| {
10499 self.buffer_store
10500 .read(cx)
10501 .get(BufferId::new(buffer_id).log_err()?)
10502 })
10503 .collect::<Vec<_>>()
10504 }
10505
10506 async fn handle_apply_additional_edits_for_completion(
10507 this: Entity<Self>,
10508 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10509 mut cx: AsyncApp,
10510 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10511 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10512 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10513 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10514 let completion = Self::deserialize_completion(
10515 envelope.payload.completion.context("invalid completion")?,
10516 )?;
10517 let all_commit_ranges = envelope
10518 .payload
10519 .all_commit_ranges
10520 .into_iter()
10521 .map(language::proto::deserialize_anchor_range)
10522 .collect::<Result<Vec<_>, _>>()?;
10523 anyhow::Ok((buffer, completion, all_commit_ranges))
10524 })?;
10525
10526 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10527 this.apply_additional_edits_for_completion(
10528 buffer,
10529 Rc::new(RefCell::new(Box::new([Completion {
10530 replace_range: completion.replace_range,
10531 new_text: completion.new_text,
10532 source: completion.source,
10533 documentation: None,
10534 label: CodeLabel::default(),
10535 match_start: None,
10536 snippet_deduplication_key: None,
10537 insert_text_mode: None,
10538 icon_path: None,
10539 confirm: None,
10540 }]))),
10541 0,
10542 false,
10543 all_commit_ranges,
10544 cx,
10545 )
10546 });
10547
10548 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10549 transaction: apply_additional_edits
10550 .await?
10551 .as_ref()
10552 .map(language::proto::serialize_transaction),
10553 })
10554 }
10555
10556 pub fn last_formatting_failure(&self) -> Option<&str> {
10557 self.last_formatting_failure.as_deref()
10558 }
10559
10560 pub fn reset_last_formatting_failure(&mut self) {
10561 self.last_formatting_failure = None;
10562 }
10563
10564 pub fn environment_for_buffer(
10565 &self,
10566 buffer: &Entity<Buffer>,
10567 cx: &mut Context<Self>,
10568 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10569 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10570 environment.update(cx, |env, cx| {
10571 env.buffer_environment(buffer, &self.worktree_store, cx)
10572 })
10573 } else {
10574 Task::ready(None).shared()
10575 }
10576 }
10577
10578 pub fn format(
10579 &mut self,
10580 buffers: HashSet<Entity<Buffer>>,
10581 target: LspFormatTarget,
10582 push_to_history: bool,
10583 trigger: FormatTrigger,
10584 cx: &mut Context<Self>,
10585 ) -> Task<anyhow::Result<ProjectTransaction>> {
10586 let logger = zlog::scoped!("format");
10587 if self.as_local().is_some() {
10588 zlog::trace!(logger => "Formatting locally");
10589 let logger = zlog::scoped!(logger => "local");
10590 let buffers = buffers
10591 .into_iter()
10592 .map(|buffer_handle| {
10593 let buffer = buffer_handle.read(cx);
10594 let buffer_abs_path = File::from_dyn(buffer.file())
10595 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10596
10597 (buffer_handle, buffer_abs_path, buffer.remote_id())
10598 })
10599 .collect::<Vec<_>>();
10600
10601 cx.spawn(async move |lsp_store, cx| {
10602 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10603
10604 for (handle, abs_path, id) in buffers {
10605 let env = lsp_store
10606 .update(cx, |lsp_store, cx| {
10607 lsp_store.environment_for_buffer(&handle, cx)
10608 })?
10609 .await;
10610
10611 let ranges = match &target {
10612 LspFormatTarget::Buffers => None,
10613 LspFormatTarget::Ranges(ranges) => {
10614 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10615 }
10616 };
10617
10618 formattable_buffers.push(FormattableBuffer {
10619 handle,
10620 abs_path,
10621 env,
10622 ranges,
10623 });
10624 }
10625 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10626
10627 let format_timer = zlog::time!(logger => "Formatting buffers");
10628 let result = LocalLspStore::format_locally(
10629 lsp_store.clone(),
10630 formattable_buffers,
10631 push_to_history,
10632 trigger,
10633 logger,
10634 cx,
10635 )
10636 .await;
10637 format_timer.end();
10638
10639 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10640
10641 lsp_store.update(cx, |lsp_store, _| {
10642 lsp_store.update_last_formatting_failure(&result);
10643 })?;
10644
10645 result
10646 })
10647 } else if let Some((client, project_id)) = self.upstream_client() {
10648 zlog::trace!(logger => "Formatting remotely");
10649 let logger = zlog::scoped!(logger => "remote");
10650
10651 let buffer_ranges = match &target {
10652 LspFormatTarget::Buffers => Vec::new(),
10653 LspFormatTarget::Ranges(ranges) => ranges
10654 .iter()
10655 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10656 buffer_id: buffer_id.to_proto(),
10657 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10658 })
10659 .collect(),
10660 };
10661
10662 let buffer_store = self.buffer_store();
10663 cx.spawn(async move |lsp_store, cx| {
10664 zlog::trace!(logger => "Sending remote format request");
10665 let request_timer = zlog::time!(logger => "remote format request");
10666 let result = client
10667 .request(proto::FormatBuffers {
10668 project_id,
10669 trigger: trigger as i32,
10670 buffer_ids: buffers
10671 .iter()
10672 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10673 .collect(),
10674 buffer_ranges,
10675 })
10676 .await
10677 .and_then(|result| result.transaction.context("missing transaction"));
10678 request_timer.end();
10679
10680 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10681
10682 lsp_store.update(cx, |lsp_store, _| {
10683 lsp_store.update_last_formatting_failure(&result);
10684 })?;
10685
10686 let transaction_response = result?;
10687 let _timer = zlog::time!(logger => "deserializing project transaction");
10688 buffer_store
10689 .update(cx, |buffer_store, cx| {
10690 buffer_store.deserialize_project_transaction(
10691 transaction_response,
10692 push_to_history,
10693 cx,
10694 )
10695 })
10696 .await
10697 })
10698 } else {
10699 zlog::trace!(logger => "Not formatting");
10700 Task::ready(Ok(ProjectTransaction::default()))
10701 }
10702 }
10703
10704 async fn handle_format_buffers(
10705 this: Entity<Self>,
10706 envelope: TypedEnvelope<proto::FormatBuffers>,
10707 mut cx: AsyncApp,
10708 ) -> Result<proto::FormatBuffersResponse> {
10709 let sender_id = envelope.original_sender_id().unwrap_or_default();
10710 let format = this.update(&mut cx, |this, cx| {
10711 let mut buffers = HashSet::default();
10712 for buffer_id in &envelope.payload.buffer_ids {
10713 let buffer_id = BufferId::new(*buffer_id)?;
10714 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10715 }
10716
10717 let target = if envelope.payload.buffer_ranges.is_empty() {
10718 LspFormatTarget::Buffers
10719 } else {
10720 let mut ranges_map = BTreeMap::new();
10721 for buffer_range in &envelope.payload.buffer_ranges {
10722 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10723 let ranges: Result<Vec<_>> = buffer_range
10724 .ranges
10725 .iter()
10726 .map(|range| {
10727 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10728 })
10729 .collect();
10730 ranges_map.insert(buffer_id, ranges?);
10731 }
10732 LspFormatTarget::Ranges(ranges_map)
10733 };
10734
10735 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10736 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10737 })?;
10738
10739 let project_transaction = format.await?;
10740 let project_transaction = this.update(&mut cx, |this, cx| {
10741 this.buffer_store.update(cx, |buffer_store, cx| {
10742 buffer_store.serialize_project_transaction_for_peer(
10743 project_transaction,
10744 sender_id,
10745 cx,
10746 )
10747 })
10748 });
10749 Ok(proto::FormatBuffersResponse {
10750 transaction: Some(project_transaction),
10751 })
10752 }
10753
10754 async fn handle_apply_code_action_kind(
10755 this: Entity<Self>,
10756 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10757 mut cx: AsyncApp,
10758 ) -> Result<proto::ApplyCodeActionKindResponse> {
10759 let sender_id = envelope.original_sender_id().unwrap_or_default();
10760 let format = this.update(&mut cx, |this, cx| {
10761 let mut buffers = HashSet::default();
10762 for buffer_id in &envelope.payload.buffer_ids {
10763 let buffer_id = BufferId::new(*buffer_id)?;
10764 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10765 }
10766 let kind = match envelope.payload.kind.as_str() {
10767 "" => CodeActionKind::EMPTY,
10768 "quickfix" => CodeActionKind::QUICKFIX,
10769 "refactor" => CodeActionKind::REFACTOR,
10770 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10771 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10772 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10773 "source" => CodeActionKind::SOURCE,
10774 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10775 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10776 _ => anyhow::bail!(
10777 "Invalid code action kind {}",
10778 envelope.payload.kind.as_str()
10779 ),
10780 };
10781 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10782 })?;
10783
10784 let project_transaction = format.await?;
10785 let project_transaction = this.update(&mut cx, |this, cx| {
10786 this.buffer_store.update(cx, |buffer_store, cx| {
10787 buffer_store.serialize_project_transaction_for_peer(
10788 project_transaction,
10789 sender_id,
10790 cx,
10791 )
10792 })
10793 });
10794 Ok(proto::ApplyCodeActionKindResponse {
10795 transaction: Some(project_transaction),
10796 })
10797 }
10798
10799 async fn shutdown_language_server(
10800 server_state: Option<LanguageServerState>,
10801 name: LanguageServerName,
10802 cx: &mut AsyncApp,
10803 ) {
10804 let server = match server_state {
10805 Some(LanguageServerState::Starting { startup, .. }) => {
10806 let mut timer = cx
10807 .background_executor()
10808 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10809 .fuse();
10810
10811 select! {
10812 server = startup.fuse() => server,
10813 () = timer => {
10814 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10815 None
10816 },
10817 }
10818 }
10819
10820 Some(LanguageServerState::Running { server, .. }) => Some(server),
10821
10822 None => None,
10823 };
10824
10825 let Some(server) = server else { return };
10826 if let Some(shutdown) = server.shutdown() {
10827 shutdown.await;
10828 }
10829 }
10830
10831 // Returns a list of all of the worktrees which no longer have a language server and the root path
10832 // for the stopped server
10833 fn stop_local_language_server(
10834 &mut self,
10835 server_id: LanguageServerId,
10836 cx: &mut Context<Self>,
10837 ) -> Task<()> {
10838 let local = match &mut self.mode {
10839 LspStoreMode::Local(local) => local,
10840 _ => {
10841 return Task::ready(());
10842 }
10843 };
10844
10845 // Remove this server ID from all entries in the given worktree.
10846 local
10847 .language_server_ids
10848 .retain(|_, state| state.id != server_id);
10849 self.buffer_store.update(cx, |buffer_store, cx| {
10850 for buffer in buffer_store.buffers() {
10851 buffer.update(cx, |buffer, cx| {
10852 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10853 buffer.set_completion_triggers(server_id, Default::default(), cx);
10854 });
10855 }
10856 });
10857
10858 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10859 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10860 summaries.retain(|path, summaries_by_server_id| {
10861 if summaries_by_server_id.remove(&server_id).is_some() {
10862 if let Some((client, project_id)) = self.downstream_client.clone() {
10863 client
10864 .send(proto::UpdateDiagnosticSummary {
10865 project_id,
10866 worktree_id: worktree_id.to_proto(),
10867 summary: Some(proto::DiagnosticSummary {
10868 path: path.as_ref().to_proto(),
10869 language_server_id: server_id.0 as u64,
10870 error_count: 0,
10871 warning_count: 0,
10872 }),
10873 more_summaries: Vec::new(),
10874 })
10875 .log_err();
10876 }
10877 cleared_paths.push(ProjectPath {
10878 worktree_id: *worktree_id,
10879 path: path.clone(),
10880 });
10881 !summaries_by_server_id.is_empty()
10882 } else {
10883 true
10884 }
10885 });
10886 }
10887 if !cleared_paths.is_empty() {
10888 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10889 server_id,
10890 paths: cleared_paths,
10891 });
10892 }
10893
10894 let local = self.as_local_mut().unwrap();
10895 for diagnostics in local.diagnostics.values_mut() {
10896 diagnostics.retain(|_, diagnostics_by_server_id| {
10897 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10898 diagnostics_by_server_id.remove(ix);
10899 !diagnostics_by_server_id.is_empty()
10900 } else {
10901 true
10902 }
10903 });
10904 }
10905 local.language_server_watched_paths.remove(&server_id);
10906
10907 let server_state = local.language_servers.remove(&server_id);
10908 self.cleanup_lsp_data(server_id);
10909 let name = self
10910 .language_server_statuses
10911 .remove(&server_id)
10912 .map(|status| status.name)
10913 .or_else(|| {
10914 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10915 Some(adapter.name())
10916 } else {
10917 None
10918 }
10919 });
10920
10921 if let Some(name) = name {
10922 log::info!("stopping language server {name}");
10923 self.languages
10924 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10925 cx.notify();
10926
10927 return cx.spawn(async move |lsp_store, cx| {
10928 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10929 lsp_store
10930 .update(cx, |lsp_store, cx| {
10931 lsp_store
10932 .languages
10933 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10934 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10935 cx.notify();
10936 })
10937 .ok();
10938 });
10939 }
10940
10941 if server_state.is_some() {
10942 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10943 }
10944 Task::ready(())
10945 }
10946
10947 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10948 self.shutdown_all_language_servers(cx).detach();
10949 }
10950
10951 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10952 if let Some((client, project_id)) = self.upstream_client() {
10953 let request = client.request(proto::StopLanguageServers {
10954 project_id,
10955 buffer_ids: Vec::new(),
10956 also_servers: Vec::new(),
10957 all: true,
10958 });
10959 cx.background_spawn(async move {
10960 request.await.ok();
10961 })
10962 } else {
10963 let Some(local) = self.as_local_mut() else {
10964 return Task::ready(());
10965 };
10966 let language_servers_to_stop = local
10967 .language_server_ids
10968 .values()
10969 .map(|state| state.id)
10970 .collect();
10971 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10972 let tasks = language_servers_to_stop
10973 .into_iter()
10974 .map(|server| self.stop_local_language_server(server, cx))
10975 .collect::<Vec<_>>();
10976 cx.background_spawn(async move {
10977 futures::future::join_all(tasks).await;
10978 })
10979 }
10980 }
10981
10982 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10983 let buffers = self.buffer_store.read(cx).buffers().collect();
10984 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10985 }
10986
10987 pub fn restart_language_servers_for_buffers(
10988 &mut self,
10989 buffers: Vec<Entity<Buffer>>,
10990 only_restart_servers: HashSet<LanguageServerSelector>,
10991 cx: &mut Context<Self>,
10992 ) {
10993 if let Some((client, project_id)) = self.upstream_client() {
10994 let request = client.request(proto::RestartLanguageServers {
10995 project_id,
10996 buffer_ids: buffers
10997 .into_iter()
10998 .map(|b| b.read(cx).remote_id().to_proto())
10999 .collect(),
11000 only_servers: only_restart_servers
11001 .into_iter()
11002 .map(|selector| {
11003 let selector = match selector {
11004 LanguageServerSelector::Id(language_server_id) => {
11005 proto::language_server_selector::Selector::ServerId(
11006 language_server_id.to_proto(),
11007 )
11008 }
11009 LanguageServerSelector::Name(language_server_name) => {
11010 proto::language_server_selector::Selector::Name(
11011 language_server_name.to_string(),
11012 )
11013 }
11014 };
11015 proto::LanguageServerSelector {
11016 selector: Some(selector),
11017 }
11018 })
11019 .collect(),
11020 all: false,
11021 });
11022 cx.background_spawn(request).detach_and_log_err(cx);
11023 } else {
11024 let stop_task = if only_restart_servers.is_empty() {
11025 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11026 } else {
11027 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11028 };
11029 cx.spawn(async move |lsp_store, cx| {
11030 stop_task.await;
11031 lsp_store.update(cx, |lsp_store, cx| {
11032 for buffer in buffers {
11033 lsp_store.register_buffer_with_language_servers(
11034 &buffer,
11035 only_restart_servers.clone(),
11036 true,
11037 cx,
11038 );
11039 }
11040 })
11041 })
11042 .detach();
11043 }
11044 }
11045
11046 pub fn stop_language_servers_for_buffers(
11047 &mut self,
11048 buffers: Vec<Entity<Buffer>>,
11049 also_stop_servers: HashSet<LanguageServerSelector>,
11050 cx: &mut Context<Self>,
11051 ) -> Task<Result<()>> {
11052 if let Some((client, project_id)) = self.upstream_client() {
11053 let request = client.request(proto::StopLanguageServers {
11054 project_id,
11055 buffer_ids: buffers
11056 .into_iter()
11057 .map(|b| b.read(cx).remote_id().to_proto())
11058 .collect(),
11059 also_servers: also_stop_servers
11060 .into_iter()
11061 .map(|selector| {
11062 let selector = match selector {
11063 LanguageServerSelector::Id(language_server_id) => {
11064 proto::language_server_selector::Selector::ServerId(
11065 language_server_id.to_proto(),
11066 )
11067 }
11068 LanguageServerSelector::Name(language_server_name) => {
11069 proto::language_server_selector::Selector::Name(
11070 language_server_name.to_string(),
11071 )
11072 }
11073 };
11074 proto::LanguageServerSelector {
11075 selector: Some(selector),
11076 }
11077 })
11078 .collect(),
11079 all: false,
11080 });
11081 cx.background_spawn(async move {
11082 let _ = request.await?;
11083 Ok(())
11084 })
11085 } else {
11086 let task =
11087 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11088 cx.background_spawn(async move {
11089 task.await;
11090 Ok(())
11091 })
11092 }
11093 }
11094
11095 fn stop_local_language_servers_for_buffers(
11096 &mut self,
11097 buffers: &[Entity<Buffer>],
11098 also_stop_servers: HashSet<LanguageServerSelector>,
11099 cx: &mut Context<Self>,
11100 ) -> Task<()> {
11101 let Some(local) = self.as_local_mut() else {
11102 return Task::ready(());
11103 };
11104 let mut language_server_names_to_stop = BTreeSet::default();
11105 let mut language_servers_to_stop = also_stop_servers
11106 .into_iter()
11107 .flat_map(|selector| match selector {
11108 LanguageServerSelector::Id(id) => Some(id),
11109 LanguageServerSelector::Name(name) => {
11110 language_server_names_to_stop.insert(name);
11111 None
11112 }
11113 })
11114 .collect::<BTreeSet<_>>();
11115
11116 let mut covered_worktrees = HashSet::default();
11117 for buffer in buffers {
11118 buffer.update(cx, |buffer, cx| {
11119 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11120 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11121 && covered_worktrees.insert(worktree_id)
11122 {
11123 language_server_names_to_stop.retain(|name| {
11124 let old_ids_count = language_servers_to_stop.len();
11125 let all_language_servers_with_this_name = local
11126 .language_server_ids
11127 .iter()
11128 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11129 language_servers_to_stop.extend(all_language_servers_with_this_name);
11130 old_ids_count == language_servers_to_stop.len()
11131 });
11132 }
11133 });
11134 }
11135 for name in language_server_names_to_stop {
11136 language_servers_to_stop.extend(
11137 local
11138 .language_server_ids
11139 .iter()
11140 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11141 );
11142 }
11143
11144 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11145 let tasks = language_servers_to_stop
11146 .into_iter()
11147 .map(|server| self.stop_local_language_server(server, cx))
11148 .collect::<Vec<_>>();
11149
11150 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11151 }
11152
11153 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11154 let (worktree, relative_path) =
11155 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11156
11157 let project_path = ProjectPath {
11158 worktree_id: worktree.read(cx).id(),
11159 path: relative_path,
11160 };
11161
11162 Some(
11163 self.buffer_store()
11164 .read(cx)
11165 .get_by_path(&project_path)?
11166 .read(cx),
11167 )
11168 }
11169
11170 #[cfg(any(test, feature = "test-support"))]
11171 pub fn update_diagnostics(
11172 &mut self,
11173 server_id: LanguageServerId,
11174 diagnostics: lsp::PublishDiagnosticsParams,
11175 result_id: Option<SharedString>,
11176 source_kind: DiagnosticSourceKind,
11177 disk_based_sources: &[String],
11178 cx: &mut Context<Self>,
11179 ) -> Result<()> {
11180 self.merge_lsp_diagnostics(
11181 source_kind,
11182 vec![DocumentDiagnosticsUpdate {
11183 diagnostics,
11184 result_id,
11185 server_id,
11186 disk_based_sources: Cow::Borrowed(disk_based_sources),
11187 registration_id: None,
11188 }],
11189 |_, _, _| false,
11190 cx,
11191 )
11192 }
11193
11194 pub fn merge_lsp_diagnostics(
11195 &mut self,
11196 source_kind: DiagnosticSourceKind,
11197 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11198 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11199 cx: &mut Context<Self>,
11200 ) -> Result<()> {
11201 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11202 let updates = lsp_diagnostics
11203 .into_iter()
11204 .filter_map(|update| {
11205 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11206 Some(DocumentDiagnosticsUpdate {
11207 diagnostics: self.lsp_to_document_diagnostics(
11208 abs_path,
11209 source_kind,
11210 update.server_id,
11211 update.diagnostics,
11212 &update.disk_based_sources,
11213 update.registration_id.clone(),
11214 ),
11215 result_id: update.result_id,
11216 server_id: update.server_id,
11217 disk_based_sources: update.disk_based_sources,
11218 registration_id: update.registration_id,
11219 })
11220 })
11221 .collect();
11222 self.merge_diagnostic_entries(updates, merge, cx)?;
11223 Ok(())
11224 }
11225
11226 fn lsp_to_document_diagnostics(
11227 &mut self,
11228 document_abs_path: PathBuf,
11229 source_kind: DiagnosticSourceKind,
11230 server_id: LanguageServerId,
11231 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11232 disk_based_sources: &[String],
11233 registration_id: Option<SharedString>,
11234 ) -> DocumentDiagnostics {
11235 let mut diagnostics = Vec::default();
11236 let mut primary_diagnostic_group_ids = HashMap::default();
11237 let mut sources_by_group_id = HashMap::default();
11238 let mut supporting_diagnostics = HashMap::default();
11239
11240 let adapter = self.language_server_adapter_for_id(server_id);
11241
11242 // Ensure that primary diagnostics are always the most severe
11243 lsp_diagnostics
11244 .diagnostics
11245 .sort_by_key(|item| item.severity);
11246
11247 for diagnostic in &lsp_diagnostics.diagnostics {
11248 let source = diagnostic.source.as_ref();
11249 let range = range_from_lsp(diagnostic.range);
11250 let is_supporting = diagnostic
11251 .related_information
11252 .as_ref()
11253 .is_some_and(|infos| {
11254 infos.iter().any(|info| {
11255 primary_diagnostic_group_ids.contains_key(&(
11256 source,
11257 diagnostic.code.clone(),
11258 range_from_lsp(info.location.range),
11259 ))
11260 })
11261 });
11262
11263 let is_unnecessary = diagnostic
11264 .tags
11265 .as_ref()
11266 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11267
11268 let underline = self
11269 .language_server_adapter_for_id(server_id)
11270 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11271
11272 if is_supporting {
11273 supporting_diagnostics.insert(
11274 (source, diagnostic.code.clone(), range),
11275 (diagnostic.severity, is_unnecessary),
11276 );
11277 } else {
11278 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11279 let is_disk_based =
11280 source.is_some_and(|source| disk_based_sources.contains(source));
11281
11282 sources_by_group_id.insert(group_id, source);
11283 primary_diagnostic_group_ids
11284 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11285
11286 diagnostics.push(DiagnosticEntry {
11287 range,
11288 diagnostic: Diagnostic {
11289 source: diagnostic.source.clone(),
11290 source_kind,
11291 code: diagnostic.code.clone(),
11292 code_description: diagnostic
11293 .code_description
11294 .as_ref()
11295 .and_then(|d| d.href.clone()),
11296 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11297 markdown: adapter.as_ref().and_then(|adapter| {
11298 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11299 }),
11300 message: diagnostic.message.trim().to_string(),
11301 group_id,
11302 is_primary: true,
11303 is_disk_based,
11304 is_unnecessary,
11305 underline,
11306 data: diagnostic.data.clone(),
11307 registration_id: registration_id.clone(),
11308 },
11309 });
11310 if let Some(infos) = &diagnostic.related_information {
11311 for info in infos {
11312 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11313 let range = range_from_lsp(info.location.range);
11314 diagnostics.push(DiagnosticEntry {
11315 range,
11316 diagnostic: Diagnostic {
11317 source: diagnostic.source.clone(),
11318 source_kind,
11319 code: diagnostic.code.clone(),
11320 code_description: diagnostic
11321 .code_description
11322 .as_ref()
11323 .and_then(|d| d.href.clone()),
11324 severity: DiagnosticSeverity::INFORMATION,
11325 markdown: adapter.as_ref().and_then(|adapter| {
11326 adapter.diagnostic_message_to_markdown(&info.message)
11327 }),
11328 message: info.message.trim().to_string(),
11329 group_id,
11330 is_primary: false,
11331 is_disk_based,
11332 is_unnecessary: false,
11333 underline,
11334 data: diagnostic.data.clone(),
11335 registration_id: registration_id.clone(),
11336 },
11337 });
11338 }
11339 }
11340 }
11341 }
11342 }
11343
11344 for entry in &mut diagnostics {
11345 let diagnostic = &mut entry.diagnostic;
11346 if !diagnostic.is_primary {
11347 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11348 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11349 source,
11350 diagnostic.code.clone(),
11351 entry.range.clone(),
11352 )) {
11353 if let Some(severity) = severity {
11354 diagnostic.severity = severity;
11355 }
11356 diagnostic.is_unnecessary = is_unnecessary;
11357 }
11358 }
11359 }
11360
11361 DocumentDiagnostics {
11362 diagnostics,
11363 document_abs_path,
11364 version: lsp_diagnostics.version,
11365 }
11366 }
11367
11368 fn insert_newly_running_language_server(
11369 &mut self,
11370 adapter: Arc<CachedLspAdapter>,
11371 language_server: Arc<LanguageServer>,
11372 server_id: LanguageServerId,
11373 key: LanguageServerSeed,
11374 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11375 cx: &mut Context<Self>,
11376 ) {
11377 let Some(local) = self.as_local_mut() else {
11378 return;
11379 };
11380 // If the language server for this key doesn't match the server id, don't store the
11381 // server. Which will cause it to be dropped, killing the process
11382 if local
11383 .language_server_ids
11384 .get(&key)
11385 .map(|state| state.id != server_id)
11386 .unwrap_or(false)
11387 {
11388 return;
11389 }
11390
11391 // Update language_servers collection with Running variant of LanguageServerState
11392 // indicating that the server is up and running and ready
11393 let workspace_folders = workspace_folders.lock().clone();
11394 language_server.set_workspace_folders(workspace_folders);
11395
11396 let workspace_diagnostics_refresh_tasks = language_server
11397 .capabilities()
11398 .diagnostic_provider
11399 .and_then(|provider| {
11400 local
11401 .language_server_dynamic_registrations
11402 .entry(server_id)
11403 .or_default()
11404 .diagnostics
11405 .entry(None)
11406 .or_insert(provider.clone());
11407 let workspace_refresher =
11408 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11409
11410 Some((None, workspace_refresher))
11411 })
11412 .into_iter()
11413 .collect();
11414 local.language_servers.insert(
11415 server_id,
11416 LanguageServerState::Running {
11417 workspace_diagnostics_refresh_tasks,
11418 adapter: adapter.clone(),
11419 server: language_server.clone(),
11420 simulate_disk_based_diagnostics_completion: None,
11421 },
11422 );
11423 local
11424 .languages
11425 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11426 if let Some(file_ops_caps) = language_server
11427 .capabilities()
11428 .workspace
11429 .as_ref()
11430 .and_then(|ws| ws.file_operations.as_ref())
11431 {
11432 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11433 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11434 if did_rename_caps.or(will_rename_caps).is_some() {
11435 let watcher = RenamePathsWatchedForServer::default()
11436 .with_did_rename_patterns(did_rename_caps)
11437 .with_will_rename_patterns(will_rename_caps);
11438 local
11439 .language_server_paths_watched_for_rename
11440 .insert(server_id, watcher);
11441 }
11442 }
11443
11444 self.language_server_statuses.insert(
11445 server_id,
11446 LanguageServerStatus {
11447 name: language_server.name(),
11448 server_version: language_server.version(),
11449 server_readable_version: language_server.readable_version(),
11450 pending_work: Default::default(),
11451 has_pending_diagnostic_updates: false,
11452 progress_tokens: Default::default(),
11453 worktree: Some(key.worktree_id),
11454 binary: Some(language_server.binary().clone()),
11455 configuration: Some(language_server.configuration().clone()),
11456 workspace_folders: language_server.workspace_folders(),
11457 process_id: language_server.process_id(),
11458 },
11459 );
11460
11461 cx.emit(LspStoreEvent::LanguageServerAdded(
11462 server_id,
11463 language_server.name(),
11464 Some(key.worktree_id),
11465 ));
11466
11467 let server_capabilities = language_server.capabilities();
11468 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11469 downstream_client
11470 .send(proto::StartLanguageServer {
11471 project_id: *project_id,
11472 server: Some(proto::LanguageServer {
11473 id: server_id.to_proto(),
11474 name: language_server.name().to_string(),
11475 worktree_id: Some(key.worktree_id.to_proto()),
11476 }),
11477 capabilities: serde_json::to_string(&server_capabilities)
11478 .expect("serializing server LSP capabilities"),
11479 })
11480 .log_err();
11481 }
11482 self.lsp_server_capabilities
11483 .insert(server_id, server_capabilities);
11484
11485 // Tell the language server about every open buffer in the worktree that matches the language.
11486 // Also check for buffers in worktrees that reused this server
11487 let mut worktrees_using_server = vec![key.worktree_id];
11488 if let Some(local) = self.as_local() {
11489 // Find all worktrees that have this server in their language server tree
11490 for (worktree_id, servers) in &local.lsp_tree.instances {
11491 if *worktree_id != key.worktree_id {
11492 for server_map in servers.roots.values() {
11493 if server_map
11494 .values()
11495 .any(|(node, _)| node.id() == Some(server_id))
11496 {
11497 worktrees_using_server.push(*worktree_id);
11498 }
11499 }
11500 }
11501 }
11502 }
11503
11504 let mut buffer_paths_registered = Vec::new();
11505 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11506 let mut lsp_adapters = HashMap::default();
11507 for buffer_handle in buffer_store.buffers() {
11508 let buffer = buffer_handle.read(cx);
11509 let file = match File::from_dyn(buffer.file()) {
11510 Some(file) => file,
11511 None => continue,
11512 };
11513 let language = match buffer.language() {
11514 Some(language) => language,
11515 None => continue,
11516 };
11517
11518 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11519 || !lsp_adapters
11520 .entry(language.name())
11521 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11522 .iter()
11523 .any(|a| a.name == key.name)
11524 {
11525 continue;
11526 }
11527 // didOpen
11528 let file = match file.as_local() {
11529 Some(file) => file,
11530 None => continue,
11531 };
11532
11533 let local = self.as_local_mut().unwrap();
11534
11535 let buffer_id = buffer.remote_id();
11536 if local.registered_buffers.contains_key(&buffer_id) {
11537 let abs_path = file.abs_path(cx);
11538 let uri = match lsp::Uri::from_file_path(&abs_path) {
11539 Ok(uri) => uri,
11540 Err(()) => {
11541 log::error!("failed to convert path to URI: {:?}", abs_path);
11542 continue;
11543 }
11544 };
11545
11546 let versions = local
11547 .buffer_snapshots
11548 .entry(buffer_id)
11549 .or_default()
11550 .entry(server_id)
11551 .and_modify(|_| {
11552 assert!(
11553 false,
11554 "There should not be an existing snapshot for a newly inserted buffer"
11555 )
11556 })
11557 .or_insert_with(|| {
11558 vec![LspBufferSnapshot {
11559 version: 0,
11560 snapshot: buffer.text_snapshot(),
11561 }]
11562 });
11563
11564 let snapshot = versions.last().unwrap();
11565 let version = snapshot.version;
11566 let initial_snapshot = &snapshot.snapshot;
11567 language_server.register_buffer(
11568 uri,
11569 adapter.language_id(&language.name()),
11570 version,
11571 initial_snapshot.text(),
11572 );
11573 buffer_paths_registered.push((buffer_id, abs_path));
11574 local
11575 .buffers_opened_in_servers
11576 .entry(buffer_id)
11577 .or_default()
11578 .insert(server_id);
11579 }
11580 buffer_handle.update(cx, |buffer, cx| {
11581 buffer.set_completion_triggers(
11582 server_id,
11583 language_server
11584 .capabilities()
11585 .completion_provider
11586 .as_ref()
11587 .and_then(|provider| {
11588 provider
11589 .trigger_characters
11590 .as_ref()
11591 .map(|characters| characters.iter().cloned().collect())
11592 })
11593 .unwrap_or_default(),
11594 cx,
11595 )
11596 });
11597 }
11598 });
11599
11600 for (buffer_id, abs_path) in buffer_paths_registered {
11601 cx.emit(LspStoreEvent::LanguageServerUpdate {
11602 language_server_id: server_id,
11603 name: Some(adapter.name()),
11604 message: proto::update_language_server::Variant::RegisteredForBuffer(
11605 proto::RegisteredForBuffer {
11606 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11607 buffer_id: buffer_id.to_proto(),
11608 },
11609 ),
11610 });
11611 }
11612
11613 cx.notify();
11614 }
11615
11616 pub fn language_servers_running_disk_based_diagnostics(
11617 &self,
11618 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11619 self.language_server_statuses
11620 .iter()
11621 .filter_map(|(id, status)| {
11622 if status.has_pending_diagnostic_updates {
11623 Some(*id)
11624 } else {
11625 None
11626 }
11627 })
11628 }
11629
11630 pub(crate) fn cancel_language_server_work_for_buffers(
11631 &mut self,
11632 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11633 cx: &mut Context<Self>,
11634 ) {
11635 if let Some((client, project_id)) = self.upstream_client() {
11636 let request = client.request(proto::CancelLanguageServerWork {
11637 project_id,
11638 work: Some(proto::cancel_language_server_work::Work::Buffers(
11639 proto::cancel_language_server_work::Buffers {
11640 buffer_ids: buffers
11641 .into_iter()
11642 .map(|b| b.read(cx).remote_id().to_proto())
11643 .collect(),
11644 },
11645 )),
11646 });
11647 cx.background_spawn(request).detach_and_log_err(cx);
11648 } else if let Some(local) = self.as_local() {
11649 let servers = buffers
11650 .into_iter()
11651 .flat_map(|buffer| {
11652 buffer.update(cx, |buffer, cx| {
11653 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11654 })
11655 })
11656 .collect::<HashSet<_>>();
11657 for server_id in servers {
11658 self.cancel_language_server_work(server_id, None, cx);
11659 }
11660 }
11661 }
11662
11663 pub(crate) fn cancel_language_server_work(
11664 &mut self,
11665 server_id: LanguageServerId,
11666 token_to_cancel: Option<ProgressToken>,
11667 cx: &mut Context<Self>,
11668 ) {
11669 if let Some(local) = self.as_local() {
11670 let status = self.language_server_statuses.get(&server_id);
11671 let server = local.language_servers.get(&server_id);
11672 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11673 {
11674 for (token, progress) in &status.pending_work {
11675 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11676 && token != token_to_cancel
11677 {
11678 continue;
11679 }
11680 if progress.is_cancellable {
11681 server
11682 .notify::<lsp::notification::WorkDoneProgressCancel>(
11683 WorkDoneProgressCancelParams {
11684 token: token.to_lsp(),
11685 },
11686 )
11687 .ok();
11688 }
11689 }
11690 }
11691 } else if let Some((client, project_id)) = self.upstream_client() {
11692 let request = client.request(proto::CancelLanguageServerWork {
11693 project_id,
11694 work: Some(
11695 proto::cancel_language_server_work::Work::LanguageServerWork(
11696 proto::cancel_language_server_work::LanguageServerWork {
11697 language_server_id: server_id.to_proto(),
11698 token: token_to_cancel.map(|token| token.to_proto()),
11699 },
11700 ),
11701 ),
11702 });
11703 cx.background_spawn(request).detach_and_log_err(cx);
11704 }
11705 }
11706
11707 fn register_supplementary_language_server(
11708 &mut self,
11709 id: LanguageServerId,
11710 name: LanguageServerName,
11711 server: Arc<LanguageServer>,
11712 cx: &mut Context<Self>,
11713 ) {
11714 if let Some(local) = self.as_local_mut() {
11715 local
11716 .supplementary_language_servers
11717 .insert(id, (name.clone(), server));
11718 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11719 }
11720 }
11721
11722 fn unregister_supplementary_language_server(
11723 &mut self,
11724 id: LanguageServerId,
11725 cx: &mut Context<Self>,
11726 ) {
11727 if let Some(local) = self.as_local_mut() {
11728 local.supplementary_language_servers.remove(&id);
11729 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11730 }
11731 }
11732
11733 pub(crate) fn supplementary_language_servers(
11734 &self,
11735 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11736 self.as_local().into_iter().flat_map(|local| {
11737 local
11738 .supplementary_language_servers
11739 .iter()
11740 .map(|(id, (name, _))| (*id, name.clone()))
11741 })
11742 }
11743
11744 pub fn language_server_adapter_for_id(
11745 &self,
11746 id: LanguageServerId,
11747 ) -> Option<Arc<CachedLspAdapter>> {
11748 self.as_local()
11749 .and_then(|local| local.language_servers.get(&id))
11750 .and_then(|language_server_state| match language_server_state {
11751 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11752 _ => None,
11753 })
11754 }
11755
11756 pub(super) fn update_local_worktree_language_servers(
11757 &mut self,
11758 worktree_handle: &Entity<Worktree>,
11759 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11760 cx: &mut Context<Self>,
11761 ) {
11762 if changes.is_empty() {
11763 return;
11764 }
11765
11766 let Some(local) = self.as_local() else { return };
11767
11768 local.prettier_store.update(cx, |prettier_store, cx| {
11769 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11770 });
11771
11772 let worktree_id = worktree_handle.read(cx).id();
11773 let mut language_server_ids = local
11774 .language_server_ids
11775 .iter()
11776 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11777 .collect::<Vec<_>>();
11778 language_server_ids.sort();
11779 language_server_ids.dedup();
11780
11781 // let abs_path = worktree_handle.read(cx).abs_path();
11782 for server_id in &language_server_ids {
11783 if let Some(LanguageServerState::Running { server, .. }) =
11784 local.language_servers.get(server_id)
11785 && let Some(watched_paths) = local
11786 .language_server_watched_paths
11787 .get(server_id)
11788 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11789 {
11790 let params = lsp::DidChangeWatchedFilesParams {
11791 changes: changes
11792 .iter()
11793 .filter_map(|(path, _, change)| {
11794 if !watched_paths.is_match(path.as_std_path()) {
11795 return None;
11796 }
11797 let typ = match change {
11798 PathChange::Loaded => return None,
11799 PathChange::Added => lsp::FileChangeType::CREATED,
11800 PathChange::Removed => lsp::FileChangeType::DELETED,
11801 PathChange::Updated => lsp::FileChangeType::CHANGED,
11802 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11803 };
11804 let uri = lsp::Uri::from_file_path(
11805 worktree_handle.read(cx).absolutize(&path),
11806 )
11807 .ok()?;
11808 Some(lsp::FileEvent { uri, typ })
11809 })
11810 .collect(),
11811 };
11812 if !params.changes.is_empty() {
11813 server
11814 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11815 .ok();
11816 }
11817 }
11818 }
11819 for (path, _, _) in changes {
11820 if let Some(file_name) = path.file_name()
11821 && local.watched_manifest_filenames.contains(file_name)
11822 {
11823 self.request_workspace_config_refresh();
11824 break;
11825 }
11826 }
11827 }
11828
11829 pub fn wait_for_remote_buffer(
11830 &mut self,
11831 id: BufferId,
11832 cx: &mut Context<Self>,
11833 ) -> Task<Result<Entity<Buffer>>> {
11834 self.buffer_store.update(cx, |buffer_store, cx| {
11835 buffer_store.wait_for_remote_buffer(id, cx)
11836 })
11837 }
11838
11839 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11840 let mut result = proto::Symbol {
11841 language_server_name: symbol.language_server_name.0.to_string(),
11842 source_worktree_id: symbol.source_worktree_id.to_proto(),
11843 language_server_id: symbol.source_language_server_id.to_proto(),
11844 name: symbol.name.clone(),
11845 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11846 start: Some(proto::PointUtf16 {
11847 row: symbol.range.start.0.row,
11848 column: symbol.range.start.0.column,
11849 }),
11850 end: Some(proto::PointUtf16 {
11851 row: symbol.range.end.0.row,
11852 column: symbol.range.end.0.column,
11853 }),
11854 worktree_id: Default::default(),
11855 path: Default::default(),
11856 signature: Default::default(),
11857 container_name: symbol.container_name.clone(),
11858 };
11859 match &symbol.path {
11860 SymbolLocation::InProject(path) => {
11861 result.worktree_id = path.worktree_id.to_proto();
11862 result.path = path.path.to_proto();
11863 }
11864 SymbolLocation::OutsideProject {
11865 abs_path,
11866 signature,
11867 } => {
11868 result.path = abs_path.to_string_lossy().into_owned();
11869 result.signature = signature.to_vec();
11870 }
11871 }
11872 result
11873 }
11874
11875 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11876 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11877 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11878 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11879
11880 let path = if serialized_symbol.signature.is_empty() {
11881 SymbolLocation::InProject(ProjectPath {
11882 worktree_id,
11883 path: RelPath::from_proto(&serialized_symbol.path)
11884 .context("invalid symbol path")?,
11885 })
11886 } else {
11887 SymbolLocation::OutsideProject {
11888 abs_path: Path::new(&serialized_symbol.path).into(),
11889 signature: serialized_symbol
11890 .signature
11891 .try_into()
11892 .map_err(|_| anyhow!("invalid signature"))?,
11893 }
11894 };
11895
11896 let start = serialized_symbol.start.context("invalid start")?;
11897 let end = serialized_symbol.end.context("invalid end")?;
11898 Ok(CoreSymbol {
11899 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11900 source_worktree_id,
11901 source_language_server_id: LanguageServerId::from_proto(
11902 serialized_symbol.language_server_id,
11903 ),
11904 path,
11905 name: serialized_symbol.name,
11906 range: Unclipped(PointUtf16::new(start.row, start.column))
11907 ..Unclipped(PointUtf16::new(end.row, end.column)),
11908 kind,
11909 container_name: serialized_symbol.container_name,
11910 })
11911 }
11912
11913 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11914 let mut serialized_completion = proto::Completion {
11915 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11916 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11917 new_text: completion.new_text.clone(),
11918 ..proto::Completion::default()
11919 };
11920 match &completion.source {
11921 CompletionSource::Lsp {
11922 insert_range,
11923 server_id,
11924 lsp_completion,
11925 lsp_defaults,
11926 resolved,
11927 } => {
11928 let (old_insert_start, old_insert_end) = insert_range
11929 .as_ref()
11930 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11931 .unzip();
11932
11933 serialized_completion.old_insert_start = old_insert_start;
11934 serialized_completion.old_insert_end = old_insert_end;
11935 serialized_completion.source = proto::completion::Source::Lsp as i32;
11936 serialized_completion.server_id = server_id.0 as u64;
11937 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11938 serialized_completion.lsp_defaults = lsp_defaults
11939 .as_deref()
11940 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11941 serialized_completion.resolved = *resolved;
11942 }
11943 CompletionSource::BufferWord {
11944 word_range,
11945 resolved,
11946 } => {
11947 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11948 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11949 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11950 serialized_completion.resolved = *resolved;
11951 }
11952 CompletionSource::Custom => {
11953 serialized_completion.source = proto::completion::Source::Custom as i32;
11954 serialized_completion.resolved = true;
11955 }
11956 CompletionSource::Dap { sort_text } => {
11957 serialized_completion.source = proto::completion::Source::Dap as i32;
11958 serialized_completion.sort_text = Some(sort_text.clone());
11959 }
11960 }
11961
11962 serialized_completion
11963 }
11964
11965 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11966 let old_replace_start = completion
11967 .old_replace_start
11968 .and_then(deserialize_anchor)
11969 .context("invalid old start")?;
11970 let old_replace_end = completion
11971 .old_replace_end
11972 .and_then(deserialize_anchor)
11973 .context("invalid old end")?;
11974 let insert_range = {
11975 match completion.old_insert_start.zip(completion.old_insert_end) {
11976 Some((start, end)) => {
11977 let start = deserialize_anchor(start).context("invalid insert old start")?;
11978 let end = deserialize_anchor(end).context("invalid insert old end")?;
11979 Some(start..end)
11980 }
11981 None => None,
11982 }
11983 };
11984 Ok(CoreCompletion {
11985 replace_range: old_replace_start..old_replace_end,
11986 new_text: completion.new_text,
11987 source: match proto::completion::Source::from_i32(completion.source) {
11988 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11989 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11990 insert_range,
11991 server_id: LanguageServerId::from_proto(completion.server_id),
11992 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11993 lsp_defaults: completion
11994 .lsp_defaults
11995 .as_deref()
11996 .map(serde_json::from_slice)
11997 .transpose()?,
11998 resolved: completion.resolved,
11999 },
12000 Some(proto::completion::Source::BufferWord) => {
12001 let word_range = completion
12002 .buffer_word_start
12003 .and_then(deserialize_anchor)
12004 .context("invalid buffer word start")?
12005 ..completion
12006 .buffer_word_end
12007 .and_then(deserialize_anchor)
12008 .context("invalid buffer word end")?;
12009 CompletionSource::BufferWord {
12010 word_range,
12011 resolved: completion.resolved,
12012 }
12013 }
12014 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12015 sort_text: completion
12016 .sort_text
12017 .context("expected sort text to exist")?,
12018 },
12019 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12020 },
12021 })
12022 }
12023
12024 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12025 let (kind, lsp_action) = match &action.lsp_action {
12026 LspAction::Action(code_action) => (
12027 proto::code_action::Kind::Action as i32,
12028 serde_json::to_vec(code_action).unwrap(),
12029 ),
12030 LspAction::Command(command) => (
12031 proto::code_action::Kind::Command as i32,
12032 serde_json::to_vec(command).unwrap(),
12033 ),
12034 LspAction::CodeLens(code_lens) => (
12035 proto::code_action::Kind::CodeLens as i32,
12036 serde_json::to_vec(code_lens).unwrap(),
12037 ),
12038 };
12039
12040 proto::CodeAction {
12041 server_id: action.server_id.0 as u64,
12042 start: Some(serialize_anchor(&action.range.start)),
12043 end: Some(serialize_anchor(&action.range.end)),
12044 lsp_action,
12045 kind,
12046 resolved: action.resolved,
12047 }
12048 }
12049
12050 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12051 let start = action
12052 .start
12053 .and_then(deserialize_anchor)
12054 .context("invalid start")?;
12055 let end = action
12056 .end
12057 .and_then(deserialize_anchor)
12058 .context("invalid end")?;
12059 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12060 Some(proto::code_action::Kind::Action) => {
12061 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12062 }
12063 Some(proto::code_action::Kind::Command) => {
12064 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12065 }
12066 Some(proto::code_action::Kind::CodeLens) => {
12067 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12068 }
12069 None => anyhow::bail!("Unknown action kind {}", action.kind),
12070 };
12071 Ok(CodeAction {
12072 server_id: LanguageServerId(action.server_id as usize),
12073 range: start..end,
12074 resolved: action.resolved,
12075 lsp_action,
12076 })
12077 }
12078
12079 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12080 match &formatting_result {
12081 Ok(_) => self.last_formatting_failure = None,
12082 Err(error) => {
12083 let error_string = format!("{error:#}");
12084 log::error!("Formatting failed: {error_string}");
12085 self.last_formatting_failure
12086 .replace(error_string.lines().join(" "));
12087 }
12088 }
12089 }
12090
12091 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12092 self.lsp_server_capabilities.remove(&for_server);
12093 self.semantic_token_config.remove_server_data(for_server);
12094 for lsp_data in self.lsp_data.values_mut() {
12095 lsp_data.remove_server_data(for_server);
12096 }
12097 if let Some(local) = self.as_local_mut() {
12098 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12099 local
12100 .workspace_pull_diagnostics_result_ids
12101 .remove(&for_server);
12102 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12103 buffer_servers.remove(&for_server);
12104 }
12105 }
12106 }
12107
12108 pub fn result_id_for_buffer_pull(
12109 &self,
12110 server_id: LanguageServerId,
12111 buffer_id: BufferId,
12112 registration_id: &Option<SharedString>,
12113 cx: &App,
12114 ) -> Option<SharedString> {
12115 let abs_path = self
12116 .buffer_store
12117 .read(cx)
12118 .get(buffer_id)
12119 .and_then(|b| File::from_dyn(b.read(cx).file()))
12120 .map(|f| f.abs_path(cx))?;
12121 self.as_local()?
12122 .buffer_pull_diagnostics_result_ids
12123 .get(&server_id)?
12124 .get(registration_id)?
12125 .get(&abs_path)?
12126 .clone()
12127 }
12128
12129 /// Gets all result_ids for a workspace diagnostics pull request.
12130 /// 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.
12131 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12132 pub fn result_ids_for_workspace_refresh(
12133 &self,
12134 server_id: LanguageServerId,
12135 registration_id: &Option<SharedString>,
12136 ) -> HashMap<PathBuf, SharedString> {
12137 let Some(local) = self.as_local() else {
12138 return HashMap::default();
12139 };
12140 local
12141 .workspace_pull_diagnostics_result_ids
12142 .get(&server_id)
12143 .into_iter()
12144 .filter_map(|diagnostics| diagnostics.get(registration_id))
12145 .flatten()
12146 .filter_map(|(abs_path, result_id)| {
12147 let result_id = local
12148 .buffer_pull_diagnostics_result_ids
12149 .get(&server_id)
12150 .and_then(|buffer_ids_result_ids| {
12151 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12152 })
12153 .cloned()
12154 .flatten()
12155 .or_else(|| result_id.clone())?;
12156 Some((abs_path.clone(), result_id))
12157 })
12158 .collect()
12159 }
12160
12161 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12162 if let Some(LanguageServerState::Running {
12163 workspace_diagnostics_refresh_tasks,
12164 ..
12165 }) = self
12166 .as_local_mut()
12167 .and_then(|local| local.language_servers.get_mut(&server_id))
12168 {
12169 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12170 diagnostics.refresh_tx.try_send(()).ok();
12171 }
12172 }
12173 }
12174
12175 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12176 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12177 /// which requires refreshing both workspace and document diagnostics.
12178 pub fn pull_document_diagnostics_for_server(
12179 &mut self,
12180 server_id: LanguageServerId,
12181 source_buffer_id: Option<BufferId>,
12182 cx: &mut Context<Self>,
12183 ) -> Shared<Task<()>> {
12184 let Some(local) = self.as_local_mut() else {
12185 return Task::ready(()).shared();
12186 };
12187 let mut buffers_to_refresh = HashSet::default();
12188 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12189 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12190 buffers_to_refresh.insert(*buffer_id);
12191 }
12192 }
12193
12194 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12195 }
12196
12197 pub fn pull_document_diagnostics_for_buffer_edit(
12198 &mut self,
12199 buffer_id: BufferId,
12200 cx: &mut Context<Self>,
12201 ) {
12202 let Some(local) = self.as_local_mut() else {
12203 return;
12204 };
12205 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12206 else {
12207 return;
12208 };
12209 for server_id in languages_servers {
12210 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12211 }
12212 }
12213
12214 fn apply_workspace_diagnostic_report(
12215 &mut self,
12216 server_id: LanguageServerId,
12217 report: lsp::WorkspaceDiagnosticReportResult,
12218 registration_id: Option<SharedString>,
12219 cx: &mut Context<Self>,
12220 ) {
12221 let mut workspace_diagnostics =
12222 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12223 report,
12224 server_id,
12225 registration_id,
12226 );
12227 workspace_diagnostics.retain(|d| match &d.diagnostics {
12228 LspPullDiagnostics::Response {
12229 server_id,
12230 registration_id,
12231 ..
12232 } => self.diagnostic_registration_exists(*server_id, registration_id),
12233 LspPullDiagnostics::Default => false,
12234 });
12235 let mut unchanged_buffers = HashMap::default();
12236 let workspace_diagnostics_updates = workspace_diagnostics
12237 .into_iter()
12238 .filter_map(
12239 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12240 LspPullDiagnostics::Response {
12241 server_id,
12242 uri,
12243 diagnostics,
12244 registration_id,
12245 } => Some((
12246 server_id,
12247 uri,
12248 diagnostics,
12249 workspace_diagnostics.version,
12250 registration_id,
12251 )),
12252 LspPullDiagnostics::Default => None,
12253 },
12254 )
12255 .fold(
12256 HashMap::default(),
12257 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12258 let (result_id, diagnostics) = match diagnostics {
12259 PulledDiagnostics::Unchanged { result_id } => {
12260 unchanged_buffers
12261 .entry(new_registration_id.clone())
12262 .or_insert_with(HashSet::default)
12263 .insert(uri.clone());
12264 (Some(result_id), Vec::new())
12265 }
12266 PulledDiagnostics::Changed {
12267 result_id,
12268 diagnostics,
12269 } => (result_id, diagnostics),
12270 };
12271 let disk_based_sources = Cow::Owned(
12272 self.language_server_adapter_for_id(server_id)
12273 .as_ref()
12274 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12275 .unwrap_or(&[])
12276 .to_vec(),
12277 );
12278
12279 let Some(abs_path) = uri.to_file_path().ok() else {
12280 return acc;
12281 };
12282 let Some((worktree, relative_path)) =
12283 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12284 else {
12285 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12286 return acc;
12287 };
12288 let worktree_id = worktree.read(cx).id();
12289 let project_path = ProjectPath {
12290 worktree_id,
12291 path: relative_path,
12292 };
12293 if let Some(local_lsp_store) = self.as_local_mut() {
12294 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12295 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12296 }
12297 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12298 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12299 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12300 acc.entry(server_id)
12301 .or_insert_with(HashMap::default)
12302 .entry(new_registration_id.clone())
12303 .or_insert_with(Vec::new)
12304 .push(DocumentDiagnosticsUpdate {
12305 server_id,
12306 diagnostics: lsp::PublishDiagnosticsParams {
12307 uri,
12308 diagnostics,
12309 version,
12310 },
12311 result_id: result_id.map(SharedString::new),
12312 disk_based_sources,
12313 registration_id: new_registration_id,
12314 });
12315 }
12316 acc
12317 },
12318 );
12319
12320 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12321 for (registration_id, diagnostic_updates) in diagnostic_updates {
12322 self.merge_lsp_diagnostics(
12323 DiagnosticSourceKind::Pulled,
12324 diagnostic_updates,
12325 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12326 DiagnosticSourceKind::Pulled => {
12327 old_diagnostic.registration_id != registration_id
12328 || unchanged_buffers
12329 .get(&old_diagnostic.registration_id)
12330 .is_some_and(|unchanged_buffers| {
12331 unchanged_buffers.contains(&document_uri)
12332 })
12333 }
12334 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12335 },
12336 cx,
12337 )
12338 .log_err();
12339 }
12340 }
12341 }
12342
12343 fn register_server_capabilities(
12344 &mut self,
12345 server_id: LanguageServerId,
12346 params: lsp::RegistrationParams,
12347 cx: &mut Context<Self>,
12348 ) -> anyhow::Result<()> {
12349 let server = self
12350 .language_server_for_id(server_id)
12351 .with_context(|| format!("no server {server_id} found"))?;
12352 for reg in params.registrations {
12353 match reg.method.as_str() {
12354 "workspace/didChangeWatchedFiles" => {
12355 if let Some(options) = reg.register_options {
12356 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12357 let caps = serde_json::from_value(options)?;
12358 local_lsp_store
12359 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12360 true
12361 } else {
12362 false
12363 };
12364 if notify {
12365 notify_server_capabilities_updated(&server, cx);
12366 }
12367 }
12368 }
12369 "workspace/didChangeConfiguration" => {
12370 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12371 }
12372 "workspace/didChangeWorkspaceFolders" => {
12373 // In this case register options is an empty object, we can ignore it
12374 let caps = lsp::WorkspaceFoldersServerCapabilities {
12375 supported: Some(true),
12376 change_notifications: Some(OneOf::Right(reg.id)),
12377 };
12378 server.update_capabilities(|capabilities| {
12379 capabilities
12380 .workspace
12381 .get_or_insert_default()
12382 .workspace_folders = Some(caps);
12383 });
12384 notify_server_capabilities_updated(&server, cx);
12385 }
12386 "workspace/symbol" => {
12387 let options = parse_register_capabilities(reg)?;
12388 server.update_capabilities(|capabilities| {
12389 capabilities.workspace_symbol_provider = Some(options);
12390 });
12391 notify_server_capabilities_updated(&server, cx);
12392 }
12393 "workspace/fileOperations" => {
12394 if let Some(options) = reg.register_options {
12395 let caps = serde_json::from_value(options)?;
12396 server.update_capabilities(|capabilities| {
12397 capabilities
12398 .workspace
12399 .get_or_insert_default()
12400 .file_operations = Some(caps);
12401 });
12402 notify_server_capabilities_updated(&server, cx);
12403 }
12404 }
12405 "workspace/executeCommand" => {
12406 if let Some(options) = reg.register_options {
12407 let options = serde_json::from_value(options)?;
12408 server.update_capabilities(|capabilities| {
12409 capabilities.execute_command_provider = Some(options);
12410 });
12411 notify_server_capabilities_updated(&server, cx);
12412 }
12413 }
12414 "textDocument/rangeFormatting" => {
12415 let options = parse_register_capabilities(reg)?;
12416 server.update_capabilities(|capabilities| {
12417 capabilities.document_range_formatting_provider = Some(options);
12418 });
12419 notify_server_capabilities_updated(&server, cx);
12420 }
12421 "textDocument/onTypeFormatting" => {
12422 if let Some(options) = reg
12423 .register_options
12424 .map(serde_json::from_value)
12425 .transpose()?
12426 {
12427 server.update_capabilities(|capabilities| {
12428 capabilities.document_on_type_formatting_provider = Some(options);
12429 });
12430 notify_server_capabilities_updated(&server, cx);
12431 }
12432 }
12433 "textDocument/formatting" => {
12434 let options = parse_register_capabilities(reg)?;
12435 server.update_capabilities(|capabilities| {
12436 capabilities.document_formatting_provider = Some(options);
12437 });
12438 notify_server_capabilities_updated(&server, cx);
12439 }
12440 "textDocument/rename" => {
12441 let options = parse_register_capabilities(reg)?;
12442 server.update_capabilities(|capabilities| {
12443 capabilities.rename_provider = Some(options);
12444 });
12445 notify_server_capabilities_updated(&server, cx);
12446 }
12447 "textDocument/inlayHint" => {
12448 let options = parse_register_capabilities(reg)?;
12449 server.update_capabilities(|capabilities| {
12450 capabilities.inlay_hint_provider = Some(options);
12451 });
12452 notify_server_capabilities_updated(&server, cx);
12453 }
12454 "textDocument/documentSymbol" => {
12455 let options = parse_register_capabilities(reg)?;
12456 server.update_capabilities(|capabilities| {
12457 capabilities.document_symbol_provider = Some(options);
12458 });
12459 notify_server_capabilities_updated(&server, cx);
12460 }
12461 "textDocument/codeAction" => {
12462 let options = parse_register_capabilities(reg)?;
12463 let provider = match options {
12464 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12465 OneOf::Right(caps) => caps,
12466 };
12467 server.update_capabilities(|capabilities| {
12468 capabilities.code_action_provider = Some(provider);
12469 });
12470 notify_server_capabilities_updated(&server, cx);
12471 }
12472 "textDocument/definition" => {
12473 let options = parse_register_capabilities(reg)?;
12474 server.update_capabilities(|capabilities| {
12475 capabilities.definition_provider = Some(options);
12476 });
12477 notify_server_capabilities_updated(&server, cx);
12478 }
12479 "textDocument/completion" => {
12480 if let Some(caps) = reg
12481 .register_options
12482 .map(serde_json::from_value::<CompletionOptions>)
12483 .transpose()?
12484 {
12485 server.update_capabilities(|capabilities| {
12486 capabilities.completion_provider = Some(caps.clone());
12487 });
12488
12489 if let Some(local) = self.as_local() {
12490 let mut buffers_with_language_server = Vec::new();
12491 for handle in self.buffer_store.read(cx).buffers() {
12492 let buffer_id = handle.read(cx).remote_id();
12493 if local
12494 .buffers_opened_in_servers
12495 .get(&buffer_id)
12496 .filter(|s| s.contains(&server_id))
12497 .is_some()
12498 {
12499 buffers_with_language_server.push(handle);
12500 }
12501 }
12502 let triggers = caps
12503 .trigger_characters
12504 .unwrap_or_default()
12505 .into_iter()
12506 .collect::<BTreeSet<_>>();
12507 for handle in buffers_with_language_server {
12508 let triggers = triggers.clone();
12509 let _ = handle.update(cx, move |buffer, cx| {
12510 buffer.set_completion_triggers(server_id, triggers, cx);
12511 });
12512 }
12513 }
12514 notify_server_capabilities_updated(&server, cx);
12515 }
12516 }
12517 "textDocument/hover" => {
12518 let options = parse_register_capabilities(reg)?;
12519 let provider = match options {
12520 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12521 OneOf::Right(caps) => caps,
12522 };
12523 server.update_capabilities(|capabilities| {
12524 capabilities.hover_provider = Some(provider);
12525 });
12526 notify_server_capabilities_updated(&server, cx);
12527 }
12528 "textDocument/signatureHelp" => {
12529 if let Some(caps) = reg
12530 .register_options
12531 .map(serde_json::from_value)
12532 .transpose()?
12533 {
12534 server.update_capabilities(|capabilities| {
12535 capabilities.signature_help_provider = Some(caps);
12536 });
12537 notify_server_capabilities_updated(&server, cx);
12538 }
12539 }
12540 "textDocument/didChange" => {
12541 if let Some(sync_kind) = reg
12542 .register_options
12543 .and_then(|opts| opts.get("syncKind").cloned())
12544 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12545 .transpose()?
12546 {
12547 server.update_capabilities(|capabilities| {
12548 let mut sync_options =
12549 Self::take_text_document_sync_options(capabilities);
12550 sync_options.change = Some(sync_kind);
12551 capabilities.text_document_sync =
12552 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12553 });
12554 notify_server_capabilities_updated(&server, cx);
12555 }
12556 }
12557 "textDocument/didSave" => {
12558 if let Some(include_text) = reg
12559 .register_options
12560 .map(|opts| {
12561 let transpose = opts
12562 .get("includeText")
12563 .cloned()
12564 .map(serde_json::from_value::<Option<bool>>)
12565 .transpose();
12566 match transpose {
12567 Ok(value) => Ok(value.flatten()),
12568 Err(e) => Err(e),
12569 }
12570 })
12571 .transpose()?
12572 {
12573 server.update_capabilities(|capabilities| {
12574 let mut sync_options =
12575 Self::take_text_document_sync_options(capabilities);
12576 sync_options.save =
12577 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12578 include_text,
12579 }));
12580 capabilities.text_document_sync =
12581 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12582 });
12583 notify_server_capabilities_updated(&server, cx);
12584 }
12585 }
12586 "textDocument/codeLens" => {
12587 if let Some(caps) = reg
12588 .register_options
12589 .map(serde_json::from_value)
12590 .transpose()?
12591 {
12592 server.update_capabilities(|capabilities| {
12593 capabilities.code_lens_provider = Some(caps);
12594 });
12595 notify_server_capabilities_updated(&server, cx);
12596 }
12597 }
12598 "textDocument/diagnostic" => {
12599 if let Some(caps) = reg
12600 .register_options
12601 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12602 .transpose()?
12603 {
12604 let local = self
12605 .as_local_mut()
12606 .context("Expected LSP Store to be local")?;
12607 let state = local
12608 .language_servers
12609 .get_mut(&server_id)
12610 .context("Could not obtain Language Servers state")?;
12611 local
12612 .language_server_dynamic_registrations
12613 .entry(server_id)
12614 .or_default()
12615 .diagnostics
12616 .insert(Some(reg.id.clone()), caps.clone());
12617
12618 let supports_workspace_diagnostics =
12619 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12620 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12621 diagnostic_options.workspace_diagnostics
12622 }
12623 DiagnosticServerCapabilities::RegistrationOptions(
12624 diagnostic_registration_options,
12625 ) => {
12626 diagnostic_registration_options
12627 .diagnostic_options
12628 .workspace_diagnostics
12629 }
12630 };
12631
12632 if supports_workspace_diagnostics(&caps) {
12633 if let LanguageServerState::Running {
12634 workspace_diagnostics_refresh_tasks,
12635 ..
12636 } = state
12637 && let Some(task) = lsp_workspace_diagnostics_refresh(
12638 Some(reg.id.clone()),
12639 caps.clone(),
12640 server.clone(),
12641 cx,
12642 )
12643 {
12644 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12645 }
12646 }
12647
12648 server.update_capabilities(|capabilities| {
12649 capabilities.diagnostic_provider = Some(caps);
12650 });
12651
12652 notify_server_capabilities_updated(&server, cx);
12653
12654 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12655 }
12656 }
12657 "textDocument/documentColor" => {
12658 let options = parse_register_capabilities(reg)?;
12659 let provider = match options {
12660 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12661 OneOf::Right(caps) => caps,
12662 };
12663 server.update_capabilities(|capabilities| {
12664 capabilities.color_provider = Some(provider);
12665 });
12666 notify_server_capabilities_updated(&server, cx);
12667 }
12668 "textDocument/foldingRange" => {
12669 let options = parse_register_capabilities(reg)?;
12670 let provider = match options {
12671 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12672 OneOf::Right(caps) => caps,
12673 };
12674 server.update_capabilities(|capabilities| {
12675 capabilities.folding_range_provider = Some(provider);
12676 });
12677 notify_server_capabilities_updated(&server, cx);
12678 }
12679 _ => log::warn!("unhandled capability registration: {reg:?}"),
12680 }
12681 }
12682
12683 Ok(())
12684 }
12685
12686 fn unregister_server_capabilities(
12687 &mut self,
12688 server_id: LanguageServerId,
12689 params: lsp::UnregistrationParams,
12690 cx: &mut Context<Self>,
12691 ) -> anyhow::Result<()> {
12692 let server = self
12693 .language_server_for_id(server_id)
12694 .with_context(|| format!("no server {server_id} found"))?;
12695 for unreg in params.unregisterations.iter() {
12696 match unreg.method.as_str() {
12697 "workspace/didChangeWatchedFiles" => {
12698 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12699 local_lsp_store
12700 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12701 true
12702 } else {
12703 false
12704 };
12705 if notify {
12706 notify_server_capabilities_updated(&server, cx);
12707 }
12708 }
12709 "workspace/didChangeConfiguration" => {
12710 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12711 }
12712 "workspace/didChangeWorkspaceFolders" => {
12713 server.update_capabilities(|capabilities| {
12714 capabilities
12715 .workspace
12716 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12717 workspace_folders: None,
12718 file_operations: None,
12719 })
12720 .workspace_folders = None;
12721 });
12722 notify_server_capabilities_updated(&server, cx);
12723 }
12724 "workspace/symbol" => {
12725 server.update_capabilities(|capabilities| {
12726 capabilities.workspace_symbol_provider = None
12727 });
12728 notify_server_capabilities_updated(&server, cx);
12729 }
12730 "workspace/fileOperations" => {
12731 server.update_capabilities(|capabilities| {
12732 capabilities
12733 .workspace
12734 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12735 workspace_folders: None,
12736 file_operations: None,
12737 })
12738 .file_operations = None;
12739 });
12740 notify_server_capabilities_updated(&server, cx);
12741 }
12742 "workspace/executeCommand" => {
12743 server.update_capabilities(|capabilities| {
12744 capabilities.execute_command_provider = None;
12745 });
12746 notify_server_capabilities_updated(&server, cx);
12747 }
12748 "textDocument/rangeFormatting" => {
12749 server.update_capabilities(|capabilities| {
12750 capabilities.document_range_formatting_provider = None
12751 });
12752 notify_server_capabilities_updated(&server, cx);
12753 }
12754 "textDocument/onTypeFormatting" => {
12755 server.update_capabilities(|capabilities| {
12756 capabilities.document_on_type_formatting_provider = None;
12757 });
12758 notify_server_capabilities_updated(&server, cx);
12759 }
12760 "textDocument/formatting" => {
12761 server.update_capabilities(|capabilities| {
12762 capabilities.document_formatting_provider = None;
12763 });
12764 notify_server_capabilities_updated(&server, cx);
12765 }
12766 "textDocument/rename" => {
12767 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12768 notify_server_capabilities_updated(&server, cx);
12769 }
12770 "textDocument/codeAction" => {
12771 server.update_capabilities(|capabilities| {
12772 capabilities.code_action_provider = None;
12773 });
12774 notify_server_capabilities_updated(&server, cx);
12775 }
12776 "textDocument/definition" => {
12777 server.update_capabilities(|capabilities| {
12778 capabilities.definition_provider = None;
12779 });
12780 notify_server_capabilities_updated(&server, cx);
12781 }
12782 "textDocument/completion" => {
12783 server.update_capabilities(|capabilities| {
12784 capabilities.completion_provider = None;
12785 });
12786 notify_server_capabilities_updated(&server, cx);
12787 }
12788 "textDocument/hover" => {
12789 server.update_capabilities(|capabilities| {
12790 capabilities.hover_provider = None;
12791 });
12792 notify_server_capabilities_updated(&server, cx);
12793 }
12794 "textDocument/signatureHelp" => {
12795 server.update_capabilities(|capabilities| {
12796 capabilities.signature_help_provider = None;
12797 });
12798 notify_server_capabilities_updated(&server, cx);
12799 }
12800 "textDocument/didChange" => {
12801 server.update_capabilities(|capabilities| {
12802 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12803 sync_options.change = None;
12804 capabilities.text_document_sync =
12805 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12806 });
12807 notify_server_capabilities_updated(&server, cx);
12808 }
12809 "textDocument/didSave" => {
12810 server.update_capabilities(|capabilities| {
12811 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12812 sync_options.save = None;
12813 capabilities.text_document_sync =
12814 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12815 });
12816 notify_server_capabilities_updated(&server, cx);
12817 }
12818 "textDocument/codeLens" => {
12819 server.update_capabilities(|capabilities| {
12820 capabilities.code_lens_provider = None;
12821 });
12822 notify_server_capabilities_updated(&server, cx);
12823 }
12824 "textDocument/diagnostic" => {
12825 let local = self
12826 .as_local_mut()
12827 .context("Expected LSP Store to be local")?;
12828
12829 let state = local
12830 .language_servers
12831 .get_mut(&server_id)
12832 .context("Could not obtain Language Servers state")?;
12833 let registrations = local
12834 .language_server_dynamic_registrations
12835 .get_mut(&server_id)
12836 .with_context(|| {
12837 format!("Expected dynamic registration to exist for server {server_id}")
12838 })?;
12839 registrations.diagnostics
12840 .remove(&Some(unreg.id.clone()))
12841 .with_context(|| format!(
12842 "Attempted to unregister non-existent diagnostic registration with ID {}",
12843 unreg.id)
12844 )?;
12845 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12846
12847 if let LanguageServerState::Running {
12848 workspace_diagnostics_refresh_tasks,
12849 ..
12850 } = state
12851 {
12852 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12853 }
12854
12855 self.clear_unregistered_diagnostics(
12856 server_id,
12857 SharedString::from(unreg.id.clone()),
12858 cx,
12859 )?;
12860
12861 if removed_last_diagnostic_provider {
12862 server.update_capabilities(|capabilities| {
12863 debug_assert!(capabilities.diagnostic_provider.is_some());
12864 capabilities.diagnostic_provider = None;
12865 });
12866 }
12867
12868 notify_server_capabilities_updated(&server, cx);
12869 }
12870 "textDocument/documentColor" => {
12871 server.update_capabilities(|capabilities| {
12872 capabilities.color_provider = None;
12873 });
12874 notify_server_capabilities_updated(&server, cx);
12875 }
12876 "textDocument/foldingRange" => {
12877 server.update_capabilities(|capabilities| {
12878 capabilities.folding_range_provider = None;
12879 });
12880 notify_server_capabilities_updated(&server, cx);
12881 }
12882 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12883 }
12884 }
12885
12886 Ok(())
12887 }
12888
12889 fn clear_unregistered_diagnostics(
12890 &mut self,
12891 server_id: LanguageServerId,
12892 cleared_registration_id: SharedString,
12893 cx: &mut Context<Self>,
12894 ) -> anyhow::Result<()> {
12895 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12896
12897 self.buffer_store.update(cx, |buffer_store, cx| {
12898 for buffer_handle in buffer_store.buffers() {
12899 let buffer = buffer_handle.read(cx);
12900 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12901 let Some(abs_path) = abs_path else {
12902 continue;
12903 };
12904 affected_abs_paths.insert(abs_path);
12905 }
12906 });
12907
12908 let local = self.as_local().context("Expected LSP Store to be local")?;
12909 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12910 let Some(worktree) = self
12911 .worktree_store
12912 .read(cx)
12913 .worktree_for_id(*worktree_id, cx)
12914 else {
12915 continue;
12916 };
12917
12918 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12919 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12920 let has_matching_registration =
12921 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12922 entry.diagnostic.registration_id.as_ref()
12923 == Some(&cleared_registration_id)
12924 });
12925 if has_matching_registration {
12926 let abs_path = worktree.read(cx).absolutize(rel_path);
12927 affected_abs_paths.insert(abs_path);
12928 }
12929 }
12930 }
12931 }
12932
12933 if affected_abs_paths.is_empty() {
12934 return Ok(());
12935 }
12936
12937 // Send a fake diagnostic update which clears the state for the registration ID
12938 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12939 affected_abs_paths
12940 .into_iter()
12941 .map(|abs_path| DocumentDiagnosticsUpdate {
12942 diagnostics: DocumentDiagnostics {
12943 diagnostics: Vec::new(),
12944 document_abs_path: abs_path,
12945 version: None,
12946 },
12947 result_id: None,
12948 registration_id: Some(cleared_registration_id.clone()),
12949 server_id,
12950 disk_based_sources: Cow::Borrowed(&[]),
12951 })
12952 .collect();
12953
12954 let merge_registration_id = cleared_registration_id.clone();
12955 self.merge_diagnostic_entries(
12956 clears,
12957 move |_, diagnostic, _| {
12958 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12959 diagnostic.registration_id != Some(merge_registration_id.clone())
12960 } else {
12961 true
12962 }
12963 },
12964 cx,
12965 )?;
12966
12967 Ok(())
12968 }
12969
12970 async fn deduplicate_range_based_lsp_requests<T>(
12971 lsp_store: &Entity<Self>,
12972 server_id: Option<LanguageServerId>,
12973 lsp_request_id: LspRequestId,
12974 proto_request: &T::ProtoRequest,
12975 range: Range<Anchor>,
12976 cx: &mut AsyncApp,
12977 ) -> Result<()>
12978 where
12979 T: LspCommand,
12980 T::ProtoRequest: proto::LspRequestMessage,
12981 {
12982 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12983 let version = deserialize_version(proto_request.buffer_version());
12984 let buffer = lsp_store.update(cx, |this, cx| {
12985 this.buffer_store.read(cx).get_existing(buffer_id)
12986 })?;
12987 buffer
12988 .update(cx, |buffer, _| buffer.wait_for_version(version))
12989 .await?;
12990 lsp_store.update(cx, |lsp_store, cx| {
12991 let buffer_snapshot = buffer.read(cx).snapshot();
12992 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12993 let chunks_queried_for = lsp_data
12994 .inlay_hints
12995 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12996 .collect::<Vec<_>>();
12997 match chunks_queried_for.as_slice() {
12998 &[chunk] => {
12999 let key = LspKey {
13000 request_type: TypeId::of::<T>(),
13001 server_queried: server_id,
13002 };
13003 let previous_request = lsp_data
13004 .chunk_lsp_requests
13005 .entry(key)
13006 .or_default()
13007 .insert(chunk, lsp_request_id);
13008 if let Some((previous_request, running_requests)) =
13009 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13010 {
13011 running_requests.remove(&previous_request);
13012 }
13013 }
13014 _ambiguous_chunks => {
13015 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13016 // there, a buffer version-based check will be performed and outdated requests discarded.
13017 }
13018 }
13019 anyhow::Ok(())
13020 })?;
13021
13022 Ok(())
13023 }
13024
13025 async fn query_lsp_locally<T>(
13026 lsp_store: Entity<Self>,
13027 for_server_id: Option<LanguageServerId>,
13028 sender_id: proto::PeerId,
13029 lsp_request_id: LspRequestId,
13030 proto_request: T::ProtoRequest,
13031 position: Option<Anchor>,
13032 cx: &mut AsyncApp,
13033 ) -> Result<()>
13034 where
13035 T: LspCommand + Clone,
13036 T::ProtoRequest: proto::LspRequestMessage,
13037 <T::ProtoRequest as proto::RequestMessage>::Response:
13038 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13039 {
13040 let (buffer_version, buffer) =
13041 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13042 let request =
13043 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13044 let key = LspKey {
13045 request_type: TypeId::of::<T>(),
13046 server_queried: for_server_id,
13047 };
13048 lsp_store.update(cx, |lsp_store, cx| {
13049 let request_task = match for_server_id {
13050 Some(server_id) => {
13051 let server_task = lsp_store.request_lsp(
13052 buffer.clone(),
13053 LanguageServerToQuery::Other(server_id),
13054 request.clone(),
13055 cx,
13056 );
13057 cx.background_spawn(async move {
13058 let mut responses = Vec::new();
13059 match server_task.await {
13060 Ok(response) => responses.push((server_id, response)),
13061 // rust-analyzer likes to error with this when its still loading up
13062 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13063 Err(e) => log::error!(
13064 "Error handling response for request {request:?}: {e:#}"
13065 ),
13066 }
13067 responses
13068 })
13069 }
13070 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13071 };
13072 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13073 if T::ProtoRequest::stop_previous_requests() {
13074 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13075 lsp_requests.clear();
13076 }
13077 }
13078 lsp_data.lsp_requests.entry(key).or_default().insert(
13079 lsp_request_id,
13080 cx.spawn(async move |lsp_store, cx| {
13081 let response = request_task.await;
13082 lsp_store
13083 .update(cx, |lsp_store, cx| {
13084 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13085 {
13086 let response = response
13087 .into_iter()
13088 .map(|(server_id, response)| {
13089 (
13090 server_id.to_proto(),
13091 T::response_to_proto(
13092 response,
13093 lsp_store,
13094 sender_id,
13095 &buffer_version,
13096 cx,
13097 )
13098 .into(),
13099 )
13100 })
13101 .collect::<HashMap<_, _>>();
13102 match client.send_lsp_response::<T::ProtoRequest>(
13103 project_id,
13104 lsp_request_id,
13105 response,
13106 ) {
13107 Ok(()) => {}
13108 Err(e) => {
13109 log::error!("Failed to send LSP response: {e:#}",)
13110 }
13111 }
13112 }
13113 })
13114 .ok();
13115 }),
13116 );
13117 });
13118 Ok(())
13119 }
13120
13121 async fn wait_for_buffer_version<T>(
13122 lsp_store: &Entity<Self>,
13123 proto_request: &T::ProtoRequest,
13124 cx: &mut AsyncApp,
13125 ) -> Result<(Global, Entity<Buffer>)>
13126 where
13127 T: LspCommand,
13128 T::ProtoRequest: proto::LspRequestMessage,
13129 {
13130 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13131 let version = deserialize_version(proto_request.buffer_version());
13132 let buffer = lsp_store.update(cx, |this, cx| {
13133 this.buffer_store.read(cx).get_existing(buffer_id)
13134 })?;
13135 buffer
13136 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13137 .await?;
13138 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13139 Ok((buffer_version, buffer))
13140 }
13141
13142 fn take_text_document_sync_options(
13143 capabilities: &mut lsp::ServerCapabilities,
13144 ) -> lsp::TextDocumentSyncOptions {
13145 match capabilities.text_document_sync.take() {
13146 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13147 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13148 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13149 sync_options.change = Some(sync_kind);
13150 sync_options
13151 }
13152 None => lsp::TextDocumentSyncOptions::default(),
13153 }
13154 }
13155
13156 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13157 self.downstream_client.clone()
13158 }
13159
13160 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13161 self.worktree_store.clone()
13162 }
13163
13164 /// Gets what's stored in the LSP data for the given buffer.
13165 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13166 self.lsp_data.get_mut(&buffer_id)
13167 }
13168
13169 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13170 /// new [`BufferLspData`] will be created to replace the previous state.
13171 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13172 let (buffer_id, buffer_version) =
13173 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13174 let lsp_data = self
13175 .lsp_data
13176 .entry(buffer_id)
13177 .or_insert_with(|| BufferLspData::new(buffer, cx));
13178 if buffer_version.changed_since(&lsp_data.buffer_version) {
13179 // To send delta requests for semantic tokens, the previous tokens
13180 // need to be kept between buffer changes.
13181 let semantic_tokens = lsp_data.semantic_tokens.take();
13182 *lsp_data = BufferLspData::new(buffer, cx);
13183 lsp_data.semantic_tokens = semantic_tokens;
13184 }
13185 lsp_data
13186 }
13187}
13188
13189// Registration with registerOptions as null, should fallback to true.
13190// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13191fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13192 reg: lsp::Registration,
13193) -> Result<OneOf<bool, T>> {
13194 Ok(match reg.register_options {
13195 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13196 None => OneOf::Left(true),
13197 })
13198}
13199
13200fn subscribe_to_binary_statuses(
13201 languages: &Arc<LanguageRegistry>,
13202 cx: &mut Context<'_, LspStore>,
13203) -> Task<()> {
13204 let mut server_statuses = languages.language_server_binary_statuses();
13205 cx.spawn(async move |lsp_store, cx| {
13206 while let Some((server_name, binary_status)) = server_statuses.next().await {
13207 if lsp_store
13208 .update(cx, |_, cx| {
13209 let mut message = None;
13210 let binary_status = match binary_status {
13211 BinaryStatus::None => proto::ServerBinaryStatus::None,
13212 BinaryStatus::CheckingForUpdate => {
13213 proto::ServerBinaryStatus::CheckingForUpdate
13214 }
13215 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13216 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13217 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13218 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13219 BinaryStatus::Failed { error } => {
13220 message = Some(error);
13221 proto::ServerBinaryStatus::Failed
13222 }
13223 };
13224 cx.emit(LspStoreEvent::LanguageServerUpdate {
13225 // Binary updates are about the binary that might not have any language server id at that point.
13226 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13227 language_server_id: LanguageServerId(0),
13228 name: Some(server_name),
13229 message: proto::update_language_server::Variant::StatusUpdate(
13230 proto::StatusUpdate {
13231 message,
13232 status: Some(proto::status_update::Status::Binary(
13233 binary_status as i32,
13234 )),
13235 },
13236 ),
13237 });
13238 })
13239 .is_err()
13240 {
13241 break;
13242 }
13243 }
13244 })
13245}
13246
13247fn lsp_workspace_diagnostics_refresh(
13248 registration_id: Option<String>,
13249 options: DiagnosticServerCapabilities,
13250 server: Arc<LanguageServer>,
13251 cx: &mut Context<'_, LspStore>,
13252) -> Option<WorkspaceRefreshTask> {
13253 let identifier = workspace_diagnostic_identifier(&options)?;
13254 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13255
13256 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13257 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13258 refresh_tx.try_send(()).ok();
13259
13260 let request_timeout = ProjectSettings::get_global(cx)
13261 .global_lsp_settings
13262 .get_request_timeout();
13263
13264 // 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.
13265 // This allows users to increase the duration if need be
13266 let timeout = if request_timeout != Duration::ZERO {
13267 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13268 } else {
13269 request_timeout
13270 };
13271
13272 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13273 let mut attempts = 0;
13274 let max_attempts = 50;
13275 let mut requests = 0;
13276
13277 loop {
13278 let Some(()) = refresh_rx.recv().await else {
13279 return;
13280 };
13281
13282 'request: loop {
13283 requests += 1;
13284 if attempts > max_attempts {
13285 log::error!(
13286 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13287 );
13288 return;
13289 }
13290 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13291 cx.background_executor()
13292 .timer(Duration::from_millis(backoff_millis))
13293 .await;
13294 attempts += 1;
13295
13296 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13297 lsp_store
13298 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13299 .into_iter()
13300 .filter_map(|(abs_path, result_id)| {
13301 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13302 Some(lsp::PreviousResultId {
13303 uri,
13304 value: result_id.to_string(),
13305 })
13306 })
13307 .collect()
13308 }) else {
13309 return;
13310 };
13311
13312 let token = if let Some(registration_id) = ®istration_id {
13313 format!(
13314 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13315 server.server_id(),
13316 )
13317 } else {
13318 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13319 };
13320
13321 progress_rx.try_recv().ok();
13322 let timer = server.request_timer(timeout).fuse();
13323 let progress = pin!(progress_rx.recv().fuse());
13324 let response_result = server
13325 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13326 lsp::WorkspaceDiagnosticParams {
13327 previous_result_ids,
13328 identifier: identifier.clone(),
13329 work_done_progress_params: Default::default(),
13330 partial_result_params: lsp::PartialResultParams {
13331 partial_result_token: Some(lsp::ProgressToken::String(token)),
13332 },
13333 },
13334 select(timer, progress).then(|either| match either {
13335 Either::Left((message, ..)) => ready(message).left_future(),
13336 Either::Right(..) => pending::<String>().right_future(),
13337 }),
13338 )
13339 .await;
13340
13341 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13342 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13343 match response_result {
13344 ConnectionResult::Timeout => {
13345 log::error!("Timeout during workspace diagnostics pull");
13346 continue 'request;
13347 }
13348 ConnectionResult::ConnectionReset => {
13349 log::error!("Server closed a workspace diagnostics pull request");
13350 continue 'request;
13351 }
13352 ConnectionResult::Result(Err(e)) => {
13353 log::error!("Error during workspace diagnostics pull: {e:#}");
13354 break 'request;
13355 }
13356 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13357 attempts = 0;
13358 if lsp_store
13359 .update(cx, |lsp_store, cx| {
13360 lsp_store.apply_workspace_diagnostic_report(
13361 server.server_id(),
13362 pulled_diagnostics,
13363 registration_id_shared.clone(),
13364 cx,
13365 )
13366 })
13367 .is_err()
13368 {
13369 return;
13370 }
13371 break 'request;
13372 }
13373 }
13374 }
13375 }
13376 });
13377
13378 Some(WorkspaceRefreshTask {
13379 refresh_tx,
13380 progress_tx,
13381 task: workspace_query_language_server,
13382 })
13383}
13384
13385fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13386 match &options {
13387 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13388 .identifier
13389 .as_deref()
13390 .map(SharedString::new),
13391 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13392 let diagnostic_options = ®istration_options.diagnostic_options;
13393 diagnostic_options
13394 .identifier
13395 .as_deref()
13396 .map(SharedString::new)
13397 }
13398 }
13399}
13400
13401fn workspace_diagnostic_identifier(
13402 options: &DiagnosticServerCapabilities,
13403) -> Option<Option<String>> {
13404 match &options {
13405 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13406 if !diagnostic_options.workspace_diagnostics {
13407 return None;
13408 }
13409 Some(diagnostic_options.identifier.clone())
13410 }
13411 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13412 let diagnostic_options = ®istration_options.diagnostic_options;
13413 if !diagnostic_options.workspace_diagnostics {
13414 return None;
13415 }
13416 Some(diagnostic_options.identifier.clone())
13417 }
13418 }
13419}
13420
13421fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13422 let CompletionSource::BufferWord {
13423 word_range,
13424 resolved,
13425 } = &mut completion.source
13426 else {
13427 return;
13428 };
13429 if *resolved {
13430 return;
13431 }
13432
13433 if completion.new_text
13434 != snapshot
13435 .text_for_range(word_range.clone())
13436 .collect::<String>()
13437 {
13438 return;
13439 }
13440
13441 let mut offset = 0;
13442 for chunk in snapshot.chunks(word_range.clone(), true) {
13443 let end_offset = offset + chunk.text.len();
13444 if let Some(highlight_id) = chunk.syntax_highlight_id {
13445 completion
13446 .label
13447 .runs
13448 .push((offset..end_offset, highlight_id));
13449 }
13450 offset = end_offset;
13451 }
13452 *resolved = true;
13453}
13454
13455impl EventEmitter<LspStoreEvent> for LspStore {}
13456
13457fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13458 hover
13459 .contents
13460 .retain(|hover_block| !hover_block.text.trim().is_empty());
13461 if hover.contents.is_empty() {
13462 None
13463 } else {
13464 Some(hover)
13465 }
13466}
13467
13468async fn populate_labels_for_completions(
13469 new_completions: Vec<CoreCompletion>,
13470 language: Option<Arc<Language>>,
13471 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13472) -> Vec<Completion> {
13473 let lsp_completions = new_completions
13474 .iter()
13475 .filter_map(|new_completion| {
13476 new_completion
13477 .source
13478 .lsp_completion(true)
13479 .map(|lsp_completion| lsp_completion.into_owned())
13480 })
13481 .collect::<Vec<_>>();
13482
13483 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13484 lsp_adapter
13485 .labels_for_completions(&lsp_completions, language)
13486 .await
13487 .log_err()
13488 .unwrap_or_default()
13489 } else {
13490 Vec::new()
13491 }
13492 .into_iter()
13493 .fuse();
13494
13495 let mut completions = Vec::new();
13496 for completion in new_completions {
13497 match completion.source.lsp_completion(true) {
13498 Some(lsp_completion) => {
13499 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13500
13501 let mut label = labels.next().flatten().unwrap_or_else(|| {
13502 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13503 });
13504 ensure_uniform_list_compatible_label(&mut label);
13505 completions.push(Completion {
13506 label,
13507 documentation,
13508 replace_range: completion.replace_range,
13509 new_text: completion.new_text,
13510 insert_text_mode: lsp_completion.insert_text_mode,
13511 source: completion.source,
13512 icon_path: None,
13513 confirm: None,
13514 match_start: None,
13515 snippet_deduplication_key: None,
13516 });
13517 }
13518 None => {
13519 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13520 ensure_uniform_list_compatible_label(&mut label);
13521 completions.push(Completion {
13522 label,
13523 documentation: None,
13524 replace_range: completion.replace_range,
13525 new_text: completion.new_text,
13526 source: completion.source,
13527 insert_text_mode: None,
13528 icon_path: None,
13529 confirm: None,
13530 match_start: None,
13531 snippet_deduplication_key: None,
13532 });
13533 }
13534 }
13535 }
13536 completions
13537}
13538
13539#[derive(Debug)]
13540pub enum LanguageServerToQuery {
13541 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13542 FirstCapable,
13543 /// Query a specific language server.
13544 Other(LanguageServerId),
13545}
13546
13547#[derive(Default)]
13548struct RenamePathsWatchedForServer {
13549 did_rename: Vec<RenameActionPredicate>,
13550 will_rename: Vec<RenameActionPredicate>,
13551}
13552
13553impl RenamePathsWatchedForServer {
13554 fn with_did_rename_patterns(
13555 mut self,
13556 did_rename: Option<&FileOperationRegistrationOptions>,
13557 ) -> Self {
13558 if let Some(did_rename) = did_rename {
13559 self.did_rename = did_rename
13560 .filters
13561 .iter()
13562 .filter_map(|filter| filter.try_into().log_err())
13563 .collect();
13564 }
13565 self
13566 }
13567 fn with_will_rename_patterns(
13568 mut self,
13569 will_rename: Option<&FileOperationRegistrationOptions>,
13570 ) -> Self {
13571 if let Some(will_rename) = will_rename {
13572 self.will_rename = will_rename
13573 .filters
13574 .iter()
13575 .filter_map(|filter| filter.try_into().log_err())
13576 .collect();
13577 }
13578 self
13579 }
13580
13581 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13582 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13583 }
13584 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13585 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13586 }
13587}
13588
13589impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13590 type Error = globset::Error;
13591 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13592 Ok(Self {
13593 kind: ops.pattern.matches.clone(),
13594 glob: GlobBuilder::new(&ops.pattern.glob)
13595 .case_insensitive(
13596 ops.pattern
13597 .options
13598 .as_ref()
13599 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13600 )
13601 .build()?
13602 .compile_matcher(),
13603 })
13604 }
13605}
13606struct RenameActionPredicate {
13607 glob: GlobMatcher,
13608 kind: Option<FileOperationPatternKind>,
13609}
13610
13611impl RenameActionPredicate {
13612 // Returns true if language server should be notified
13613 fn eval(&self, path: &str, is_dir: bool) -> bool {
13614 self.kind.as_ref().is_none_or(|kind| {
13615 let expected_kind = if is_dir {
13616 FileOperationPatternKind::Folder
13617 } else {
13618 FileOperationPatternKind::File
13619 };
13620 kind == &expected_kind
13621 }) && self.glob.is_match(path)
13622 }
13623}
13624
13625#[derive(Default)]
13626struct LanguageServerWatchedPaths {
13627 worktree_paths: HashMap<WorktreeId, GlobSet>,
13628 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13629}
13630
13631#[derive(Default)]
13632struct LanguageServerWatchedPathsBuilder {
13633 worktree_paths: HashMap<WorktreeId, GlobSet>,
13634 abs_paths: HashMap<Arc<Path>, GlobSet>,
13635}
13636
13637impl LanguageServerWatchedPathsBuilder {
13638 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13639 self.worktree_paths.insert(worktree_id, glob_set);
13640 }
13641 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13642 self.abs_paths.insert(path, glob_set);
13643 }
13644 fn build(
13645 self,
13646 fs: Arc<dyn Fs>,
13647 language_server_id: LanguageServerId,
13648 cx: &mut Context<LspStore>,
13649 ) -> LanguageServerWatchedPaths {
13650 let lsp_store = cx.weak_entity();
13651
13652 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13653 let abs_paths = self
13654 .abs_paths
13655 .into_iter()
13656 .map(|(abs_path, globset)| {
13657 let task = cx.spawn({
13658 let abs_path = abs_path.clone();
13659 let fs = fs.clone();
13660
13661 let lsp_store = lsp_store.clone();
13662 async move |_, cx| {
13663 maybe!(async move {
13664 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13665 while let Some(update) = push_updates.0.next().await {
13666 let action = lsp_store
13667 .update(cx, |this, _| {
13668 let Some(local) = this.as_local() else {
13669 return ControlFlow::Break(());
13670 };
13671 let Some(watcher) = local
13672 .language_server_watched_paths
13673 .get(&language_server_id)
13674 else {
13675 return ControlFlow::Break(());
13676 };
13677 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13678 "Watched abs path is not registered with a watcher",
13679 );
13680 let matching_entries = update
13681 .into_iter()
13682 .filter(|event| globs.is_match(&event.path))
13683 .collect::<Vec<_>>();
13684 this.lsp_notify_abs_paths_changed(
13685 language_server_id,
13686 matching_entries,
13687 );
13688 ControlFlow::Continue(())
13689 })
13690 .ok()?;
13691
13692 if action.is_break() {
13693 break;
13694 }
13695 }
13696 Some(())
13697 })
13698 .await;
13699 }
13700 });
13701 (abs_path, (globset, task))
13702 })
13703 .collect();
13704 LanguageServerWatchedPaths {
13705 worktree_paths: self.worktree_paths,
13706 abs_paths,
13707 }
13708 }
13709}
13710
13711struct LspBufferSnapshot {
13712 version: i32,
13713 snapshot: TextBufferSnapshot,
13714}
13715
13716/// A prompt requested by LSP server.
13717#[derive(Clone, Debug)]
13718pub struct LanguageServerPromptRequest {
13719 pub id: usize,
13720 pub level: PromptLevel,
13721 pub message: String,
13722 pub actions: Vec<MessageActionItem>,
13723 pub lsp_name: String,
13724 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13725}
13726
13727impl LanguageServerPromptRequest {
13728 pub fn new(
13729 level: PromptLevel,
13730 message: String,
13731 actions: Vec<MessageActionItem>,
13732 lsp_name: String,
13733 response_channel: smol::channel::Sender<MessageActionItem>,
13734 ) -> Self {
13735 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13736 LanguageServerPromptRequest {
13737 id,
13738 level,
13739 message,
13740 actions,
13741 lsp_name,
13742 response_channel,
13743 }
13744 }
13745 pub async fn respond(self, index: usize) -> Option<()> {
13746 if let Some(response) = self.actions.into_iter().nth(index) {
13747 self.response_channel.send(response).await.ok()
13748 } else {
13749 None
13750 }
13751 }
13752
13753 #[cfg(any(test, feature = "test-support"))]
13754 pub fn test(
13755 level: PromptLevel,
13756 message: String,
13757 actions: Vec<MessageActionItem>,
13758 lsp_name: String,
13759 ) -> Self {
13760 let (tx, _rx) = smol::channel::unbounded();
13761 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13762 }
13763}
13764impl PartialEq for LanguageServerPromptRequest {
13765 fn eq(&self, other: &Self) -> bool {
13766 self.message == other.message && self.actions == other.actions
13767 }
13768}
13769
13770#[derive(Clone, Debug, PartialEq)]
13771pub enum LanguageServerLogType {
13772 Log(MessageType),
13773 Trace { verbose_info: Option<String> },
13774 Rpc { received: bool },
13775}
13776
13777impl LanguageServerLogType {
13778 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13779 match self {
13780 Self::Log(log_type) => {
13781 use proto::log_message::LogLevel;
13782 let level = match *log_type {
13783 MessageType::ERROR => LogLevel::Error,
13784 MessageType::WARNING => LogLevel::Warning,
13785 MessageType::INFO => LogLevel::Info,
13786 MessageType::LOG => LogLevel::Log,
13787 other => {
13788 log::warn!("Unknown lsp log message type: {other:?}");
13789 LogLevel::Log
13790 }
13791 };
13792 proto::language_server_log::LogType::Log(proto::LogMessage {
13793 level: level as i32,
13794 })
13795 }
13796 Self::Trace { verbose_info } => {
13797 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13798 verbose_info: verbose_info.to_owned(),
13799 })
13800 }
13801 Self::Rpc { received } => {
13802 let kind = if *received {
13803 proto::rpc_message::Kind::Received
13804 } else {
13805 proto::rpc_message::Kind::Sent
13806 };
13807 let kind = kind as i32;
13808 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13809 }
13810 }
13811 }
13812
13813 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13814 use proto::log_message::LogLevel;
13815 use proto::rpc_message;
13816 match log_type {
13817 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13818 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13819 LogLevel::Error => MessageType::ERROR,
13820 LogLevel::Warning => MessageType::WARNING,
13821 LogLevel::Info => MessageType::INFO,
13822 LogLevel::Log => MessageType::LOG,
13823 },
13824 ),
13825 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13826 verbose_info: trace_message.verbose_info,
13827 },
13828 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13829 received: match rpc_message::Kind::from_i32(message.kind)
13830 .unwrap_or(rpc_message::Kind::Received)
13831 {
13832 rpc_message::Kind::Received => true,
13833 rpc_message::Kind::Sent => false,
13834 },
13835 },
13836 }
13837 }
13838}
13839
13840pub struct WorkspaceRefreshTask {
13841 refresh_tx: mpsc::Sender<()>,
13842 progress_tx: mpsc::Sender<()>,
13843 #[allow(dead_code)]
13844 task: Task<()>,
13845}
13846
13847pub enum LanguageServerState {
13848 Starting {
13849 startup: Task<Option<Arc<LanguageServer>>>,
13850 /// List of language servers that will be added to the workspace once it's initialization completes.
13851 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13852 },
13853
13854 Running {
13855 adapter: Arc<CachedLspAdapter>,
13856 server: Arc<LanguageServer>,
13857 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13858 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13859 },
13860}
13861
13862impl LanguageServerState {
13863 fn add_workspace_folder(&self, uri: Uri) {
13864 match self {
13865 LanguageServerState::Starting {
13866 pending_workspace_folders,
13867 ..
13868 } => {
13869 pending_workspace_folders.lock().insert(uri);
13870 }
13871 LanguageServerState::Running { server, .. } => {
13872 server.add_workspace_folder(uri);
13873 }
13874 }
13875 }
13876 fn _remove_workspace_folder(&self, uri: Uri) {
13877 match self {
13878 LanguageServerState::Starting {
13879 pending_workspace_folders,
13880 ..
13881 } => {
13882 pending_workspace_folders.lock().remove(&uri);
13883 }
13884 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13885 }
13886 }
13887}
13888
13889impl std::fmt::Debug for LanguageServerState {
13890 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13891 match self {
13892 LanguageServerState::Starting { .. } => {
13893 f.debug_struct("LanguageServerState::Starting").finish()
13894 }
13895 LanguageServerState::Running { .. } => {
13896 f.debug_struct("LanguageServerState::Running").finish()
13897 }
13898 }
13899 }
13900}
13901
13902#[derive(Clone, Debug, Serialize)]
13903pub struct LanguageServerProgress {
13904 pub is_disk_based_diagnostics_progress: bool,
13905 pub is_cancellable: bool,
13906 pub title: Option<String>,
13907 pub message: Option<String>,
13908 pub percentage: Option<usize>,
13909 #[serde(skip_serializing)]
13910 pub last_update_at: Instant,
13911}
13912
13913#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13914pub struct DiagnosticSummary {
13915 pub error_count: usize,
13916 pub warning_count: usize,
13917}
13918
13919impl DiagnosticSummary {
13920 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13921 let mut this = Self {
13922 error_count: 0,
13923 warning_count: 0,
13924 };
13925
13926 for entry in diagnostics {
13927 if entry.diagnostic.is_primary {
13928 match entry.diagnostic.severity {
13929 DiagnosticSeverity::ERROR => this.error_count += 1,
13930 DiagnosticSeverity::WARNING => this.warning_count += 1,
13931 _ => {}
13932 }
13933 }
13934 }
13935
13936 this
13937 }
13938
13939 pub fn is_empty(&self) -> bool {
13940 self.error_count == 0 && self.warning_count == 0
13941 }
13942
13943 pub fn to_proto(
13944 self,
13945 language_server_id: LanguageServerId,
13946 path: &RelPath,
13947 ) -> proto::DiagnosticSummary {
13948 proto::DiagnosticSummary {
13949 path: path.to_proto(),
13950 language_server_id: language_server_id.0 as u64,
13951 error_count: self.error_count as u32,
13952 warning_count: self.warning_count as u32,
13953 }
13954 }
13955}
13956
13957#[derive(Clone, Debug)]
13958pub enum CompletionDocumentation {
13959 /// There is no documentation for this completion.
13960 Undocumented,
13961 /// A single line of documentation.
13962 SingleLine(SharedString),
13963 /// Multiple lines of plain text documentation.
13964 MultiLinePlainText(SharedString),
13965 /// Markdown documentation.
13966 MultiLineMarkdown(SharedString),
13967 /// Both single line and multiple lines of plain text documentation.
13968 SingleLineAndMultiLinePlainText {
13969 single_line: SharedString,
13970 plain_text: Option<SharedString>,
13971 },
13972}
13973
13974impl CompletionDocumentation {
13975 #[cfg(any(test, feature = "test-support"))]
13976 pub fn text(&self) -> SharedString {
13977 match self {
13978 CompletionDocumentation::Undocumented => "".into(),
13979 CompletionDocumentation::SingleLine(s) => s.clone(),
13980 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13981 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13982 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13983 single_line.clone()
13984 }
13985 }
13986 }
13987}
13988
13989impl From<lsp::Documentation> for CompletionDocumentation {
13990 fn from(docs: lsp::Documentation) -> Self {
13991 match docs {
13992 lsp::Documentation::String(text) => {
13993 if text.lines().count() <= 1 {
13994 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13995 } else {
13996 CompletionDocumentation::MultiLinePlainText(text.into())
13997 }
13998 }
13999
14000 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14001 lsp::MarkupKind::PlainText => {
14002 if value.lines().count() <= 1 {
14003 CompletionDocumentation::SingleLine(value.into())
14004 } else {
14005 CompletionDocumentation::MultiLinePlainText(value.into())
14006 }
14007 }
14008
14009 lsp::MarkupKind::Markdown => {
14010 CompletionDocumentation::MultiLineMarkdown(value.into())
14011 }
14012 },
14013 }
14014 }
14015}
14016
14017pub enum ResolvedHint {
14018 Resolved(InlayHint),
14019 Resolving(Shared<Task<()>>),
14020}
14021
14022pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14023 glob.components()
14024 .take_while(|component| match component {
14025 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14026 _ => true,
14027 })
14028 .collect()
14029}
14030
14031pub struct SshLspAdapter {
14032 name: LanguageServerName,
14033 binary: LanguageServerBinary,
14034 initialization_options: Option<String>,
14035 code_action_kinds: Option<Vec<CodeActionKind>>,
14036}
14037
14038impl SshLspAdapter {
14039 pub fn new(
14040 name: LanguageServerName,
14041 binary: LanguageServerBinary,
14042 initialization_options: Option<String>,
14043 code_action_kinds: Option<String>,
14044 ) -> Self {
14045 Self {
14046 name,
14047 binary,
14048 initialization_options,
14049 code_action_kinds: code_action_kinds
14050 .as_ref()
14051 .and_then(|c| serde_json::from_str(c).ok()),
14052 }
14053 }
14054}
14055
14056impl LspInstaller for SshLspAdapter {
14057 type BinaryVersion = ();
14058 async fn check_if_user_installed(
14059 &self,
14060 _: &dyn LspAdapterDelegate,
14061 _: Option<Toolchain>,
14062 _: &AsyncApp,
14063 ) -> Option<LanguageServerBinary> {
14064 Some(self.binary.clone())
14065 }
14066
14067 async fn cached_server_binary(
14068 &self,
14069 _: PathBuf,
14070 _: &dyn LspAdapterDelegate,
14071 ) -> Option<LanguageServerBinary> {
14072 None
14073 }
14074
14075 async fn fetch_latest_server_version(
14076 &self,
14077 _: &dyn LspAdapterDelegate,
14078 _: bool,
14079 _: &mut AsyncApp,
14080 ) -> Result<()> {
14081 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14082 }
14083
14084 async fn fetch_server_binary(
14085 &self,
14086 _: (),
14087 _: PathBuf,
14088 _: &dyn LspAdapterDelegate,
14089 ) -> Result<LanguageServerBinary> {
14090 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14091 }
14092}
14093
14094#[async_trait(?Send)]
14095impl LspAdapter for SshLspAdapter {
14096 fn name(&self) -> LanguageServerName {
14097 self.name.clone()
14098 }
14099
14100 async fn initialization_options(
14101 self: Arc<Self>,
14102 _: &Arc<dyn LspAdapterDelegate>,
14103 _: &mut AsyncApp,
14104 ) -> Result<Option<serde_json::Value>> {
14105 let Some(options) = &self.initialization_options else {
14106 return Ok(None);
14107 };
14108 let result = serde_json::from_str(options)?;
14109 Ok(result)
14110 }
14111
14112 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14113 self.code_action_kinds.clone()
14114 }
14115}
14116
14117pub fn language_server_settings<'a>(
14118 delegate: &'a dyn LspAdapterDelegate,
14119 language: &LanguageServerName,
14120 cx: &'a App,
14121) -> Option<&'a LspSettings> {
14122 language_server_settings_for(
14123 SettingsLocation {
14124 worktree_id: delegate.worktree_id(),
14125 path: RelPath::empty(),
14126 },
14127 language,
14128 cx,
14129 )
14130}
14131
14132pub fn language_server_settings_for<'a>(
14133 location: SettingsLocation<'a>,
14134 language: &LanguageServerName,
14135 cx: &'a App,
14136) -> Option<&'a LspSettings> {
14137 ProjectSettings::get(Some(location), cx).lsp.get(language)
14138}
14139
14140pub struct LocalLspAdapterDelegate {
14141 lsp_store: WeakEntity<LspStore>,
14142 worktree: worktree::Snapshot,
14143 fs: Arc<dyn Fs>,
14144 http_client: Arc<dyn HttpClient>,
14145 language_registry: Arc<LanguageRegistry>,
14146 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14147}
14148
14149impl LocalLspAdapterDelegate {
14150 pub fn new(
14151 language_registry: Arc<LanguageRegistry>,
14152 environment: &Entity<ProjectEnvironment>,
14153 lsp_store: WeakEntity<LspStore>,
14154 worktree: &Entity<Worktree>,
14155 http_client: Arc<dyn HttpClient>,
14156 fs: Arc<dyn Fs>,
14157 cx: &mut App,
14158 ) -> Arc<Self> {
14159 let load_shell_env_task =
14160 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14161
14162 Arc::new(Self {
14163 lsp_store,
14164 worktree: worktree.read(cx).snapshot(),
14165 fs,
14166 http_client,
14167 language_registry,
14168 load_shell_env_task,
14169 })
14170 }
14171
14172 pub fn from_local_lsp(
14173 local: &LocalLspStore,
14174 worktree: &Entity<Worktree>,
14175 cx: &mut App,
14176 ) -> Arc<Self> {
14177 Self::new(
14178 local.languages.clone(),
14179 &local.environment,
14180 local.weak.clone(),
14181 worktree,
14182 local.http_client.clone(),
14183 local.fs.clone(),
14184 cx,
14185 )
14186 }
14187}
14188
14189#[async_trait]
14190impl LspAdapterDelegate for LocalLspAdapterDelegate {
14191 fn show_notification(&self, message: &str, cx: &mut App) {
14192 self.lsp_store
14193 .update(cx, |_, cx| {
14194 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14195 })
14196 .ok();
14197 }
14198
14199 fn http_client(&self) -> Arc<dyn HttpClient> {
14200 self.http_client.clone()
14201 }
14202
14203 fn worktree_id(&self) -> WorktreeId {
14204 self.worktree.id()
14205 }
14206
14207 fn worktree_root_path(&self) -> &Path {
14208 self.worktree.abs_path().as_ref()
14209 }
14210
14211 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14212 self.worktree.resolve_relative_path(path)
14213 }
14214
14215 async fn shell_env(&self) -> HashMap<String, String> {
14216 let task = self.load_shell_env_task.clone();
14217 task.await.unwrap_or_default()
14218 }
14219
14220 async fn npm_package_installed_version(
14221 &self,
14222 package_name: &str,
14223 ) -> Result<Option<(PathBuf, Version)>> {
14224 let local_package_directory = self.worktree_root_path();
14225 let node_modules_directory = local_package_directory.join("node_modules");
14226
14227 if let Some(version) =
14228 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14229 {
14230 return Ok(Some((node_modules_directory, version)));
14231 }
14232 let Some(npm) = self.which("npm".as_ref()).await else {
14233 log::warn!(
14234 "Failed to find npm executable for {:?}",
14235 local_package_directory
14236 );
14237 return Ok(None);
14238 };
14239
14240 let env = self.shell_env().await;
14241 let output = util::command::new_command(&npm)
14242 .args(["root", "-g"])
14243 .envs(env)
14244 .current_dir(local_package_directory)
14245 .output()
14246 .await?;
14247 let global_node_modules =
14248 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14249
14250 if let Some(version) =
14251 read_package_installed_version(global_node_modules.clone(), package_name).await?
14252 {
14253 return Ok(Some((global_node_modules, version)));
14254 }
14255 return Ok(None);
14256 }
14257
14258 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14259 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14260 if self.fs.is_file(&worktree_abs_path).await {
14261 worktree_abs_path.pop();
14262 }
14263
14264 let env = self.shell_env().await;
14265
14266 let shell_path = env.get("PATH").cloned();
14267
14268 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14269 }
14270
14271 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14272 let mut working_dir = self.worktree_root_path().to_path_buf();
14273 if self.fs.is_file(&working_dir).await {
14274 working_dir.pop();
14275 }
14276 let output = util::command::new_command(&command.path)
14277 .args(command.arguments)
14278 .envs(command.env.clone().unwrap_or_default())
14279 .current_dir(working_dir)
14280 .output()
14281 .await?;
14282
14283 anyhow::ensure!(
14284 output.status.success(),
14285 "{}, stdout: {:?}, stderr: {:?}",
14286 output.status,
14287 String::from_utf8_lossy(&output.stdout),
14288 String::from_utf8_lossy(&output.stderr)
14289 );
14290 Ok(())
14291 }
14292
14293 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14294 self.language_registry
14295 .update_lsp_binary_status(server_name, status);
14296 }
14297
14298 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14299 self.language_registry
14300 .all_lsp_adapters()
14301 .into_iter()
14302 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14303 .collect()
14304 }
14305
14306 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14307 let dir = self.language_registry.language_server_download_dir(name)?;
14308
14309 if !dir.exists() {
14310 smol::fs::create_dir_all(&dir)
14311 .await
14312 .context("failed to create container directory")
14313 .log_err()?;
14314 }
14315
14316 Some(dir)
14317 }
14318
14319 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14320 let entry = self
14321 .worktree
14322 .entry_for_path(path)
14323 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14324 let abs_path = self.worktree.absolutize(&entry.path);
14325 self.fs.load(&abs_path).await
14326 }
14327}
14328
14329async fn populate_labels_for_symbols(
14330 symbols: Vec<CoreSymbol>,
14331 language_registry: &Arc<LanguageRegistry>,
14332 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14333 output: &mut Vec<Symbol>,
14334) {
14335 #[allow(clippy::mutable_key_type)]
14336 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14337
14338 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14339 for symbol in symbols {
14340 let Some(file_name) = symbol.path.file_name() else {
14341 continue;
14342 };
14343 let language = language_registry
14344 .load_language_for_file_path(Path::new(file_name))
14345 .await
14346 .ok()
14347 .or_else(|| {
14348 unknown_paths.insert(file_name.into());
14349 None
14350 });
14351 symbols_by_language
14352 .entry(language)
14353 .or_default()
14354 .push(symbol);
14355 }
14356
14357 for unknown_path in unknown_paths {
14358 log::info!("no language found for symbol in file {unknown_path:?}");
14359 }
14360
14361 let mut label_params = Vec::new();
14362 for (language, mut symbols) in symbols_by_language {
14363 label_params.clear();
14364 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14365 name: mem::take(&mut symbol.name),
14366 kind: symbol.kind,
14367 container_name: symbol.container_name.take(),
14368 }));
14369
14370 let mut labels = Vec::new();
14371 if let Some(language) = language {
14372 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14373 language_registry
14374 .lsp_adapters(&language.name())
14375 .first()
14376 .cloned()
14377 });
14378 if let Some(lsp_adapter) = lsp_adapter {
14379 labels = lsp_adapter
14380 .labels_for_symbols(&label_params, &language)
14381 .await
14382 .log_err()
14383 .unwrap_or_default();
14384 }
14385 }
14386
14387 for (
14388 (
14389 symbol,
14390 language::Symbol {
14391 name,
14392 container_name,
14393 ..
14394 },
14395 ),
14396 label,
14397 ) in symbols
14398 .into_iter()
14399 .zip(label_params.drain(..))
14400 .zip(labels.into_iter().chain(iter::repeat(None)))
14401 {
14402 output.push(Symbol {
14403 language_server_name: symbol.language_server_name,
14404 source_worktree_id: symbol.source_worktree_id,
14405 source_language_server_id: symbol.source_language_server_id,
14406 path: symbol.path,
14407 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14408 name,
14409 kind: symbol.kind,
14410 range: symbol.range,
14411 container_name,
14412 });
14413 }
14414 }
14415}
14416
14417pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14418 text.lines()
14419 .map(|line| line.trim())
14420 .filter(|line| !line.is_empty())
14421 .join(separator)
14422}
14423
14424fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14425 match server.capabilities().text_document_sync.as_ref()? {
14426 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14427 // Server wants didSave but didn't specify includeText.
14428 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14429 // Server doesn't want didSave at all.
14430 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14431 // Server provided SaveOptions.
14432 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14433 Some(save_options.include_text.unwrap_or(false))
14434 }
14435 },
14436 // We do not have any save info. Kind affects didChange only.
14437 lsp::TextDocumentSyncCapability::Kind(_) => None,
14438 }
14439}
14440
14441/// Completion items are displayed in a `UniformList`.
14442/// Usually, those items are single-line strings, but in LSP responses,
14443/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14444/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14445/// 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,
14446/// breaking the completions menu presentation.
14447///
14448/// 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.
14449pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14450 let mut new_text = String::with_capacity(label.text.len());
14451 let mut offset_map = vec![0; label.text.len() + 1];
14452 let mut last_char_was_space = false;
14453 let mut new_idx = 0;
14454 let chars = label.text.char_indices().fuse();
14455 let mut newlines_removed = false;
14456
14457 for (idx, c) in chars {
14458 offset_map[idx] = new_idx;
14459
14460 match c {
14461 '\n' if last_char_was_space => {
14462 newlines_removed = true;
14463 }
14464 '\t' | ' ' if last_char_was_space => {}
14465 '\n' if !last_char_was_space => {
14466 new_text.push(' ');
14467 new_idx += 1;
14468 last_char_was_space = true;
14469 newlines_removed = true;
14470 }
14471 ' ' | '\t' => {
14472 new_text.push(' ');
14473 new_idx += 1;
14474 last_char_was_space = true;
14475 }
14476 _ => {
14477 new_text.push(c);
14478 new_idx += c.len_utf8();
14479 last_char_was_space = false;
14480 }
14481 }
14482 }
14483 offset_map[label.text.len()] = new_idx;
14484
14485 // Only modify the label if newlines were removed.
14486 if !newlines_removed {
14487 return;
14488 }
14489
14490 let last_index = new_idx;
14491 let mut run_ranges_errors = Vec::new();
14492 label.runs.retain_mut(|(range, _)| {
14493 match offset_map.get(range.start) {
14494 Some(&start) => range.start = start,
14495 None => {
14496 run_ranges_errors.push(range.clone());
14497 return false;
14498 }
14499 }
14500
14501 match offset_map.get(range.end) {
14502 Some(&end) => range.end = end,
14503 None => {
14504 run_ranges_errors.push(range.clone());
14505 range.end = last_index;
14506 }
14507 }
14508 true
14509 });
14510 if !run_ranges_errors.is_empty() {
14511 log::error!(
14512 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14513 label.text
14514 );
14515 }
14516
14517 let mut wrong_filter_range = None;
14518 if label.filter_range == (0..label.text.len()) {
14519 label.filter_range = 0..new_text.len();
14520 } else {
14521 let mut original_filter_range = Some(label.filter_range.clone());
14522 match offset_map.get(label.filter_range.start) {
14523 Some(&start) => label.filter_range.start = start,
14524 None => {
14525 wrong_filter_range = original_filter_range.take();
14526 label.filter_range.start = last_index;
14527 }
14528 }
14529
14530 match offset_map.get(label.filter_range.end) {
14531 Some(&end) => label.filter_range.end = end,
14532 None => {
14533 wrong_filter_range = original_filter_range.take();
14534 label.filter_range.end = last_index;
14535 }
14536 }
14537 }
14538 if let Some(wrong_filter_range) = wrong_filter_range {
14539 log::error!(
14540 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14541 label.text
14542 );
14543 }
14544
14545 label.text = new_text;
14546}
14547
14548/// Apply edits to the buffer that will become part of the formatting transaction.
14549/// Fails if the buffer has been edited since the start of that transaction.
14550fn extend_formatting_transaction(
14551 buffer: &FormattableBuffer,
14552 formatting_transaction_id: text::TransactionId,
14553 cx: &mut AsyncApp,
14554 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14555) -> anyhow::Result<()> {
14556 buffer.handle.update(cx, |buffer, cx| {
14557 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14558 if last_transaction_id != Some(formatting_transaction_id) {
14559 anyhow::bail!("Buffer edited while formatting. Aborting")
14560 }
14561 buffer.start_transaction();
14562 operation(buffer, cx);
14563 if let Some(transaction_id) = buffer.end_transaction(cx) {
14564 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14565 }
14566 Ok(())
14567 })
14568}