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 /// Apply edits to the buffer that will become part of the formatting transaction.
1615 /// Fails if the buffer has been edited since the start of that transaction.
1616 fn extend_formatting_transaction(
1617 buffer: &FormattableBuffer,
1618 formatting_transaction_id: text::TransactionId,
1619 cx: &mut AsyncApp,
1620 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1621 ) -> anyhow::Result<()> {
1622 buffer.handle.update(cx, |buffer, cx| {
1623 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1624 if last_transaction_id != Some(formatting_transaction_id) {
1625 anyhow::bail!("Buffer edited while formatting. Aborting")
1626 }
1627 buffer.start_transaction();
1628 operation(buffer, cx);
1629 if let Some(transaction_id) = buffer.end_transaction(cx) {
1630 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1631 }
1632 Ok(())
1633 })
1634 }
1635
1636 // handle whitespace formatting
1637 if settings.remove_trailing_whitespace_on_save {
1638 zlog::trace!(logger => "removing trailing whitespace");
1639 let diff = buffer
1640 .handle
1641 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1642 .await;
1643 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 })?;
1646 }
1647
1648 if settings.ensure_final_newline_on_save {
1649 zlog::trace!(logger => "ensuring final newline");
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.ensure_final_newline(cx);
1652 })?;
1653 }
1654
1655 // Formatter for `code_actions_on_format` that runs before
1656 // the rest of the formatters
1657 let mut code_actions_on_format_formatters = None;
1658 let should_run_code_actions_on_format = !matches!(
1659 (trigger, &settings.format_on_save),
1660 (FormatTrigger::Save, &FormatOnSave::Off)
1661 );
1662 if should_run_code_actions_on_format {
1663 let have_code_actions_to_run_on_format = settings
1664 .code_actions_on_format
1665 .values()
1666 .any(|enabled| *enabled);
1667 if have_code_actions_to_run_on_format {
1668 zlog::trace!(logger => "going to run code actions on format");
1669 code_actions_on_format_formatters = Some(
1670 settings
1671 .code_actions_on_format
1672 .iter()
1673 .filter_map(|(action, enabled)| enabled.then_some(action))
1674 .cloned()
1675 .map(Formatter::CodeAction)
1676 .collect::<Vec<_>>(),
1677 );
1678 }
1679 }
1680
1681 let formatters = match (trigger, &settings.format_on_save) {
1682 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1683 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1684 settings.formatter.as_ref()
1685 }
1686 };
1687
1688 let formatters = code_actions_on_format_formatters
1689 .iter()
1690 .flatten()
1691 .chain(formatters);
1692
1693 for formatter in formatters {
1694 let formatter = if formatter == &Formatter::Auto {
1695 if settings.prettier.allowed {
1696 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1697 &Formatter::Prettier
1698 } else {
1699 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1700 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1701 }
1702 } else {
1703 formatter
1704 };
1705 match formatter {
1706 Formatter::None => {
1707 zlog::trace!(logger => "skipping formatter 'none'");
1708 continue;
1709 }
1710 Formatter::Auto => unreachable!("Auto resolved above"),
1711 Formatter::Prettier => {
1712 let logger = zlog::scoped!(logger => "prettier");
1713 zlog::trace!(logger => "formatting");
1714 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1715
1716 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1717 lsp_store.prettier_store().unwrap().downgrade()
1718 })?;
1719 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1720 .await
1721 .transpose()?;
1722 let Some(diff) = diff else {
1723 zlog::trace!(logger => "No changes");
1724 continue;
1725 };
1726
1727 extend_formatting_transaction(
1728 buffer,
1729 formatting_transaction_id,
1730 cx,
1731 |buffer, cx| {
1732 buffer.apply_diff(diff, cx);
1733 },
1734 )?;
1735 }
1736 Formatter::External { command, arguments } => {
1737 let logger = zlog::scoped!(logger => "command");
1738 zlog::trace!(logger => "formatting");
1739 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1740
1741 let diff = Self::format_via_external_command(
1742 buffer,
1743 &command,
1744 arguments.as_deref(),
1745 cx,
1746 )
1747 .await
1748 .with_context(|| {
1749 format!("Failed to format buffer via external command: {}", command)
1750 })?;
1751 let Some(diff) = diff else {
1752 zlog::trace!(logger => "No changes");
1753 continue;
1754 };
1755
1756 extend_formatting_transaction(
1757 buffer,
1758 formatting_transaction_id,
1759 cx,
1760 |buffer, cx| {
1761 buffer.apply_diff(diff, cx);
1762 },
1763 )?;
1764 }
1765 Formatter::LanguageServer(specifier) => {
1766 let logger = zlog::scoped!(logger => "language-server");
1767 zlog::trace!(logger => "formatting");
1768 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1769
1770 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1771 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1772 continue;
1773 };
1774
1775 let language_server = match specifier {
1776 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1777 adapters_and_servers.iter().find_map(|(adapter, server)| {
1778 if adapter.name.0.as_ref() == name {
1779 Some(server.clone())
1780 } else {
1781 None
1782 }
1783 })
1784 }
1785 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1786 .iter()
1787 .find(|(_, server)| Self::server_supports_formatting(server))
1788 .map(|(_, server)| server.clone()),
1789 };
1790
1791 let Some(language_server) = language_server else {
1792 log::debug!(
1793 "No language server found to format buffer '{:?}'. Skipping",
1794 buffer_path_abs.as_path().to_string_lossy()
1795 );
1796 continue;
1797 };
1798
1799 zlog::trace!(
1800 logger =>
1801 "Formatting buffer '{:?}' using language server '{:?}'",
1802 buffer_path_abs.as_path().to_string_lossy(),
1803 language_server.name()
1804 );
1805
1806 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1807 zlog::trace!(logger => "formatting ranges");
1808 Self::format_ranges_via_lsp(
1809 &lsp_store,
1810 &buffer.handle,
1811 ranges,
1812 buffer_path_abs,
1813 &language_server,
1814 &settings,
1815 cx,
1816 )
1817 .await
1818 .context("Failed to format ranges via language server")?
1819 } else {
1820 zlog::trace!(logger => "formatting full");
1821 Self::format_via_lsp(
1822 &lsp_store,
1823 &buffer.handle,
1824 buffer_path_abs,
1825 &language_server,
1826 &settings,
1827 cx,
1828 )
1829 .await
1830 .context("failed to format via language server")?
1831 };
1832
1833 if edits.is_empty() {
1834 zlog::trace!(logger => "No changes");
1835 continue;
1836 }
1837 extend_formatting_transaction(
1838 buffer,
1839 formatting_transaction_id,
1840 cx,
1841 |buffer, cx| {
1842 buffer.edit(edits, None, cx);
1843 },
1844 )?;
1845 }
1846 Formatter::CodeAction(code_action_name) => {
1847 let logger = zlog::scoped!(logger => "code-actions");
1848 zlog::trace!(logger => "formatting");
1849 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1850
1851 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1852 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1853 continue;
1854 };
1855
1856 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1857 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1858
1859 let mut actions_and_servers = Vec::new();
1860
1861 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1862 let actions_result = Self::get_server_code_actions_from_action_kinds(
1863 &lsp_store,
1864 language_server.server_id(),
1865 vec![code_action_kind.clone()],
1866 &buffer.handle,
1867 cx,
1868 )
1869 .await
1870 .with_context(|| {
1871 format!(
1872 "Failed to resolve code action {:?} with language server {}",
1873 code_action_kind,
1874 language_server.name()
1875 )
1876 });
1877 let Ok(actions) = actions_result else {
1878 // note: it may be better to set result to the error and break formatters here
1879 // but for now we try to execute the actions that we can resolve and skip the rest
1880 zlog::error!(
1881 logger =>
1882 "Failed to resolve code action {:?} with language server {}",
1883 code_action_kind,
1884 language_server.name()
1885 );
1886 continue;
1887 };
1888 for action in actions {
1889 actions_and_servers.push((action, index));
1890 }
1891 }
1892
1893 if actions_and_servers.is_empty() {
1894 zlog::warn!(logger => "No code actions were resolved, continuing");
1895 continue;
1896 }
1897
1898 'actions: for (mut action, server_index) in actions_and_servers {
1899 let server = &adapters_and_servers[server_index].1;
1900
1901 let describe_code_action = |action: &CodeAction| {
1902 format!(
1903 "code action '{}' with title \"{}\" on server {}",
1904 action
1905 .lsp_action
1906 .action_kind()
1907 .unwrap_or("unknown".into())
1908 .as_str(),
1909 action.lsp_action.title(),
1910 server.name(),
1911 )
1912 };
1913
1914 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1915
1916 if let Err(err) =
1917 Self::try_resolve_code_action(server, &mut action, request_timeout)
1918 .await
1919 {
1920 zlog::error!(
1921 logger =>
1922 "Failed to resolve {}. Error: {}",
1923 describe_code_action(&action),
1924 err
1925 );
1926 continue;
1927 }
1928
1929 if let Some(edit) = action.lsp_action.edit().cloned() {
1930 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1931 // but filters out and logs warnings for code actions that require unreasonably
1932 // difficult handling on our part, such as:
1933 // - applying edits that call commands
1934 // which can result in arbitrary workspace edits being sent from the server that
1935 // have no way of being tied back to the command that initiated them (i.e. we
1936 // can't know which edits are part of the format request, or if the server is done sending
1937 // actions in response to the command)
1938 // - actions that create/delete/modify/rename files other than the one we are formatting
1939 // as we then would need to handle such changes correctly in the local history as well
1940 // as the remote history through the ProjectTransaction
1941 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1942 // Supporting these actions is not impossible, but not supported as of yet.
1943 if edit.changes.is_none() && edit.document_changes.is_none() {
1944 zlog::trace!(
1945 logger =>
1946 "No changes for code action. Skipping {}",
1947 describe_code_action(&action),
1948 );
1949 continue;
1950 }
1951
1952 let mut operations = Vec::new();
1953 if let Some(document_changes) = edit.document_changes {
1954 match document_changes {
1955 lsp::DocumentChanges::Edits(edits) => operations.extend(
1956 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1957 ),
1958 lsp::DocumentChanges::Operations(ops) => operations = ops,
1959 }
1960 } else if let Some(changes) = edit.changes {
1961 operations.extend(changes.into_iter().map(|(uri, edits)| {
1962 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1963 text_document:
1964 lsp::OptionalVersionedTextDocumentIdentifier {
1965 uri,
1966 version: None,
1967 },
1968 edits: edits.into_iter().map(Edit::Plain).collect(),
1969 })
1970 }));
1971 }
1972
1973 let mut edits = Vec::with_capacity(operations.len());
1974
1975 if operations.is_empty() {
1976 zlog::trace!(
1977 logger =>
1978 "No changes for code action. Skipping {}",
1979 describe_code_action(&action),
1980 );
1981 continue;
1982 }
1983 for operation in operations {
1984 let op = match operation {
1985 lsp::DocumentChangeOperation::Edit(op) => op,
1986 lsp::DocumentChangeOperation::Op(_) => {
1987 zlog::warn!(
1988 logger =>
1989 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1990 describe_code_action(&action),
1991 );
1992 continue 'actions;
1993 }
1994 };
1995 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1996 zlog::warn!(
1997 logger =>
1998 "Failed to convert URI '{:?}' to file path. Skipping {}",
1999 &op.text_document.uri,
2000 describe_code_action(&action),
2001 );
2002 continue 'actions;
2003 };
2004 if &file_path != buffer_path_abs {
2005 zlog::warn!(
2006 logger =>
2007 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2008 file_path,
2009 buffer_path_abs,
2010 describe_code_action(&action),
2011 );
2012 continue 'actions;
2013 }
2014
2015 let mut lsp_edits = Vec::new();
2016 for edit in op.edits {
2017 match edit {
2018 Edit::Plain(edit) => {
2019 if !lsp_edits.contains(&edit) {
2020 lsp_edits.push(edit);
2021 }
2022 }
2023 Edit::Annotated(edit) => {
2024 if !lsp_edits.contains(&edit.text_edit) {
2025 lsp_edits.push(edit.text_edit);
2026 }
2027 }
2028 Edit::Snippet(_) => {
2029 zlog::warn!(
2030 logger =>
2031 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2032 describe_code_action(&action),
2033 );
2034 continue 'actions;
2035 }
2036 }
2037 }
2038 let edits_result = lsp_store
2039 .update(cx, |lsp_store, cx| {
2040 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2041 &buffer.handle,
2042 lsp_edits,
2043 server.server_id(),
2044 op.text_document.version,
2045 cx,
2046 )
2047 })?
2048 .await;
2049 let Ok(resolved_edits) = edits_result else {
2050 zlog::warn!(
2051 logger =>
2052 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2053 buffer_path_abs.as_path(),
2054 describe_code_action(&action),
2055 );
2056 continue 'actions;
2057 };
2058 edits.extend(resolved_edits);
2059 }
2060
2061 if edits.is_empty() {
2062 zlog::warn!(logger => "No edits resolved from LSP");
2063 continue;
2064 }
2065
2066 extend_formatting_transaction(
2067 buffer,
2068 formatting_transaction_id,
2069 cx,
2070 |buffer, cx| {
2071 zlog::info!(
2072 "Applying edits {edits:?}. Content: {:?}",
2073 buffer.text()
2074 );
2075 buffer.edit(edits, None, cx);
2076 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2077 },
2078 )?;
2079 }
2080
2081 // bail early if command is invalid
2082 let Some(command) = action.lsp_action.command() else {
2083 continue;
2084 };
2085
2086 zlog::warn!(
2087 logger =>
2088 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2089 &command.command,
2090 );
2091
2092 let server_capabilities = server.capabilities();
2093 let available_commands = server_capabilities
2094 .execute_command_provider
2095 .as_ref()
2096 .map(|options| options.commands.as_slice())
2097 .unwrap_or_default();
2098 if !available_commands.contains(&command.command) {
2099 zlog::warn!(
2100 logger =>
2101 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2102 command.command,
2103 server.name(),
2104 );
2105 continue;
2106 }
2107
2108 // noop so we just ensure buffer hasn't been edited since resolving code actions
2109 extend_formatting_transaction(
2110 buffer,
2111 formatting_transaction_id,
2112 cx,
2113 |_, _| {},
2114 )?;
2115 zlog::info!(logger => "Executing command {}", &command.command);
2116
2117 lsp_store.update(cx, |this, _| {
2118 this.as_local_mut()
2119 .unwrap()
2120 .last_workspace_edits_by_language_server
2121 .remove(&server.server_id());
2122 })?;
2123
2124 let execute_command_result = server
2125 .request::<lsp::request::ExecuteCommand>(
2126 lsp::ExecuteCommandParams {
2127 command: command.command.clone(),
2128 arguments: command.arguments.clone().unwrap_or_default(),
2129 ..Default::default()
2130 },
2131 request_timeout,
2132 )
2133 .await
2134 .into_response();
2135
2136 if execute_command_result.is_err() {
2137 zlog::error!(
2138 logger =>
2139 "Failed to execute command '{}' as part of {}",
2140 &command.command,
2141 describe_code_action(&action),
2142 );
2143 continue 'actions;
2144 }
2145
2146 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2147 this.as_local_mut()
2148 .unwrap()
2149 .last_workspace_edits_by_language_server
2150 .remove(&server.server_id())
2151 .unwrap_or_default()
2152 })?;
2153
2154 if let Some(transaction) =
2155 project_transaction_command.0.remove(&buffer.handle)
2156 {
2157 zlog::trace!(
2158 logger =>
2159 "Successfully captured {} edits that resulted from command {}",
2160 transaction.edit_ids.len(),
2161 &command.command,
2162 );
2163 let transaction_id_project_transaction = transaction.id;
2164 buffer.handle.update(cx, |buffer, _| {
2165 // it may have been removed from history if push_to_history was
2166 // false in deserialize_workspace_edit. If so push it so we
2167 // can merge it with the format transaction
2168 // and pop the combined transaction off the history stack
2169 // later if push_to_history is false
2170 if buffer.get_transaction(transaction.id).is_none() {
2171 buffer.push_transaction(transaction, Instant::now());
2172 }
2173 buffer.merge_transactions(
2174 transaction_id_project_transaction,
2175 formatting_transaction_id,
2176 );
2177 });
2178 }
2179
2180 if project_transaction_command.0.is_empty() {
2181 continue;
2182 }
2183
2184 let mut extra_buffers = String::new();
2185 for buffer in project_transaction_command.0.keys() {
2186 buffer.read_with(cx, |b, cx| {
2187 let Some(path) = b.project_path(cx) else {
2188 return;
2189 };
2190
2191 if !extra_buffers.is_empty() {
2192 extra_buffers.push_str(", ");
2193 }
2194 extra_buffers.push_str(path.path.as_unix_str());
2195 });
2196 }
2197 zlog::warn!(
2198 logger =>
2199 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2200 &command.command,
2201 extra_buffers,
2202 );
2203 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2204 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2205 // add it so it's included, and merge it into the format transaction when its created later
2206 }
2207 }
2208 }
2209 }
2210
2211 Ok(())
2212 }
2213
2214 pub async fn format_ranges_via_lsp(
2215 this: &WeakEntity<LspStore>,
2216 buffer_handle: &Entity<Buffer>,
2217 ranges: &[Range<Anchor>],
2218 abs_path: &Path,
2219 language_server: &Arc<LanguageServer>,
2220 settings: &LanguageSettings,
2221 cx: &mut AsyncApp,
2222 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2223 let capabilities = &language_server.capabilities();
2224 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2225 if range_formatting_provider == Some(&OneOf::Left(false)) {
2226 anyhow::bail!(
2227 "{} language server does not support range formatting",
2228 language_server.name()
2229 );
2230 }
2231
2232 let uri = file_path_to_lsp_url(abs_path)?;
2233 let text_document = lsp::TextDocumentIdentifier::new(uri);
2234
2235 let request_timeout = cx.update(|app| {
2236 ProjectSettings::get_global(app)
2237 .global_lsp_settings
2238 .get_request_timeout()
2239 });
2240 let lsp_edits = {
2241 let mut lsp_ranges = Vec::new();
2242 this.update(cx, |_this, cx| {
2243 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2244 // not have been sent to the language server. This seems like a fairly systemic
2245 // issue, though, the resolution probably is not specific to formatting.
2246 //
2247 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2248 // LSP.
2249 let snapshot = buffer_handle.read(cx).snapshot();
2250 for range in ranges {
2251 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2252 }
2253 anyhow::Ok(())
2254 })??;
2255
2256 let mut edits = None;
2257 for range in lsp_ranges {
2258 if let Some(mut edit) = language_server
2259 .request::<lsp::request::RangeFormatting>(
2260 lsp::DocumentRangeFormattingParams {
2261 text_document: text_document.clone(),
2262 range,
2263 options: lsp_command::lsp_formatting_options(settings),
2264 work_done_progress_params: Default::default(),
2265 },
2266 request_timeout,
2267 )
2268 .await
2269 .into_response()?
2270 {
2271 edits.get_or_insert_with(Vec::new).append(&mut edit);
2272 }
2273 }
2274 edits
2275 };
2276
2277 if let Some(lsp_edits) = lsp_edits {
2278 this.update(cx, |this, cx| {
2279 this.as_local_mut().unwrap().edits_from_lsp(
2280 buffer_handle,
2281 lsp_edits,
2282 language_server.server_id(),
2283 None,
2284 cx,
2285 )
2286 })?
2287 .await
2288 } else {
2289 Ok(Vec::with_capacity(0))
2290 }
2291 }
2292
2293 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2294 let capabilities = server.capabilities();
2295 let formatting = capabilities.document_formatting_provider.as_ref();
2296 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2297 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2298 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2299 }
2300
2301 async fn format_via_lsp(
2302 this: &WeakEntity<LspStore>,
2303 buffer: &Entity<Buffer>,
2304 abs_path: &Path,
2305 language_server: &Arc<LanguageServer>,
2306 settings: &LanguageSettings,
2307 cx: &mut AsyncApp,
2308 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2309 let logger = zlog::scoped!("lsp_format");
2310 zlog::debug!(logger => "Formatting via LSP");
2311
2312 let uri = file_path_to_lsp_url(abs_path)?;
2313 let text_document = lsp::TextDocumentIdentifier::new(uri);
2314 let capabilities = &language_server.capabilities();
2315
2316 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2317 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2318
2319 let request_timeout = cx.update(|app| {
2320 ProjectSettings::get_global(app)
2321 .global_lsp_settings
2322 .get_request_timeout()
2323 });
2324
2325 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2326 let _timer = zlog::time!(logger => "format-full");
2327 language_server
2328 .request::<lsp::request::Formatting>(
2329 lsp::DocumentFormattingParams {
2330 text_document,
2331 options: lsp_command::lsp_formatting_options(settings),
2332 work_done_progress_params: Default::default(),
2333 },
2334 request_timeout,
2335 )
2336 .await
2337 .into_response()?
2338 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2339 let _timer = zlog::time!(logger => "format-range");
2340 let buffer_start = lsp::Position::new(0, 0);
2341 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2342 language_server
2343 .request::<lsp::request::RangeFormatting>(
2344 lsp::DocumentRangeFormattingParams {
2345 text_document: text_document.clone(),
2346 range: lsp::Range::new(buffer_start, buffer_end),
2347 options: lsp_command::lsp_formatting_options(settings),
2348 work_done_progress_params: Default::default(),
2349 },
2350 request_timeout,
2351 )
2352 .await
2353 .into_response()?
2354 } else {
2355 None
2356 };
2357
2358 if let Some(lsp_edits) = lsp_edits {
2359 this.update(cx, |this, cx| {
2360 this.as_local_mut().unwrap().edits_from_lsp(
2361 buffer,
2362 lsp_edits,
2363 language_server.server_id(),
2364 None,
2365 cx,
2366 )
2367 })?
2368 .await
2369 } else {
2370 Ok(Vec::with_capacity(0))
2371 }
2372 }
2373
2374 async fn format_via_external_command(
2375 buffer: &FormattableBuffer,
2376 command: &str,
2377 arguments: Option<&[String]>,
2378 cx: &mut AsyncApp,
2379 ) -> Result<Option<Diff>> {
2380 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2381 let file = File::from_dyn(buffer.file())?;
2382 let worktree = file.worktree.read(cx);
2383 let mut worktree_path = worktree.abs_path().to_path_buf();
2384 if worktree.root_entry()?.is_file() {
2385 worktree_path.pop();
2386 }
2387 Some(worktree_path)
2388 });
2389
2390 use util::command::Stdio;
2391 let mut child = util::command::new_command(command);
2392
2393 if let Some(buffer_env) = buffer.env.as_ref() {
2394 child.envs(buffer_env);
2395 }
2396
2397 if let Some(working_dir_path) = working_dir_path {
2398 child.current_dir(working_dir_path);
2399 }
2400
2401 if let Some(arguments) = arguments {
2402 child.args(arguments.iter().map(|arg| {
2403 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2404 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2405 } else {
2406 arg.replace("{buffer_path}", "Untitled")
2407 }
2408 }));
2409 }
2410
2411 let mut child = child
2412 .stdin(Stdio::piped())
2413 .stdout(Stdio::piped())
2414 .stderr(Stdio::piped())
2415 .spawn()?;
2416
2417 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2418 let text = buffer
2419 .handle
2420 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2421 for chunk in text.chunks() {
2422 stdin.write_all(chunk.as_bytes()).await?;
2423 }
2424 stdin.flush().await?;
2425
2426 let output = child.output().await?;
2427 anyhow::ensure!(
2428 output.status.success(),
2429 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2430 output.status.code(),
2431 String::from_utf8_lossy(&output.stdout),
2432 String::from_utf8_lossy(&output.stderr),
2433 );
2434
2435 let stdout = String::from_utf8(output.stdout)?;
2436 Ok(Some(
2437 buffer
2438 .handle
2439 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2440 .await,
2441 ))
2442 }
2443
2444 async fn try_resolve_code_action(
2445 lang_server: &LanguageServer,
2446 action: &mut CodeAction,
2447 request_timeout: Duration,
2448 ) -> anyhow::Result<()> {
2449 match &mut action.lsp_action {
2450 LspAction::Action(lsp_action) => {
2451 if !action.resolved
2452 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2453 && lsp_action.data.is_some()
2454 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2455 {
2456 **lsp_action = lang_server
2457 .request::<lsp::request::CodeActionResolveRequest>(
2458 *lsp_action.clone(),
2459 request_timeout,
2460 )
2461 .await
2462 .into_response()?;
2463 }
2464 }
2465 LspAction::CodeLens(lens) => {
2466 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2467 *lens = lang_server
2468 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2469 .await
2470 .into_response()?;
2471 }
2472 }
2473 LspAction::Command(_) => {}
2474 }
2475
2476 action.resolved = true;
2477 anyhow::Ok(())
2478 }
2479
2480 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2481 let buffer = buffer_handle.read(cx);
2482
2483 let file = buffer.file().cloned();
2484
2485 let Some(file) = File::from_dyn(file.as_ref()) else {
2486 return;
2487 };
2488 if !file.is_local() {
2489 return;
2490 }
2491 let path = ProjectPath::from_file(file, cx);
2492 let worktree_id = file.worktree_id(cx);
2493 let language = buffer.language().cloned();
2494
2495 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2496 for (server_id, diagnostics) in
2497 diagnostics.get(file.path()).cloned().unwrap_or_default()
2498 {
2499 self.update_buffer_diagnostics(
2500 buffer_handle,
2501 server_id,
2502 None,
2503 None,
2504 None,
2505 Vec::new(),
2506 diagnostics,
2507 cx,
2508 )
2509 .log_err();
2510 }
2511 }
2512 let Some(language) = language else {
2513 return;
2514 };
2515 let Some(snapshot) = self
2516 .worktree_store
2517 .read(cx)
2518 .worktree_for_id(worktree_id, cx)
2519 .map(|worktree| worktree.read(cx).snapshot())
2520 else {
2521 return;
2522 };
2523 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2524
2525 for server_id in
2526 self.lsp_tree
2527 .get(path, language.name(), language.manifest(), &delegate, cx)
2528 {
2529 let server = self
2530 .language_servers
2531 .get(&server_id)
2532 .and_then(|server_state| {
2533 if let LanguageServerState::Running { server, .. } = server_state {
2534 Some(server.clone())
2535 } else {
2536 None
2537 }
2538 });
2539 let server = match server {
2540 Some(server) => server,
2541 None => continue,
2542 };
2543
2544 buffer_handle.update(cx, |buffer, cx| {
2545 buffer.set_completion_triggers(
2546 server.server_id(),
2547 server
2548 .capabilities()
2549 .completion_provider
2550 .as_ref()
2551 .and_then(|provider| {
2552 provider
2553 .trigger_characters
2554 .as_ref()
2555 .map(|characters| characters.iter().cloned().collect())
2556 })
2557 .unwrap_or_default(),
2558 cx,
2559 );
2560 });
2561 }
2562 }
2563
2564 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2565 buffer.update(cx, |buffer, cx| {
2566 let Some(language) = buffer.language() else {
2567 return;
2568 };
2569 let path = ProjectPath {
2570 worktree_id: old_file.worktree_id(cx),
2571 path: old_file.path.clone(),
2572 };
2573 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2574 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2575 buffer.set_completion_triggers(server_id, Default::default(), cx);
2576 }
2577 });
2578 }
2579
2580 fn update_buffer_diagnostics(
2581 &mut self,
2582 buffer: &Entity<Buffer>,
2583 server_id: LanguageServerId,
2584 registration_id: Option<Option<SharedString>>,
2585 result_id: Option<SharedString>,
2586 version: Option<i32>,
2587 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2588 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2589 cx: &mut Context<LspStore>,
2590 ) -> Result<()> {
2591 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2592 Ordering::Equal
2593 .then_with(|| b.is_primary.cmp(&a.is_primary))
2594 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2595 .then_with(|| a.severity.cmp(&b.severity))
2596 .then_with(|| a.message.cmp(&b.message))
2597 }
2598
2599 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2600 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2601 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2602
2603 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2604 Ordering::Equal
2605 .then_with(|| a.range.start.cmp(&b.range.start))
2606 .then_with(|| b.range.end.cmp(&a.range.end))
2607 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2608 });
2609
2610 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2611
2612 let edits_since_save = std::cell::LazyCell::new(|| {
2613 let saved_version = buffer.read(cx).saved_version();
2614 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2615 });
2616
2617 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2618
2619 for (new_diagnostic, entry) in diagnostics {
2620 let start;
2621 let end;
2622 if new_diagnostic && entry.diagnostic.is_disk_based {
2623 // Some diagnostics are based on files on disk instead of buffers'
2624 // current contents. Adjust these diagnostics' ranges to reflect
2625 // any unsaved edits.
2626 // Do not alter the reused ones though, as their coordinates were stored as anchors
2627 // and were properly adjusted on reuse.
2628 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2629 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2630 } else {
2631 start = entry.range.start;
2632 end = entry.range.end;
2633 }
2634
2635 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2636 ..snapshot.clip_point_utf16(end, Bias::Right);
2637
2638 // Expand empty ranges by one codepoint
2639 if range.start == range.end {
2640 // This will be go to the next boundary when being clipped
2641 range.end.column += 1;
2642 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2643 if range.start == range.end && range.end.column > 0 {
2644 range.start.column -= 1;
2645 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2646 }
2647 }
2648
2649 sanitized_diagnostics.push(DiagnosticEntry {
2650 range,
2651 diagnostic: entry.diagnostic,
2652 });
2653 }
2654 drop(edits_since_save);
2655
2656 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2657 buffer.update(cx, |buffer, cx| {
2658 if let Some(registration_id) = registration_id {
2659 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2660 self.buffer_pull_diagnostics_result_ids
2661 .entry(server_id)
2662 .or_default()
2663 .entry(registration_id)
2664 .or_default()
2665 .insert(abs_path, result_id);
2666 }
2667 }
2668
2669 buffer.update_diagnostics(server_id, set, cx)
2670 });
2671
2672 Ok(())
2673 }
2674
2675 fn register_language_server_for_invisible_worktree(
2676 &mut self,
2677 worktree: &Entity<Worktree>,
2678 language_server_id: LanguageServerId,
2679 cx: &mut App,
2680 ) {
2681 let worktree = worktree.read(cx);
2682 let worktree_id = worktree.id();
2683 debug_assert!(!worktree.is_visible());
2684 let Some(mut origin_seed) = self
2685 .language_server_ids
2686 .iter()
2687 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2688 else {
2689 return;
2690 };
2691 origin_seed.worktree_id = worktree_id;
2692 self.language_server_ids
2693 .entry(origin_seed)
2694 .or_insert_with(|| UnifiedLanguageServer {
2695 id: language_server_id,
2696 project_roots: Default::default(),
2697 });
2698 }
2699
2700 fn register_buffer_with_language_servers(
2701 &mut self,
2702 buffer_handle: &Entity<Buffer>,
2703 only_register_servers: HashSet<LanguageServerSelector>,
2704 cx: &mut Context<LspStore>,
2705 ) {
2706 let buffer = buffer_handle.read(cx);
2707 let buffer_id = buffer.remote_id();
2708
2709 let Some(file) = File::from_dyn(buffer.file()) else {
2710 return;
2711 };
2712 if !file.is_local() {
2713 return;
2714 }
2715
2716 let abs_path = file.abs_path(cx);
2717 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2718 return;
2719 };
2720 let initial_snapshot = buffer.text_snapshot();
2721 let worktree_id = file.worktree_id(cx);
2722
2723 let Some(language) = buffer.language().cloned() else {
2724 return;
2725 };
2726 let path: Arc<RelPath> = file
2727 .path()
2728 .parent()
2729 .map(Arc::from)
2730 .unwrap_or_else(|| file.path().clone());
2731 let Some(worktree) = self
2732 .worktree_store
2733 .read(cx)
2734 .worktree_for_id(worktree_id, cx)
2735 else {
2736 return;
2737 };
2738 let language_name = language.name();
2739 let (reused, delegate, servers) = self
2740 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2741 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2742 .unwrap_or_else(|| {
2743 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2744 let delegate: Arc<dyn ManifestDelegate> =
2745 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2746
2747 let servers = self
2748 .lsp_tree
2749 .walk(
2750 ProjectPath { worktree_id, path },
2751 language.name(),
2752 language.manifest(),
2753 &delegate,
2754 cx,
2755 )
2756 .collect::<Vec<_>>();
2757 (false, lsp_delegate, servers)
2758 });
2759 let servers_and_adapters = servers
2760 .into_iter()
2761 .filter_map(|server_node| {
2762 if reused && server_node.server_id().is_none() {
2763 return None;
2764 }
2765 if !only_register_servers.is_empty() {
2766 if let Some(server_id) = server_node.server_id()
2767 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2768 {
2769 return None;
2770 }
2771 if let Some(name) = server_node.name()
2772 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2773 {
2774 return None;
2775 }
2776 }
2777
2778 let server_id = server_node.server_id_or_init(|disposition| {
2779 let path = &disposition.path;
2780
2781 {
2782 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2783
2784 let server_id = self.get_or_insert_language_server(
2785 &worktree,
2786 delegate.clone(),
2787 disposition,
2788 &language_name,
2789 cx,
2790 );
2791
2792 if let Some(state) = self.language_servers.get(&server_id)
2793 && let Ok(uri) = uri
2794 {
2795 state.add_workspace_folder(uri);
2796 };
2797 server_id
2798 }
2799 })?;
2800 let server_state = self.language_servers.get(&server_id)?;
2801 if let LanguageServerState::Running {
2802 server, adapter, ..
2803 } = server_state
2804 {
2805 Some((server.clone(), adapter.clone()))
2806 } else {
2807 None
2808 }
2809 })
2810 .collect::<Vec<_>>();
2811 for (server, adapter) in servers_and_adapters {
2812 buffer_handle.update(cx, |buffer, cx| {
2813 buffer.set_completion_triggers(
2814 server.server_id(),
2815 server
2816 .capabilities()
2817 .completion_provider
2818 .as_ref()
2819 .and_then(|provider| {
2820 provider
2821 .trigger_characters
2822 .as_ref()
2823 .map(|characters| characters.iter().cloned().collect())
2824 })
2825 .unwrap_or_default(),
2826 cx,
2827 );
2828 });
2829
2830 let snapshot = LspBufferSnapshot {
2831 version: 0,
2832 snapshot: initial_snapshot.clone(),
2833 };
2834
2835 let mut registered = false;
2836 self.buffer_snapshots
2837 .entry(buffer_id)
2838 .or_default()
2839 .entry(server.server_id())
2840 .or_insert_with(|| {
2841 registered = true;
2842 server.register_buffer(
2843 uri.clone(),
2844 adapter.language_id(&language.name()),
2845 0,
2846 initial_snapshot.text(),
2847 );
2848
2849 vec![snapshot]
2850 });
2851
2852 self.buffers_opened_in_servers
2853 .entry(buffer_id)
2854 .or_default()
2855 .insert(server.server_id());
2856 if registered {
2857 cx.emit(LspStoreEvent::LanguageServerUpdate {
2858 language_server_id: server.server_id(),
2859 name: None,
2860 message: proto::update_language_server::Variant::RegisteredForBuffer(
2861 proto::RegisteredForBuffer {
2862 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2863 buffer_id: buffer_id.to_proto(),
2864 },
2865 ),
2866 });
2867 }
2868 }
2869 }
2870
2871 fn reuse_existing_language_server<'lang_name>(
2872 &self,
2873 server_tree: &LanguageServerTree,
2874 worktree: &Entity<Worktree>,
2875 language_name: &'lang_name LanguageName,
2876 cx: &mut App,
2877 ) -> Option<(
2878 Arc<LocalLspAdapterDelegate>,
2879 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2880 )> {
2881 if worktree.read(cx).is_visible() {
2882 return None;
2883 }
2884
2885 let worktree_store = self.worktree_store.read(cx);
2886 let servers = server_tree
2887 .instances
2888 .iter()
2889 .filter(|(worktree_id, _)| {
2890 worktree_store
2891 .worktree_for_id(**worktree_id, cx)
2892 .is_some_and(|worktree| worktree.read(cx).is_visible())
2893 })
2894 .flat_map(|(worktree_id, servers)| {
2895 servers
2896 .roots
2897 .iter()
2898 .flat_map(|(_, language_servers)| language_servers)
2899 .map(move |(_, (server_node, server_languages))| {
2900 (worktree_id, server_node, server_languages)
2901 })
2902 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2903 .map(|(worktree_id, server_node, _)| {
2904 (
2905 *worktree_id,
2906 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2907 )
2908 })
2909 })
2910 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2911 acc.entry(worktree_id)
2912 .or_insert_with(Vec::new)
2913 .push(server_node);
2914 acc
2915 })
2916 .into_values()
2917 .max_by_key(|servers| servers.len())?;
2918
2919 let worktree_id = worktree.read(cx).id();
2920 let apply = move |tree: &mut LanguageServerTree| {
2921 for server_node in &servers {
2922 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2923 }
2924 servers
2925 };
2926
2927 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2928 Some((delegate, apply))
2929 }
2930
2931 pub(crate) fn unregister_old_buffer_from_language_servers(
2932 &mut self,
2933 buffer: &Entity<Buffer>,
2934 old_file: &File,
2935 cx: &mut App,
2936 ) {
2937 let old_path = match old_file.as_local() {
2938 Some(local) => local.abs_path(cx),
2939 None => return,
2940 };
2941
2942 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2943 debug_panic!("{old_path:?} is not parseable as an URI");
2944 return;
2945 };
2946 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2947 }
2948
2949 pub(crate) fn unregister_buffer_from_language_servers(
2950 &mut self,
2951 buffer: &Entity<Buffer>,
2952 file_url: &lsp::Uri,
2953 cx: &mut App,
2954 ) {
2955 buffer.update(cx, |buffer, cx| {
2956 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2957
2958 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2959 if snapshots
2960 .as_mut()
2961 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2962 {
2963 language_server.unregister_buffer(file_url.clone());
2964 }
2965 }
2966 });
2967 }
2968
2969 fn buffer_snapshot_for_lsp_version(
2970 &mut self,
2971 buffer: &Entity<Buffer>,
2972 server_id: LanguageServerId,
2973 version: Option<i32>,
2974 cx: &App,
2975 ) -> Result<TextBufferSnapshot> {
2976 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2977
2978 if let Some(version) = version {
2979 let buffer_id = buffer.read(cx).remote_id();
2980 let snapshots = if let Some(snapshots) = self
2981 .buffer_snapshots
2982 .get_mut(&buffer_id)
2983 .and_then(|m| m.get_mut(&server_id))
2984 {
2985 snapshots
2986 } else if version == 0 {
2987 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2988 // We detect this case and treat it as if the version was `None`.
2989 return Ok(buffer.read(cx).text_snapshot());
2990 } else {
2991 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2992 };
2993
2994 let found_snapshot = snapshots
2995 .binary_search_by_key(&version, |e| e.version)
2996 .map(|ix| snapshots[ix].snapshot.clone())
2997 .map_err(|_| {
2998 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2999 })?;
3000
3001 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3002 Ok(found_snapshot)
3003 } else {
3004 Ok((buffer.read(cx)).text_snapshot())
3005 }
3006 }
3007
3008 async fn get_server_code_actions_from_action_kinds(
3009 lsp_store: &WeakEntity<LspStore>,
3010 language_server_id: LanguageServerId,
3011 code_action_kinds: Vec<lsp::CodeActionKind>,
3012 buffer: &Entity<Buffer>,
3013 cx: &mut AsyncApp,
3014 ) -> Result<Vec<CodeAction>> {
3015 let actions = lsp_store
3016 .update(cx, move |this, cx| {
3017 let request = GetCodeActions {
3018 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3019 kinds: Some(code_action_kinds),
3020 };
3021 let server = LanguageServerToQuery::Other(language_server_id);
3022 this.request_lsp(buffer.clone(), server, request, cx)
3023 })?
3024 .await?;
3025 Ok(actions)
3026 }
3027
3028 pub async fn execute_code_actions_on_server(
3029 lsp_store: &WeakEntity<LspStore>,
3030 language_server: &Arc<LanguageServer>,
3031 actions: Vec<CodeAction>,
3032 push_to_history: bool,
3033 project_transaction: &mut ProjectTransaction,
3034 cx: &mut AsyncApp,
3035 ) -> anyhow::Result<()> {
3036 let request_timeout = cx.update(|app| {
3037 ProjectSettings::get_global(app)
3038 .global_lsp_settings
3039 .get_request_timeout()
3040 });
3041
3042 for mut action in actions {
3043 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3044 .await
3045 .context("resolving a formatting code action")?;
3046
3047 if let Some(edit) = action.lsp_action.edit() {
3048 if edit.changes.is_none() && edit.document_changes.is_none() {
3049 continue;
3050 }
3051
3052 let new = Self::deserialize_workspace_edit(
3053 lsp_store.upgrade().context("project dropped")?,
3054 edit.clone(),
3055 push_to_history,
3056 language_server.clone(),
3057 cx,
3058 )
3059 .await?;
3060 project_transaction.0.extend(new.0);
3061 }
3062
3063 let Some(command) = action.lsp_action.command() else {
3064 continue;
3065 };
3066
3067 let server_capabilities = language_server.capabilities();
3068 let available_commands = server_capabilities
3069 .execute_command_provider
3070 .as_ref()
3071 .map(|options| options.commands.as_slice())
3072 .unwrap_or_default();
3073 if !available_commands.contains(&command.command) {
3074 log::warn!(
3075 "Cannot execute a command {} not listed in the language server capabilities",
3076 command.command
3077 );
3078 continue;
3079 }
3080
3081 lsp_store.update(cx, |lsp_store, _| {
3082 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3083 mode.last_workspace_edits_by_language_server
3084 .remove(&language_server.server_id());
3085 }
3086 })?;
3087
3088 language_server
3089 .request::<lsp::request::ExecuteCommand>(
3090 lsp::ExecuteCommandParams {
3091 command: command.command.clone(),
3092 arguments: command.arguments.clone().unwrap_or_default(),
3093 ..Default::default()
3094 },
3095 request_timeout,
3096 )
3097 .await
3098 .into_response()
3099 .context("execute command")?;
3100
3101 lsp_store.update(cx, |this, _| {
3102 if let LspStoreMode::Local(mode) = &mut this.mode {
3103 project_transaction.0.extend(
3104 mode.last_workspace_edits_by_language_server
3105 .remove(&language_server.server_id())
3106 .unwrap_or_default()
3107 .0,
3108 )
3109 }
3110 })?;
3111 }
3112 Ok(())
3113 }
3114
3115 pub async fn deserialize_text_edits(
3116 this: Entity<LspStore>,
3117 buffer_to_edit: Entity<Buffer>,
3118 edits: Vec<lsp::TextEdit>,
3119 push_to_history: bool,
3120 _: Arc<CachedLspAdapter>,
3121 language_server: Arc<LanguageServer>,
3122 cx: &mut AsyncApp,
3123 ) -> Result<Option<Transaction>> {
3124 let edits = this
3125 .update(cx, |this, cx| {
3126 this.as_local_mut().unwrap().edits_from_lsp(
3127 &buffer_to_edit,
3128 edits,
3129 language_server.server_id(),
3130 None,
3131 cx,
3132 )
3133 })
3134 .await?;
3135
3136 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3137 buffer.finalize_last_transaction();
3138 buffer.start_transaction();
3139 for (range, text) in edits {
3140 buffer.edit([(range, text)], None, cx);
3141 }
3142
3143 if buffer.end_transaction(cx).is_some() {
3144 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3145 if !push_to_history {
3146 buffer.forget_transaction(transaction.id);
3147 }
3148 Some(transaction)
3149 } else {
3150 None
3151 }
3152 });
3153
3154 Ok(transaction)
3155 }
3156
3157 #[allow(clippy::type_complexity)]
3158 pub fn edits_from_lsp(
3159 &mut self,
3160 buffer: &Entity<Buffer>,
3161 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3162 server_id: LanguageServerId,
3163 version: Option<i32>,
3164 cx: &mut Context<LspStore>,
3165 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3166 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3167 cx.background_spawn(async move {
3168 let snapshot = snapshot?;
3169 let mut lsp_edits = lsp_edits
3170 .into_iter()
3171 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3172 .collect::<Vec<_>>();
3173
3174 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3175
3176 let mut lsp_edits = lsp_edits.into_iter().peekable();
3177 let mut edits = Vec::new();
3178 while let Some((range, mut new_text)) = lsp_edits.next() {
3179 // Clip invalid ranges provided by the language server.
3180 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3181 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3182
3183 // Combine any LSP edits that are adjacent.
3184 //
3185 // Also, combine LSP edits that are separated from each other by only
3186 // a newline. This is important because for some code actions,
3187 // Rust-analyzer rewrites the entire buffer via a series of edits that
3188 // are separated by unchanged newline characters.
3189 //
3190 // In order for the diffing logic below to work properly, any edits that
3191 // cancel each other out must be combined into one.
3192 while let Some((next_range, next_text)) = lsp_edits.peek() {
3193 if next_range.start.0 > range.end {
3194 if next_range.start.0.row > range.end.row + 1
3195 || next_range.start.0.column > 0
3196 || snapshot.clip_point_utf16(
3197 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3198 Bias::Left,
3199 ) > range.end
3200 {
3201 break;
3202 }
3203 new_text.push('\n');
3204 }
3205 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3206 new_text.push_str(next_text);
3207 lsp_edits.next();
3208 }
3209
3210 // For multiline edits, perform a diff of the old and new text so that
3211 // we can identify the changes more precisely, preserving the locations
3212 // of any anchors positioned in the unchanged regions.
3213 if range.end.row > range.start.row {
3214 let offset = range.start.to_offset(&snapshot);
3215 let old_text = snapshot.text_for_range(range).collect::<String>();
3216 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3217 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3218 (
3219 snapshot.anchor_after(offset + range.start)
3220 ..snapshot.anchor_before(offset + range.end),
3221 replacement,
3222 )
3223 }));
3224 } else if range.end == range.start {
3225 let anchor = snapshot.anchor_after(range.start);
3226 edits.push((anchor..anchor, new_text.into()));
3227 } else {
3228 let edit_start = snapshot.anchor_after(range.start);
3229 let edit_end = snapshot.anchor_before(range.end);
3230 edits.push((edit_start..edit_end, new_text.into()));
3231 }
3232 }
3233
3234 Ok(edits)
3235 })
3236 }
3237
3238 pub(crate) async fn deserialize_workspace_edit(
3239 this: Entity<LspStore>,
3240 edit: lsp::WorkspaceEdit,
3241 push_to_history: bool,
3242 language_server: Arc<LanguageServer>,
3243 cx: &mut AsyncApp,
3244 ) -> Result<ProjectTransaction> {
3245 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3246
3247 let mut operations = Vec::new();
3248 if let Some(document_changes) = edit.document_changes {
3249 match document_changes {
3250 lsp::DocumentChanges::Edits(edits) => {
3251 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3252 }
3253 lsp::DocumentChanges::Operations(ops) => operations = ops,
3254 }
3255 } else if let Some(changes) = edit.changes {
3256 operations.extend(changes.into_iter().map(|(uri, edits)| {
3257 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3258 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3259 uri,
3260 version: None,
3261 },
3262 edits: edits.into_iter().map(Edit::Plain).collect(),
3263 })
3264 }));
3265 }
3266
3267 let mut project_transaction = ProjectTransaction::default();
3268 for operation in operations {
3269 match operation {
3270 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3271 let abs_path = op
3272 .uri
3273 .to_file_path()
3274 .map_err(|()| anyhow!("can't convert URI to path"))?;
3275
3276 if let Some(parent_path) = abs_path.parent() {
3277 fs.create_dir(parent_path).await?;
3278 }
3279 if abs_path.ends_with("/") {
3280 fs.create_dir(&abs_path).await?;
3281 } else {
3282 fs.create_file(
3283 &abs_path,
3284 op.options
3285 .map(|options| fs::CreateOptions {
3286 overwrite: options.overwrite.unwrap_or(false),
3287 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3288 })
3289 .unwrap_or_default(),
3290 )
3291 .await?;
3292 }
3293 }
3294
3295 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3296 let source_abs_path = op
3297 .old_uri
3298 .to_file_path()
3299 .map_err(|()| anyhow!("can't convert URI to path"))?;
3300 let target_abs_path = op
3301 .new_uri
3302 .to_file_path()
3303 .map_err(|()| anyhow!("can't convert URI to path"))?;
3304
3305 let options = fs::RenameOptions {
3306 overwrite: op
3307 .options
3308 .as_ref()
3309 .and_then(|options| options.overwrite)
3310 .unwrap_or(false),
3311 ignore_if_exists: op
3312 .options
3313 .as_ref()
3314 .and_then(|options| options.ignore_if_exists)
3315 .unwrap_or(false),
3316 create_parents: true,
3317 };
3318
3319 fs.rename(&source_abs_path, &target_abs_path, options)
3320 .await?;
3321 }
3322
3323 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3324 let abs_path = op
3325 .uri
3326 .to_file_path()
3327 .map_err(|()| anyhow!("can't convert URI to path"))?;
3328 let options = op
3329 .options
3330 .map(|options| fs::RemoveOptions {
3331 recursive: options.recursive.unwrap_or(false),
3332 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3333 })
3334 .unwrap_or_default();
3335 if abs_path.ends_with("/") {
3336 fs.remove_dir(&abs_path, options).await?;
3337 } else {
3338 fs.remove_file(&abs_path, options).await?;
3339 }
3340 }
3341
3342 lsp::DocumentChangeOperation::Edit(op) => {
3343 let buffer_to_edit = this
3344 .update(cx, |this, cx| {
3345 this.open_local_buffer_via_lsp(
3346 op.text_document.uri.clone(),
3347 language_server.server_id(),
3348 cx,
3349 )
3350 })
3351 .await?;
3352
3353 let edits = this
3354 .update(cx, |this, cx| {
3355 let path = buffer_to_edit.read(cx).project_path(cx);
3356 let active_entry = this.active_entry;
3357 let is_active_entry = path.is_some_and(|project_path| {
3358 this.worktree_store
3359 .read(cx)
3360 .entry_for_path(&project_path, cx)
3361 .is_some_and(|entry| Some(entry.id) == active_entry)
3362 });
3363 let local = this.as_local_mut().unwrap();
3364
3365 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3366 for edit in op.edits {
3367 match edit {
3368 Edit::Plain(edit) => {
3369 if !edits.contains(&edit) {
3370 edits.push(edit)
3371 }
3372 }
3373 Edit::Annotated(edit) => {
3374 if !edits.contains(&edit.text_edit) {
3375 edits.push(edit.text_edit)
3376 }
3377 }
3378 Edit::Snippet(edit) => {
3379 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3380 else {
3381 continue;
3382 };
3383
3384 if is_active_entry {
3385 snippet_edits.push((edit.range, snippet));
3386 } else {
3387 // Since this buffer is not focused, apply a normal edit.
3388 let new_edit = TextEdit {
3389 range: edit.range,
3390 new_text: snippet.text,
3391 };
3392 if !edits.contains(&new_edit) {
3393 edits.push(new_edit);
3394 }
3395 }
3396 }
3397 }
3398 }
3399 if !snippet_edits.is_empty() {
3400 let buffer_id = buffer_to_edit.read(cx).remote_id();
3401 let version = if let Some(buffer_version) = op.text_document.version
3402 {
3403 local
3404 .buffer_snapshot_for_lsp_version(
3405 &buffer_to_edit,
3406 language_server.server_id(),
3407 Some(buffer_version),
3408 cx,
3409 )
3410 .ok()
3411 .map(|snapshot| snapshot.version)
3412 } else {
3413 Some(buffer_to_edit.read(cx).saved_version().clone())
3414 };
3415
3416 let most_recent_edit =
3417 version.and_then(|version| version.most_recent());
3418 // Check if the edit that triggered that edit has been made by this participant.
3419
3420 if let Some(most_recent_edit) = most_recent_edit {
3421 cx.emit(LspStoreEvent::SnippetEdit {
3422 buffer_id,
3423 edits: snippet_edits,
3424 most_recent_edit,
3425 });
3426 }
3427 }
3428
3429 local.edits_from_lsp(
3430 &buffer_to_edit,
3431 edits,
3432 language_server.server_id(),
3433 op.text_document.version,
3434 cx,
3435 )
3436 })
3437 .await?;
3438
3439 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3440 buffer.finalize_last_transaction();
3441 buffer.start_transaction();
3442 for (range, text) in edits {
3443 buffer.edit([(range, text)], None, cx);
3444 }
3445
3446 buffer.end_transaction(cx).and_then(|transaction_id| {
3447 if push_to_history {
3448 buffer.finalize_last_transaction();
3449 buffer.get_transaction(transaction_id).cloned()
3450 } else {
3451 buffer.forget_transaction(transaction_id)
3452 }
3453 })
3454 });
3455 if let Some(transaction) = transaction {
3456 project_transaction.0.insert(buffer_to_edit, transaction);
3457 }
3458 }
3459 }
3460 }
3461
3462 Ok(project_transaction)
3463 }
3464
3465 async fn on_lsp_workspace_edit(
3466 this: WeakEntity<LspStore>,
3467 params: lsp::ApplyWorkspaceEditParams,
3468 server_id: LanguageServerId,
3469 cx: &mut AsyncApp,
3470 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3471 let this = this.upgrade().context("project project closed")?;
3472 let language_server = this
3473 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3474 .context("language server not found")?;
3475 let transaction = Self::deserialize_workspace_edit(
3476 this.clone(),
3477 params.edit,
3478 true,
3479 language_server.clone(),
3480 cx,
3481 )
3482 .await
3483 .log_err();
3484 this.update(cx, |this, cx| {
3485 if let Some(transaction) = transaction {
3486 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3487
3488 this.as_local_mut()
3489 .unwrap()
3490 .last_workspace_edits_by_language_server
3491 .insert(server_id, transaction);
3492 }
3493 });
3494 Ok(lsp::ApplyWorkspaceEditResponse {
3495 applied: true,
3496 failed_change: None,
3497 failure_reason: None,
3498 })
3499 }
3500
3501 fn remove_worktree(
3502 &mut self,
3503 id_to_remove: WorktreeId,
3504 cx: &mut Context<LspStore>,
3505 ) -> Vec<LanguageServerId> {
3506 self.restricted_worktrees_tasks.remove(&id_to_remove);
3507 self.diagnostics.remove(&id_to_remove);
3508 self.prettier_store.update(cx, |prettier_store, cx| {
3509 prettier_store.remove_worktree(id_to_remove, cx);
3510 });
3511
3512 let mut servers_to_remove = BTreeSet::default();
3513 let mut servers_to_preserve = HashSet::default();
3514 for (seed, state) in &self.language_server_ids {
3515 if seed.worktree_id == id_to_remove {
3516 servers_to_remove.insert(state.id);
3517 } else {
3518 servers_to_preserve.insert(state.id);
3519 }
3520 }
3521 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3522 self.language_server_ids
3523 .retain(|_, state| !servers_to_remove.contains(&state.id));
3524 for server_id_to_remove in &servers_to_remove {
3525 self.language_server_watched_paths
3526 .remove(server_id_to_remove);
3527 self.language_server_paths_watched_for_rename
3528 .remove(server_id_to_remove);
3529 self.last_workspace_edits_by_language_server
3530 .remove(server_id_to_remove);
3531 self.language_servers.remove(server_id_to_remove);
3532 self.buffer_pull_diagnostics_result_ids
3533 .remove(server_id_to_remove);
3534 self.workspace_pull_diagnostics_result_ids
3535 .remove(server_id_to_remove);
3536 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3537 buffer_servers.remove(server_id_to_remove);
3538 }
3539 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3540 }
3541 servers_to_remove.into_iter().collect()
3542 }
3543
3544 fn rebuild_watched_paths_inner<'a>(
3545 &'a self,
3546 language_server_id: LanguageServerId,
3547 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3548 cx: &mut Context<LspStore>,
3549 ) -> LanguageServerWatchedPathsBuilder {
3550 let worktrees = self
3551 .worktree_store
3552 .read(cx)
3553 .worktrees()
3554 .filter_map(|worktree| {
3555 self.language_servers_for_worktree(worktree.read(cx).id())
3556 .find(|server| server.server_id() == language_server_id)
3557 .map(|_| worktree)
3558 })
3559 .collect::<Vec<_>>();
3560
3561 let mut worktree_globs = HashMap::default();
3562 let mut abs_globs = HashMap::default();
3563 log::trace!(
3564 "Processing new watcher paths for language server with id {}",
3565 language_server_id
3566 );
3567
3568 for watcher in watchers {
3569 if let Some((worktree, literal_prefix, pattern)) =
3570 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3571 {
3572 worktree.update(cx, |worktree, _| {
3573 if let Some((tree, glob)) =
3574 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3575 {
3576 tree.add_path_prefix_to_scan(literal_prefix);
3577 worktree_globs
3578 .entry(tree.id())
3579 .or_insert_with(GlobSetBuilder::new)
3580 .add(glob);
3581 }
3582 });
3583 } else {
3584 let (path, pattern) = match &watcher.glob_pattern {
3585 lsp::GlobPattern::String(s) => {
3586 let watcher_path = SanitizedPath::new(s);
3587 let path = glob_literal_prefix(watcher_path.as_path());
3588 let pattern = watcher_path
3589 .as_path()
3590 .strip_prefix(&path)
3591 .map(|p| p.to_string_lossy().into_owned())
3592 .unwrap_or_else(|e| {
3593 debug_panic!(
3594 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3595 s,
3596 path.display(),
3597 e
3598 );
3599 watcher_path.as_path().to_string_lossy().into_owned()
3600 });
3601 (path, pattern)
3602 }
3603 lsp::GlobPattern::Relative(rp) => {
3604 let Ok(mut base_uri) = match &rp.base_uri {
3605 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3606 lsp::OneOf::Right(base_uri) => base_uri,
3607 }
3608 .to_file_path() else {
3609 continue;
3610 };
3611
3612 let path = glob_literal_prefix(Path::new(&rp.pattern));
3613 let pattern = Path::new(&rp.pattern)
3614 .strip_prefix(&path)
3615 .map(|p| p.to_string_lossy().into_owned())
3616 .unwrap_or_else(|e| {
3617 debug_panic!(
3618 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3619 rp.pattern,
3620 path.display(),
3621 e
3622 );
3623 rp.pattern.clone()
3624 });
3625 base_uri.push(path);
3626 (base_uri, pattern)
3627 }
3628 };
3629
3630 if let Some(glob) = Glob::new(&pattern).log_err() {
3631 if !path
3632 .components()
3633 .any(|c| matches!(c, path::Component::Normal(_)))
3634 {
3635 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3636 // rather than adding a new watcher for `/`.
3637 for worktree in &worktrees {
3638 worktree_globs
3639 .entry(worktree.read(cx).id())
3640 .or_insert_with(GlobSetBuilder::new)
3641 .add(glob.clone());
3642 }
3643 } else {
3644 abs_globs
3645 .entry(path.into())
3646 .or_insert_with(GlobSetBuilder::new)
3647 .add(glob);
3648 }
3649 }
3650 }
3651 }
3652
3653 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3654 for (worktree_id, builder) in worktree_globs {
3655 if let Ok(globset) = builder.build() {
3656 watch_builder.watch_worktree(worktree_id, globset);
3657 }
3658 }
3659 for (abs_path, builder) in abs_globs {
3660 if let Ok(globset) = builder.build() {
3661 watch_builder.watch_abs_path(abs_path, globset);
3662 }
3663 }
3664 watch_builder
3665 }
3666
3667 fn worktree_and_path_for_file_watcher(
3668 worktrees: &[Entity<Worktree>],
3669 watcher: &FileSystemWatcher,
3670 cx: &App,
3671 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3672 worktrees.iter().find_map(|worktree| {
3673 let tree = worktree.read(cx);
3674 let worktree_root_path = tree.abs_path();
3675 let path_style = tree.path_style();
3676 match &watcher.glob_pattern {
3677 lsp::GlobPattern::String(s) => {
3678 let watcher_path = SanitizedPath::new(s);
3679 let relative = watcher_path
3680 .as_path()
3681 .strip_prefix(&worktree_root_path)
3682 .ok()?;
3683 let literal_prefix = glob_literal_prefix(relative);
3684 Some((
3685 worktree.clone(),
3686 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3687 relative.to_string_lossy().into_owned(),
3688 ))
3689 }
3690 lsp::GlobPattern::Relative(rp) => {
3691 let base_uri = match &rp.base_uri {
3692 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3693 lsp::OneOf::Right(base_uri) => base_uri,
3694 }
3695 .to_file_path()
3696 .ok()?;
3697 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3698 let mut literal_prefix = relative.to_owned();
3699 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3700 Some((
3701 worktree.clone(),
3702 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3703 rp.pattern.clone(),
3704 ))
3705 }
3706 }
3707 })
3708 }
3709
3710 fn rebuild_watched_paths(
3711 &mut self,
3712 language_server_id: LanguageServerId,
3713 cx: &mut Context<LspStore>,
3714 ) {
3715 let Some(registrations) = self
3716 .language_server_dynamic_registrations
3717 .get(&language_server_id)
3718 else {
3719 return;
3720 };
3721
3722 let watch_builder = self.rebuild_watched_paths_inner(
3723 language_server_id,
3724 registrations.did_change_watched_files.values().flatten(),
3725 cx,
3726 );
3727 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3728 self.language_server_watched_paths
3729 .insert(language_server_id, watcher);
3730
3731 cx.notify();
3732 }
3733
3734 fn on_lsp_did_change_watched_files(
3735 &mut self,
3736 language_server_id: LanguageServerId,
3737 registration_id: &str,
3738 params: DidChangeWatchedFilesRegistrationOptions,
3739 cx: &mut Context<LspStore>,
3740 ) {
3741 let registrations = self
3742 .language_server_dynamic_registrations
3743 .entry(language_server_id)
3744 .or_default();
3745
3746 registrations
3747 .did_change_watched_files
3748 .insert(registration_id.to_string(), params.watchers);
3749
3750 self.rebuild_watched_paths(language_server_id, cx);
3751 }
3752
3753 fn on_lsp_unregister_did_change_watched_files(
3754 &mut self,
3755 language_server_id: LanguageServerId,
3756 registration_id: &str,
3757 cx: &mut Context<LspStore>,
3758 ) {
3759 let registrations = self
3760 .language_server_dynamic_registrations
3761 .entry(language_server_id)
3762 .or_default();
3763
3764 if registrations
3765 .did_change_watched_files
3766 .remove(registration_id)
3767 .is_some()
3768 {
3769 log::info!(
3770 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3771 language_server_id,
3772 registration_id
3773 );
3774 } else {
3775 log::warn!(
3776 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3777 language_server_id,
3778 registration_id
3779 );
3780 }
3781
3782 self.rebuild_watched_paths(language_server_id, cx);
3783 }
3784
3785 async fn initialization_options_for_adapter(
3786 adapter: Arc<dyn LspAdapter>,
3787 delegate: &Arc<dyn LspAdapterDelegate>,
3788 cx: &mut AsyncApp,
3789 ) -> Result<Option<serde_json::Value>> {
3790 let Some(mut initialization_config) =
3791 adapter.clone().initialization_options(delegate, cx).await?
3792 else {
3793 return Ok(None);
3794 };
3795
3796 for other_adapter in delegate.registered_lsp_adapters() {
3797 if other_adapter.name() == adapter.name() {
3798 continue;
3799 }
3800 if let Ok(Some(target_config)) = other_adapter
3801 .clone()
3802 .additional_initialization_options(adapter.name(), delegate)
3803 .await
3804 {
3805 merge_json_value_into(target_config.clone(), &mut initialization_config);
3806 }
3807 }
3808
3809 Ok(Some(initialization_config))
3810 }
3811
3812 async fn workspace_configuration_for_adapter(
3813 adapter: Arc<dyn LspAdapter>,
3814 delegate: &Arc<dyn LspAdapterDelegate>,
3815 toolchain: Option<Toolchain>,
3816 requested_uri: Option<Uri>,
3817 cx: &mut AsyncApp,
3818 ) -> Result<serde_json::Value> {
3819 let mut workspace_config = adapter
3820 .clone()
3821 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3822 .await?;
3823
3824 for other_adapter in delegate.registered_lsp_adapters() {
3825 if other_adapter.name() == adapter.name() {
3826 continue;
3827 }
3828 if let Ok(Some(target_config)) = other_adapter
3829 .clone()
3830 .additional_workspace_configuration(adapter.name(), delegate, cx)
3831 .await
3832 {
3833 merge_json_value_into(target_config.clone(), &mut workspace_config);
3834 }
3835 }
3836
3837 Ok(workspace_config)
3838 }
3839
3840 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3841 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3842 Some(server.clone())
3843 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3844 Some(Arc::clone(server))
3845 } else {
3846 None
3847 }
3848 }
3849}
3850
3851fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3852 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3853 cx.emit(LspStoreEvent::LanguageServerUpdate {
3854 language_server_id: server.server_id(),
3855 name: Some(server.name()),
3856 message: proto::update_language_server::Variant::MetadataUpdated(
3857 proto::ServerMetadataUpdated {
3858 capabilities: Some(capabilities),
3859 binary: Some(proto::LanguageServerBinaryInfo {
3860 path: server.binary().path.to_string_lossy().into_owned(),
3861 arguments: server
3862 .binary()
3863 .arguments
3864 .iter()
3865 .map(|arg| arg.to_string_lossy().into_owned())
3866 .collect(),
3867 }),
3868 configuration: serde_json::to_string(server.configuration()).ok(),
3869 workspace_folders: server
3870 .workspace_folders()
3871 .iter()
3872 .map(|uri| uri.to_string())
3873 .collect(),
3874 },
3875 ),
3876 });
3877 }
3878}
3879
3880#[derive(Debug)]
3881pub struct FormattableBuffer {
3882 handle: Entity<Buffer>,
3883 abs_path: Option<PathBuf>,
3884 env: Option<HashMap<String, String>>,
3885 ranges: Option<Vec<Range<Anchor>>>,
3886}
3887
3888pub struct RemoteLspStore {
3889 upstream_client: Option<AnyProtoClient>,
3890 upstream_project_id: u64,
3891}
3892
3893pub(crate) enum LspStoreMode {
3894 Local(LocalLspStore), // ssh host and collab host
3895 Remote(RemoteLspStore), // collab guest
3896}
3897
3898impl LspStoreMode {
3899 fn is_local(&self) -> bool {
3900 matches!(self, LspStoreMode::Local(_))
3901 }
3902}
3903
3904pub struct LspStore {
3905 mode: LspStoreMode,
3906 last_formatting_failure: Option<String>,
3907 downstream_client: Option<(AnyProtoClient, u64)>,
3908 nonce: u128,
3909 buffer_store: Entity<BufferStore>,
3910 worktree_store: Entity<WorktreeStore>,
3911 pub languages: Arc<LanguageRegistry>,
3912 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3913 active_entry: Option<ProjectEntryId>,
3914 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3915 _maintain_buffer_languages: Task<()>,
3916 diagnostic_summaries:
3917 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3918 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3919 semantic_token_config: SemanticTokenConfig,
3920 lsp_data: HashMap<BufferId, BufferLspData>,
3921 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3922 next_hint_id: Arc<AtomicUsize>,
3923}
3924
3925#[derive(Debug)]
3926pub struct BufferLspData {
3927 buffer_version: Global,
3928 document_colors: Option<DocumentColorData>,
3929 code_lens: Option<CodeLensData>,
3930 semantic_tokens: Option<SemanticTokensData>,
3931 folding_ranges: Option<FoldingRangeData>,
3932 document_symbols: Option<DocumentSymbolsData>,
3933 inlay_hints: BufferInlayHints,
3934 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3935 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3936}
3937
3938#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3939struct LspKey {
3940 request_type: TypeId,
3941 server_queried: Option<LanguageServerId>,
3942}
3943
3944impl BufferLspData {
3945 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3946 Self {
3947 buffer_version: buffer.read(cx).version(),
3948 document_colors: None,
3949 code_lens: None,
3950 semantic_tokens: None,
3951 folding_ranges: None,
3952 document_symbols: None,
3953 inlay_hints: BufferInlayHints::new(buffer, cx),
3954 lsp_requests: HashMap::default(),
3955 chunk_lsp_requests: HashMap::default(),
3956 }
3957 }
3958
3959 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3960 if let Some(document_colors) = &mut self.document_colors {
3961 document_colors.remove_server_data(for_server);
3962 }
3963
3964 if let Some(code_lens) = &mut self.code_lens {
3965 code_lens.remove_server_data(for_server);
3966 }
3967
3968 self.inlay_hints.remove_server_data(for_server);
3969
3970 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3971 semantic_tokens.remove_server_data(for_server);
3972 }
3973
3974 if let Some(folding_ranges) = &mut self.folding_ranges {
3975 folding_ranges.ranges.remove(&for_server);
3976 }
3977
3978 if let Some(document_symbols) = &mut self.document_symbols {
3979 document_symbols.remove_server_data(for_server);
3980 }
3981 }
3982
3983 #[cfg(any(test, feature = "test-support"))]
3984 pub fn inlay_hints(&self) -> &BufferInlayHints {
3985 &self.inlay_hints
3986 }
3987}
3988
3989#[derive(Debug)]
3990pub enum LspStoreEvent {
3991 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3992 LanguageServerRemoved(LanguageServerId),
3993 LanguageServerUpdate {
3994 language_server_id: LanguageServerId,
3995 name: Option<LanguageServerName>,
3996 message: proto::update_language_server::Variant,
3997 },
3998 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3999 LanguageServerPrompt(LanguageServerPromptRequest),
4000 LanguageDetected {
4001 buffer: Entity<Buffer>,
4002 new_language: Option<Arc<Language>>,
4003 },
4004 Notification(String),
4005 RefreshInlayHints {
4006 server_id: LanguageServerId,
4007 request_id: Option<usize>,
4008 },
4009 RefreshSemanticTokens {
4010 server_id: LanguageServerId,
4011 request_id: Option<usize>,
4012 },
4013 RefreshCodeLens,
4014 DiagnosticsUpdated {
4015 server_id: LanguageServerId,
4016 paths: Vec<ProjectPath>,
4017 },
4018 DiskBasedDiagnosticsStarted {
4019 language_server_id: LanguageServerId,
4020 },
4021 DiskBasedDiagnosticsFinished {
4022 language_server_id: LanguageServerId,
4023 },
4024 SnippetEdit {
4025 buffer_id: BufferId,
4026 edits: Vec<(lsp::Range, Snippet)>,
4027 most_recent_edit: clock::Lamport,
4028 },
4029 WorkspaceEditApplied(ProjectTransaction),
4030}
4031
4032#[derive(Clone, Debug, Serialize)]
4033pub struct LanguageServerStatus {
4034 pub name: LanguageServerName,
4035 pub server_version: Option<SharedString>,
4036 pub server_readable_version: Option<SharedString>,
4037 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4038 pub has_pending_diagnostic_updates: bool,
4039 pub progress_tokens: HashSet<ProgressToken>,
4040 pub worktree: Option<WorktreeId>,
4041 pub binary: Option<LanguageServerBinary>,
4042 pub configuration: Option<Value>,
4043 pub workspace_folders: BTreeSet<Uri>,
4044 pub process_id: Option<u32>,
4045}
4046
4047#[derive(Clone, Debug)]
4048struct CoreSymbol {
4049 pub language_server_name: LanguageServerName,
4050 pub source_worktree_id: WorktreeId,
4051 pub source_language_server_id: LanguageServerId,
4052 pub path: SymbolLocation,
4053 pub name: String,
4054 pub kind: lsp::SymbolKind,
4055 pub range: Range<Unclipped<PointUtf16>>,
4056 pub container_name: Option<String>,
4057}
4058
4059#[derive(Clone, Debug, PartialEq, Eq)]
4060pub enum SymbolLocation {
4061 InProject(ProjectPath),
4062 OutsideProject {
4063 abs_path: Arc<Path>,
4064 signature: [u8; 32],
4065 },
4066}
4067
4068impl SymbolLocation {
4069 fn file_name(&self) -> Option<&str> {
4070 match self {
4071 Self::InProject(path) => path.path.file_name(),
4072 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4073 }
4074 }
4075}
4076
4077impl LspStore {
4078 pub fn init(client: &AnyProtoClient) {
4079 client.add_entity_request_handler(Self::handle_lsp_query);
4080 client.add_entity_message_handler(Self::handle_lsp_query_response);
4081 client.add_entity_request_handler(Self::handle_restart_language_servers);
4082 client.add_entity_request_handler(Self::handle_stop_language_servers);
4083 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4084 client.add_entity_message_handler(Self::handle_start_language_server);
4085 client.add_entity_message_handler(Self::handle_update_language_server);
4086 client.add_entity_message_handler(Self::handle_language_server_log);
4087 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4088 client.add_entity_request_handler(Self::handle_format_buffers);
4089 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4090 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4091 client.add_entity_request_handler(Self::handle_apply_code_action);
4092 client.add_entity_request_handler(Self::handle_get_project_symbols);
4093 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4094 client.add_entity_request_handler(Self::handle_get_color_presentation);
4095 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4096 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4097 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4098 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4099 client.add_entity_request_handler(Self::handle_on_type_formatting);
4100 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4101 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4102 client.add_entity_request_handler(Self::handle_rename_project_entry);
4103 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4104 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4105 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4106 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4107 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4109 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4110
4111 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4112 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4113 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4114 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4115 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4116 client.add_entity_request_handler(
4117 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4118 );
4119 client.add_entity_request_handler(
4120 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4121 );
4122 client.add_entity_request_handler(
4123 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4124 );
4125 }
4126
4127 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4128 match &self.mode {
4129 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4130 _ => None,
4131 }
4132 }
4133
4134 pub fn as_local(&self) -> Option<&LocalLspStore> {
4135 match &self.mode {
4136 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4137 _ => None,
4138 }
4139 }
4140
4141 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4142 match &mut self.mode {
4143 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4144 _ => None,
4145 }
4146 }
4147
4148 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4149 match &self.mode {
4150 LspStoreMode::Remote(RemoteLspStore {
4151 upstream_client: Some(upstream_client),
4152 upstream_project_id,
4153 ..
4154 }) => Some((upstream_client.clone(), *upstream_project_id)),
4155
4156 LspStoreMode::Remote(RemoteLspStore {
4157 upstream_client: None,
4158 ..
4159 }) => None,
4160 LspStoreMode::Local(_) => None,
4161 }
4162 }
4163
4164 pub fn new_local(
4165 buffer_store: Entity<BufferStore>,
4166 worktree_store: Entity<WorktreeStore>,
4167 prettier_store: Entity<PrettierStore>,
4168 toolchain_store: Entity<LocalToolchainStore>,
4169 environment: Entity<ProjectEnvironment>,
4170 manifest_tree: Entity<ManifestTree>,
4171 languages: Arc<LanguageRegistry>,
4172 http_client: Arc<dyn HttpClient>,
4173 fs: Arc<dyn Fs>,
4174 cx: &mut Context<Self>,
4175 ) -> Self {
4176 let yarn = YarnPathStore::new(fs.clone(), cx);
4177 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4178 .detach();
4179 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4180 .detach();
4181 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4182 .detach();
4183 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4184 .detach();
4185 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4186 .detach();
4187 subscribe_to_binary_statuses(&languages, cx).detach();
4188
4189 let _maintain_workspace_config = {
4190 let (sender, receiver) = watch::channel();
4191 (Self::maintain_workspace_config(receiver, cx), sender)
4192 };
4193
4194 Self {
4195 mode: LspStoreMode::Local(LocalLspStore {
4196 weak: cx.weak_entity(),
4197 worktree_store: worktree_store.clone(),
4198
4199 supplementary_language_servers: Default::default(),
4200 languages: languages.clone(),
4201 language_server_ids: Default::default(),
4202 language_servers: Default::default(),
4203 last_workspace_edits_by_language_server: Default::default(),
4204 language_server_watched_paths: Default::default(),
4205 language_server_paths_watched_for_rename: Default::default(),
4206 language_server_dynamic_registrations: Default::default(),
4207 buffers_being_formatted: Default::default(),
4208 buffers_to_refresh_hash_set: HashSet::default(),
4209 buffers_to_refresh_queue: VecDeque::new(),
4210 _background_diagnostics_worker: Task::ready(()).shared(),
4211 buffer_snapshots: Default::default(),
4212 prettier_store,
4213 environment,
4214 http_client,
4215 fs,
4216 yarn,
4217 next_diagnostic_group_id: Default::default(),
4218 diagnostics: Default::default(),
4219 _subscription: cx.on_app_quit(|this, _| {
4220 this.as_local_mut()
4221 .unwrap()
4222 .shutdown_language_servers_on_quit()
4223 }),
4224 lsp_tree: LanguageServerTree::new(
4225 manifest_tree,
4226 languages.clone(),
4227 toolchain_store.clone(),
4228 ),
4229 toolchain_store,
4230 registered_buffers: HashMap::default(),
4231 buffers_opened_in_servers: HashMap::default(),
4232 buffer_pull_diagnostics_result_ids: HashMap::default(),
4233 workspace_pull_diagnostics_result_ids: HashMap::default(),
4234 restricted_worktrees_tasks: HashMap::default(),
4235 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4236 .manifest_file_names(),
4237 }),
4238 last_formatting_failure: None,
4239 downstream_client: None,
4240 buffer_store,
4241 worktree_store,
4242 languages: languages.clone(),
4243 language_server_statuses: Default::default(),
4244 nonce: StdRng::from_os_rng().random(),
4245 diagnostic_summaries: HashMap::default(),
4246 lsp_server_capabilities: HashMap::default(),
4247 semantic_token_config: SemanticTokenConfig::new(cx),
4248 lsp_data: HashMap::default(),
4249 buffer_reload_tasks: HashMap::default(),
4250 next_hint_id: Arc::default(),
4251 active_entry: None,
4252 _maintain_workspace_config,
4253 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4254 }
4255 }
4256
4257 fn send_lsp_proto_request<R: LspCommand>(
4258 &self,
4259 buffer: Entity<Buffer>,
4260 client: AnyProtoClient,
4261 upstream_project_id: u64,
4262 request: R,
4263 cx: &mut Context<LspStore>,
4264 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4265 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4266 return Task::ready(Ok(R::Response::default()));
4267 }
4268 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4269 cx.spawn(async move |this, cx| {
4270 let response = client.request(message).await?;
4271 let this = this.upgrade().context("project dropped")?;
4272 request
4273 .response_from_proto(response, this, buffer, cx.clone())
4274 .await
4275 })
4276 }
4277
4278 pub(super) fn new_remote(
4279 buffer_store: Entity<BufferStore>,
4280 worktree_store: Entity<WorktreeStore>,
4281 languages: Arc<LanguageRegistry>,
4282 upstream_client: AnyProtoClient,
4283 project_id: u64,
4284 cx: &mut Context<Self>,
4285 ) -> Self {
4286 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4287 .detach();
4288 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4289 .detach();
4290 subscribe_to_binary_statuses(&languages, cx).detach();
4291 let _maintain_workspace_config = {
4292 let (sender, receiver) = watch::channel();
4293 (Self::maintain_workspace_config(receiver, cx), sender)
4294 };
4295 Self {
4296 mode: LspStoreMode::Remote(RemoteLspStore {
4297 upstream_client: Some(upstream_client),
4298 upstream_project_id: project_id,
4299 }),
4300 downstream_client: None,
4301 last_formatting_failure: None,
4302 buffer_store,
4303 worktree_store,
4304 languages: languages.clone(),
4305 language_server_statuses: Default::default(),
4306 nonce: StdRng::from_os_rng().random(),
4307 diagnostic_summaries: HashMap::default(),
4308 lsp_server_capabilities: HashMap::default(),
4309 semantic_token_config: SemanticTokenConfig::new(cx),
4310 next_hint_id: Arc::default(),
4311 lsp_data: HashMap::default(),
4312 buffer_reload_tasks: HashMap::default(),
4313 active_entry: None,
4314
4315 _maintain_workspace_config,
4316 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4317 }
4318 }
4319
4320 fn on_buffer_store_event(
4321 &mut self,
4322 _: Entity<BufferStore>,
4323 event: &BufferStoreEvent,
4324 cx: &mut Context<Self>,
4325 ) {
4326 match event {
4327 BufferStoreEvent::BufferAdded(buffer) => {
4328 self.on_buffer_added(buffer, cx).log_err();
4329 }
4330 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4331 let buffer_id = buffer.read(cx).remote_id();
4332 if let Some(local) = self.as_local_mut()
4333 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4334 {
4335 local.reset_buffer(buffer, old_file, cx);
4336
4337 if local.registered_buffers.contains_key(&buffer_id) {
4338 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4339 }
4340 }
4341
4342 self.detect_language_for_buffer(buffer, cx);
4343 if let Some(local) = self.as_local_mut() {
4344 local.initialize_buffer(buffer, cx);
4345 if local.registered_buffers.contains_key(&buffer_id) {
4346 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4347 }
4348 }
4349 }
4350 _ => {}
4351 }
4352 }
4353
4354 fn on_worktree_store_event(
4355 &mut self,
4356 _: Entity<WorktreeStore>,
4357 event: &WorktreeStoreEvent,
4358 cx: &mut Context<Self>,
4359 ) {
4360 match event {
4361 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4362 if !worktree.read(cx).is_local() {
4363 return;
4364 }
4365 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4366 worktree::Event::UpdatedEntries(changes) => {
4367 this.update_local_worktree_language_servers(&worktree, changes, cx);
4368 }
4369 worktree::Event::UpdatedGitRepositories(_)
4370 | worktree::Event::DeletedEntry(_) => {}
4371 })
4372 .detach()
4373 }
4374 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4375 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4376 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4377 }
4378 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4379 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4380 }
4381 WorktreeStoreEvent::WorktreeReleased(..)
4382 | WorktreeStoreEvent::WorktreeOrderChanged
4383 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4384 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4385 }
4386 }
4387
4388 fn on_prettier_store_event(
4389 &mut self,
4390 _: Entity<PrettierStore>,
4391 event: &PrettierStoreEvent,
4392 cx: &mut Context<Self>,
4393 ) {
4394 match event {
4395 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4396 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4397 }
4398 PrettierStoreEvent::LanguageServerAdded {
4399 new_server_id,
4400 name,
4401 prettier_server,
4402 } => {
4403 self.register_supplementary_language_server(
4404 *new_server_id,
4405 name.clone(),
4406 prettier_server.clone(),
4407 cx,
4408 );
4409 }
4410 }
4411 }
4412
4413 fn on_toolchain_store_event(
4414 &mut self,
4415 _: Entity<LocalToolchainStore>,
4416 event: &ToolchainStoreEvent,
4417 _: &mut Context<Self>,
4418 ) {
4419 if let ToolchainStoreEvent::ToolchainActivated = event {
4420 self.request_workspace_config_refresh()
4421 }
4422 }
4423
4424 fn request_workspace_config_refresh(&mut self) {
4425 *self._maintain_workspace_config.1.borrow_mut() = ();
4426 }
4427
4428 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4429 self.as_local().map(|local| local.prettier_store.clone())
4430 }
4431
4432 fn on_buffer_event(
4433 &mut self,
4434 buffer: Entity<Buffer>,
4435 event: &language::BufferEvent,
4436 cx: &mut Context<Self>,
4437 ) {
4438 match event {
4439 language::BufferEvent::Edited { .. } => {
4440 self.on_buffer_edited(buffer, cx);
4441 }
4442
4443 language::BufferEvent::Saved => {
4444 self.on_buffer_saved(buffer, cx);
4445 }
4446
4447 language::BufferEvent::Reloaded => {
4448 self.on_buffer_reloaded(buffer, cx);
4449 }
4450
4451 _ => {}
4452 }
4453 }
4454
4455 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4456 buffer
4457 .read(cx)
4458 .set_language_registry(self.languages.clone());
4459
4460 cx.subscribe(buffer, |this, buffer, event, cx| {
4461 this.on_buffer_event(buffer, event, cx);
4462 })
4463 .detach();
4464
4465 self.detect_language_for_buffer(buffer, cx);
4466 if let Some(local) = self.as_local_mut() {
4467 local.initialize_buffer(buffer, cx);
4468 }
4469
4470 Ok(())
4471 }
4472
4473 pub fn refresh_background_diagnostics_for_buffers(
4474 &mut self,
4475 buffers: HashSet<BufferId>,
4476 cx: &mut Context<Self>,
4477 ) -> Shared<Task<()>> {
4478 let Some(local) = self.as_local_mut() else {
4479 return Task::ready(()).shared();
4480 };
4481 for buffer in buffers {
4482 if local.buffers_to_refresh_hash_set.insert(buffer) {
4483 local.buffers_to_refresh_queue.push_back(buffer);
4484 if local.buffers_to_refresh_queue.len() == 1 {
4485 local._background_diagnostics_worker =
4486 Self::background_diagnostics_worker(cx).shared();
4487 }
4488 }
4489 }
4490
4491 local._background_diagnostics_worker.clone()
4492 }
4493
4494 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4495 let buffer_store = self.buffer_store.clone();
4496 let local = self.as_local_mut()?;
4497 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4498 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4499 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4500 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4501 }
4502 }
4503 None
4504 }
4505
4506 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4507 cx.spawn(async move |this, cx| {
4508 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4509 task.await.log_err();
4510 }
4511 })
4512 }
4513
4514 pub(crate) fn register_buffer_with_language_servers(
4515 &mut self,
4516 buffer: &Entity<Buffer>,
4517 only_register_servers: HashSet<LanguageServerSelector>,
4518 ignore_refcounts: bool,
4519 cx: &mut Context<Self>,
4520 ) -> OpenLspBufferHandle {
4521 let buffer_id = buffer.read(cx).remote_id();
4522 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4523 if let Some(local) = self.as_local_mut() {
4524 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4525 if !ignore_refcounts {
4526 *refcount += 1;
4527 }
4528
4529 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4530 // 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
4531 // 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
4532 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4533 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4534 return handle;
4535 };
4536 if !file.is_local() {
4537 return handle;
4538 }
4539
4540 if ignore_refcounts || *refcount == 1 {
4541 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4542 }
4543 if !ignore_refcounts {
4544 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4545 let refcount = {
4546 let local = lsp_store.as_local_mut().unwrap();
4547 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4548 debug_panic!("bad refcounting");
4549 return;
4550 };
4551
4552 *refcount -= 1;
4553 *refcount
4554 };
4555 if refcount == 0 {
4556 lsp_store.lsp_data.remove(&buffer_id);
4557 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4558 let local = lsp_store.as_local_mut().unwrap();
4559 local.registered_buffers.remove(&buffer_id);
4560
4561 local.buffers_opened_in_servers.remove(&buffer_id);
4562 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4563 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4564
4565 let buffer_abs_path = file.abs_path(cx);
4566 for (_, buffer_pull_diagnostics_result_ids) in
4567 &mut local.buffer_pull_diagnostics_result_ids
4568 {
4569 buffer_pull_diagnostics_result_ids.retain(
4570 |_, buffer_result_ids| {
4571 buffer_result_ids.remove(&buffer_abs_path);
4572 !buffer_result_ids.is_empty()
4573 },
4574 );
4575 }
4576
4577 let diagnostic_updates = local
4578 .language_servers
4579 .keys()
4580 .cloned()
4581 .map(|server_id| DocumentDiagnosticsUpdate {
4582 diagnostics: DocumentDiagnostics {
4583 document_abs_path: buffer_abs_path.clone(),
4584 version: None,
4585 diagnostics: Vec::new(),
4586 },
4587 result_id: None,
4588 registration_id: None,
4589 server_id,
4590 disk_based_sources: Cow::Borrowed(&[]),
4591 })
4592 .collect::<Vec<_>>();
4593
4594 lsp_store
4595 .merge_diagnostic_entries(
4596 diagnostic_updates,
4597 |_, diagnostic, _| {
4598 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4599 },
4600 cx,
4601 )
4602 .context("Clearing diagnostics for the closed buffer")
4603 .log_err();
4604 }
4605 }
4606 })
4607 .detach();
4608 }
4609 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4610 let buffer_id = buffer.read(cx).remote_id().to_proto();
4611 cx.background_spawn(async move {
4612 upstream_client
4613 .request(proto::RegisterBufferWithLanguageServers {
4614 project_id: upstream_project_id,
4615 buffer_id,
4616 only_servers: only_register_servers
4617 .into_iter()
4618 .map(|selector| {
4619 let selector = match selector {
4620 LanguageServerSelector::Id(language_server_id) => {
4621 proto::language_server_selector::Selector::ServerId(
4622 language_server_id.to_proto(),
4623 )
4624 }
4625 LanguageServerSelector::Name(language_server_name) => {
4626 proto::language_server_selector::Selector::Name(
4627 language_server_name.to_string(),
4628 )
4629 }
4630 };
4631 proto::LanguageServerSelector {
4632 selector: Some(selector),
4633 }
4634 })
4635 .collect(),
4636 })
4637 .await
4638 })
4639 .detach();
4640 } else {
4641 // Our remote connection got closed
4642 }
4643 handle
4644 }
4645
4646 fn maintain_buffer_languages(
4647 languages: Arc<LanguageRegistry>,
4648 cx: &mut Context<Self>,
4649 ) -> Task<()> {
4650 let mut subscription = languages.subscribe();
4651 let mut prev_reload_count = languages.reload_count();
4652 cx.spawn(async move |this, cx| {
4653 while let Some(()) = subscription.next().await {
4654 if let Some(this) = this.upgrade() {
4655 // If the language registry has been reloaded, then remove and
4656 // re-assign the languages on all open buffers.
4657 let reload_count = languages.reload_count();
4658 if reload_count > prev_reload_count {
4659 prev_reload_count = reload_count;
4660 this.update(cx, |this, cx| {
4661 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4662 for buffer in buffer_store.buffers() {
4663 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4664 {
4665 buffer.update(cx, |buffer, cx| {
4666 buffer.set_language_async(None, cx)
4667 });
4668 if let Some(local) = this.as_local_mut() {
4669 local.reset_buffer(&buffer, &f, cx);
4670
4671 if local
4672 .registered_buffers
4673 .contains_key(&buffer.read(cx).remote_id())
4674 && let Some(file_url) =
4675 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4676 {
4677 local.unregister_buffer_from_language_servers(
4678 &buffer, &file_url, cx,
4679 );
4680 }
4681 }
4682 }
4683 }
4684 });
4685 });
4686 }
4687
4688 this.update(cx, |this, cx| {
4689 let mut plain_text_buffers = Vec::new();
4690 let mut buffers_with_unknown_injections = Vec::new();
4691 for handle in this.buffer_store.read(cx).buffers() {
4692 let buffer = handle.read(cx);
4693 if buffer.language().is_none()
4694 || buffer.language() == Some(&*language::PLAIN_TEXT)
4695 {
4696 plain_text_buffers.push(handle);
4697 } else if buffer.contains_unknown_injections() {
4698 buffers_with_unknown_injections.push(handle);
4699 }
4700 }
4701
4702 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4703 // and reused later in the invisible worktrees.
4704 plain_text_buffers.sort_by_key(|buffer| {
4705 Reverse(
4706 File::from_dyn(buffer.read(cx).file())
4707 .map(|file| file.worktree.read(cx).is_visible()),
4708 )
4709 });
4710
4711 for buffer in plain_text_buffers {
4712 this.detect_language_for_buffer(&buffer, cx);
4713 if let Some(local) = this.as_local_mut() {
4714 local.initialize_buffer(&buffer, cx);
4715 if local
4716 .registered_buffers
4717 .contains_key(&buffer.read(cx).remote_id())
4718 {
4719 local.register_buffer_with_language_servers(
4720 &buffer,
4721 HashSet::default(),
4722 cx,
4723 );
4724 }
4725 }
4726 }
4727
4728 for buffer in buffers_with_unknown_injections {
4729 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4730 }
4731 });
4732 }
4733 }
4734 })
4735 }
4736
4737 fn detect_language_for_buffer(
4738 &mut self,
4739 buffer_handle: &Entity<Buffer>,
4740 cx: &mut Context<Self>,
4741 ) -> Option<language::AvailableLanguage> {
4742 // If the buffer has a language, set it and start the language server if we haven't already.
4743 let buffer = buffer_handle.read(cx);
4744 let file = buffer.file()?;
4745
4746 let content = buffer.as_rope();
4747 let available_language = self.languages.language_for_file(file, Some(content), cx);
4748 if let Some(available_language) = &available_language {
4749 if let Some(Ok(Ok(new_language))) = self
4750 .languages
4751 .load_language(available_language)
4752 .now_or_never()
4753 {
4754 self.set_language_for_buffer(buffer_handle, new_language, cx);
4755 }
4756 } else {
4757 cx.emit(LspStoreEvent::LanguageDetected {
4758 buffer: buffer_handle.clone(),
4759 new_language: None,
4760 });
4761 }
4762
4763 available_language
4764 }
4765
4766 pub(crate) fn set_language_for_buffer(
4767 &mut self,
4768 buffer_entity: &Entity<Buffer>,
4769 new_language: Arc<Language>,
4770 cx: &mut Context<Self>,
4771 ) {
4772 let buffer = buffer_entity.read(cx);
4773 let buffer_file = buffer.file().cloned();
4774 let buffer_id = buffer.remote_id();
4775 if let Some(local_store) = self.as_local_mut()
4776 && local_store.registered_buffers.contains_key(&buffer_id)
4777 && let Some(abs_path) =
4778 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4779 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4780 {
4781 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4782 }
4783 buffer_entity.update(cx, |buffer, cx| {
4784 if buffer
4785 .language()
4786 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4787 {
4788 buffer.set_language_async(Some(new_language.clone()), cx);
4789 }
4790 });
4791
4792 let settings =
4793 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4794 let buffer_file = File::from_dyn(buffer_file.as_ref());
4795
4796 let worktree_id = if let Some(file) = buffer_file {
4797 let worktree = file.worktree.clone();
4798
4799 if let Some(local) = self.as_local_mut()
4800 && local.registered_buffers.contains_key(&buffer_id)
4801 {
4802 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4803 }
4804 Some(worktree.read(cx).id())
4805 } else {
4806 None
4807 };
4808
4809 if settings.prettier.allowed
4810 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4811 {
4812 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4813 if let Some(prettier_store) = prettier_store {
4814 prettier_store.update(cx, |prettier_store, cx| {
4815 prettier_store.install_default_prettier(
4816 worktree_id,
4817 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4818 cx,
4819 )
4820 })
4821 }
4822 }
4823
4824 cx.emit(LspStoreEvent::LanguageDetected {
4825 buffer: buffer_entity.clone(),
4826 new_language: Some(new_language),
4827 })
4828 }
4829
4830 pub fn buffer_store(&self) -> Entity<BufferStore> {
4831 self.buffer_store.clone()
4832 }
4833
4834 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4835 self.active_entry = active_entry;
4836 }
4837
4838 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4839 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4840 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4841 {
4842 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4843 summaries
4844 .iter()
4845 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4846 });
4847 if let Some(summary) = summaries.next() {
4848 client
4849 .send(proto::UpdateDiagnosticSummary {
4850 project_id: downstream_project_id,
4851 worktree_id: worktree.id().to_proto(),
4852 summary: Some(summary),
4853 more_summaries: summaries.collect(),
4854 })
4855 .log_err();
4856 }
4857 }
4858 }
4859
4860 fn is_capable_for_proto_request<R>(
4861 &self,
4862 buffer: &Entity<Buffer>,
4863 request: &R,
4864 cx: &App,
4865 ) -> bool
4866 where
4867 R: LspCommand,
4868 {
4869 self.check_if_capable_for_proto_request(
4870 buffer,
4871 |capabilities| {
4872 request.check_capabilities(AdapterServerCapabilities {
4873 server_capabilities: capabilities.clone(),
4874 code_action_kinds: None,
4875 })
4876 },
4877 cx,
4878 )
4879 }
4880
4881 fn check_if_capable_for_proto_request<F>(
4882 &self,
4883 buffer: &Entity<Buffer>,
4884 check: F,
4885 cx: &App,
4886 ) -> bool
4887 where
4888 F: FnMut(&lsp::ServerCapabilities) -> bool,
4889 {
4890 let Some(language) = buffer.read(cx).language().cloned() else {
4891 return false;
4892 };
4893 let registered_language_servers = self
4894 .languages
4895 .lsp_adapters(&language.name())
4896 .into_iter()
4897 .map(|lsp_adapter| lsp_adapter.name())
4898 .collect::<HashSet<_>>();
4899 self.language_server_statuses
4900 .iter()
4901 .filter_map(|(server_id, server_status)| {
4902 // Include servers that are either registered for this language OR
4903 // available to be loaded (for SSH remote mode where adapters like
4904 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4905 // but only loaded on the server side)
4906 let is_relevant = registered_language_servers.contains(&server_status.name)
4907 || self.languages.is_lsp_adapter_available(&server_status.name);
4908 is_relevant.then_some(server_id)
4909 })
4910 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4911 .any(check)
4912 }
4913
4914 fn all_capable_for_proto_request<F>(
4915 &self,
4916 buffer: &Entity<Buffer>,
4917 mut check: F,
4918 cx: &App,
4919 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4920 where
4921 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4922 {
4923 let Some(language) = buffer.read(cx).language().cloned() else {
4924 return Vec::default();
4925 };
4926 let registered_language_servers = self
4927 .languages
4928 .lsp_adapters(&language.name())
4929 .into_iter()
4930 .map(|lsp_adapter| lsp_adapter.name())
4931 .collect::<HashSet<_>>();
4932 self.language_server_statuses
4933 .iter()
4934 .filter_map(|(server_id, server_status)| {
4935 // Include servers that are either registered for this language OR
4936 // available to be loaded (for SSH remote mode where adapters like
4937 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4938 // but only loaded on the server side)
4939 let is_relevant = registered_language_servers.contains(&server_status.name)
4940 || self.languages.is_lsp_adapter_available(&server_status.name);
4941 is_relevant.then_some((server_id, &server_status.name))
4942 })
4943 .filter_map(|(server_id, server_name)| {
4944 self.lsp_server_capabilities
4945 .get(server_id)
4946 .map(|c| (server_id, server_name, c))
4947 })
4948 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4949 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4950 .collect()
4951 }
4952
4953 pub fn request_lsp<R>(
4954 &mut self,
4955 buffer: Entity<Buffer>,
4956 server: LanguageServerToQuery,
4957 request: R,
4958 cx: &mut Context<Self>,
4959 ) -> Task<Result<R::Response>>
4960 where
4961 R: LspCommand,
4962 <R::LspRequest as lsp::request::Request>::Result: Send,
4963 <R::LspRequest as lsp::request::Request>::Params: Send,
4964 {
4965 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4966 return self.send_lsp_proto_request(
4967 buffer,
4968 upstream_client,
4969 upstream_project_id,
4970 request,
4971 cx,
4972 );
4973 }
4974
4975 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4976 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4977 local
4978 .language_servers_for_buffer(buffer, cx)
4979 .find(|(_, server)| {
4980 request.check_capabilities(server.adapter_server_capabilities())
4981 })
4982 .map(|(_, server)| server.clone())
4983 }),
4984 LanguageServerToQuery::Other(id) => self
4985 .language_server_for_local_buffer(buffer, id, cx)
4986 .and_then(|(_, server)| {
4987 request
4988 .check_capabilities(server.adapter_server_capabilities())
4989 .then(|| Arc::clone(server))
4990 }),
4991 }) else {
4992 return Task::ready(Ok(Default::default()));
4993 };
4994
4995 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4996
4997 let Some(file) = file else {
4998 return Task::ready(Ok(Default::default()));
4999 };
5000
5001 let lsp_params = match request.to_lsp_params_or_response(
5002 &file.abs_path(cx),
5003 buffer.read(cx),
5004 &language_server,
5005 cx,
5006 ) {
5007 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5008 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5009 Err(err) => {
5010 let message = format!(
5011 "{} via {} failed: {}",
5012 request.display_name(),
5013 language_server.name(),
5014 err
5015 );
5016 // rust-analyzer likes to error with this when its still loading up
5017 if !message.ends_with("content modified") {
5018 log::warn!("{message}");
5019 }
5020 return Task::ready(Err(anyhow!(message)));
5021 }
5022 };
5023
5024 let status = request.status();
5025 let request_timeout = ProjectSettings::get_global(cx)
5026 .global_lsp_settings
5027 .get_request_timeout();
5028
5029 cx.spawn(async move |this, cx| {
5030 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5031
5032 let id = lsp_request.id();
5033 let _cleanup = if status.is_some() {
5034 cx.update(|cx| {
5035 this.update(cx, |this, cx| {
5036 this.on_lsp_work_start(
5037 language_server.server_id(),
5038 ProgressToken::Number(id),
5039 LanguageServerProgress {
5040 is_disk_based_diagnostics_progress: false,
5041 is_cancellable: false,
5042 title: None,
5043 message: status.clone(),
5044 percentage: None,
5045 last_update_at: cx.background_executor().now(),
5046 },
5047 cx,
5048 );
5049 })
5050 })
5051 .log_err();
5052
5053 Some(defer(|| {
5054 cx.update(|cx| {
5055 this.update(cx, |this, cx| {
5056 this.on_lsp_work_end(
5057 language_server.server_id(),
5058 ProgressToken::Number(id),
5059 cx,
5060 );
5061 })
5062 })
5063 .log_err();
5064 }))
5065 } else {
5066 None
5067 };
5068
5069 let result = lsp_request.await.into_response();
5070
5071 let response = result.map_err(|err| {
5072 let message = format!(
5073 "{} via {} failed: {}",
5074 request.display_name(),
5075 language_server.name(),
5076 err
5077 );
5078 // rust-analyzer likes to error with this when its still loading up
5079 if !message.ends_with("content modified") {
5080 log::warn!("{message}");
5081 }
5082 anyhow::anyhow!(message)
5083 })?;
5084
5085 request
5086 .response_from_lsp(
5087 response,
5088 this.upgrade().context("no app context")?,
5089 buffer,
5090 language_server.server_id(),
5091 cx.clone(),
5092 )
5093 .await
5094 })
5095 }
5096
5097 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5098 let mut language_formatters_to_check = Vec::new();
5099 for buffer in self.buffer_store.read(cx).buffers() {
5100 let buffer = buffer.read(cx);
5101 let buffer_file = File::from_dyn(buffer.file());
5102 let buffer_language = buffer.language();
5103 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5104 if buffer_language.is_some() {
5105 language_formatters_to_check.push((
5106 buffer_file.map(|f| f.worktree_id(cx)),
5107 settings.into_owned(),
5108 ));
5109 }
5110 }
5111
5112 self.request_workspace_config_refresh();
5113
5114 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5115 prettier_store.update(cx, |prettier_store, cx| {
5116 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5117 })
5118 }
5119
5120 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5121 .global_lsp_settings
5122 .semantic_token_rules
5123 .clone();
5124 self.semantic_token_config
5125 .update_rules(new_semantic_token_rules);
5126 // Always clear cached stylizers so that changes to language-specific
5127 // semantic token rules (e.g. from extension install/uninstall) are
5128 // picked up. Stylizers are recreated lazily, so this is cheap.
5129 self.semantic_token_config.clear_stylizers();
5130
5131 let new_global_semantic_tokens_mode =
5132 all_language_settings(None, cx).defaults.semantic_tokens;
5133 if self
5134 .semantic_token_config
5135 .update_global_mode(new_global_semantic_tokens_mode)
5136 {
5137 self.restart_all_language_servers(cx);
5138 }
5139
5140 cx.notify();
5141 }
5142
5143 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5144 let buffer_store = self.buffer_store.clone();
5145 let Some(local) = self.as_local_mut() else {
5146 return;
5147 };
5148 let mut adapters = BTreeMap::default();
5149 let get_adapter = {
5150 let languages = local.languages.clone();
5151 let environment = local.environment.clone();
5152 let weak = local.weak.clone();
5153 let worktree_store = local.worktree_store.clone();
5154 let http_client = local.http_client.clone();
5155 let fs = local.fs.clone();
5156 move |worktree_id, cx: &mut App| {
5157 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5158 Some(LocalLspAdapterDelegate::new(
5159 languages.clone(),
5160 &environment,
5161 weak.clone(),
5162 &worktree,
5163 http_client.clone(),
5164 fs.clone(),
5165 cx,
5166 ))
5167 }
5168 };
5169
5170 let mut messages_to_report = Vec::new();
5171 let (new_tree, to_stop) = {
5172 let mut rebase = local.lsp_tree.rebase();
5173 let buffers = buffer_store
5174 .read(cx)
5175 .buffers()
5176 .filter_map(|buffer| {
5177 let raw_buffer = buffer.read(cx);
5178 if !local
5179 .registered_buffers
5180 .contains_key(&raw_buffer.remote_id())
5181 {
5182 return None;
5183 }
5184 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5185 let language = raw_buffer.language().cloned()?;
5186 Some((file, language, raw_buffer.remote_id()))
5187 })
5188 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5189 for (file, language, buffer_id) in buffers {
5190 let worktree_id = file.worktree_id(cx);
5191 let Some(worktree) = local
5192 .worktree_store
5193 .read(cx)
5194 .worktree_for_id(worktree_id, cx)
5195 else {
5196 continue;
5197 };
5198
5199 if let Some((_, apply)) = local.reuse_existing_language_server(
5200 rebase.server_tree(),
5201 &worktree,
5202 &language.name(),
5203 cx,
5204 ) {
5205 (apply)(rebase.server_tree());
5206 } else if let Some(lsp_delegate) = adapters
5207 .entry(worktree_id)
5208 .or_insert_with(|| get_adapter(worktree_id, cx))
5209 .clone()
5210 {
5211 let delegate =
5212 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5213 let path = file
5214 .path()
5215 .parent()
5216 .map(Arc::from)
5217 .unwrap_or_else(|| file.path().clone());
5218 let worktree_path = ProjectPath { worktree_id, path };
5219 let abs_path = file.abs_path(cx);
5220 let nodes = rebase
5221 .walk(
5222 worktree_path,
5223 language.name(),
5224 language.manifest(),
5225 delegate.clone(),
5226 cx,
5227 )
5228 .collect::<Vec<_>>();
5229 for node in nodes {
5230 let server_id = node.server_id_or_init(|disposition| {
5231 let path = &disposition.path;
5232 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5233 let key = LanguageServerSeed {
5234 worktree_id,
5235 name: disposition.server_name.clone(),
5236 settings: LanguageServerSeedSettings {
5237 binary: disposition.settings.binary.clone(),
5238 initialization_options: disposition
5239 .settings
5240 .initialization_options
5241 .clone(),
5242 },
5243 toolchain: local.toolchain_store.read(cx).active_toolchain(
5244 path.worktree_id,
5245 &path.path,
5246 language.name(),
5247 ),
5248 };
5249 local.language_server_ids.remove(&key);
5250
5251 let server_id = local.get_or_insert_language_server(
5252 &worktree,
5253 lsp_delegate.clone(),
5254 disposition,
5255 &language.name(),
5256 cx,
5257 );
5258 if let Some(state) = local.language_servers.get(&server_id)
5259 && let Ok(uri) = uri
5260 {
5261 state.add_workspace_folder(uri);
5262 };
5263 server_id
5264 });
5265
5266 if let Some(language_server_id) = server_id {
5267 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5268 language_server_id,
5269 name: node.name(),
5270 message:
5271 proto::update_language_server::Variant::RegisteredForBuffer(
5272 proto::RegisteredForBuffer {
5273 buffer_abs_path: abs_path
5274 .to_string_lossy()
5275 .into_owned(),
5276 buffer_id: buffer_id.to_proto(),
5277 },
5278 ),
5279 });
5280 }
5281 }
5282 } else {
5283 continue;
5284 }
5285 }
5286 rebase.finish()
5287 };
5288 for message in messages_to_report {
5289 cx.emit(message);
5290 }
5291 local.lsp_tree = new_tree;
5292 for (id, _) in to_stop {
5293 self.stop_local_language_server(id, cx).detach();
5294 }
5295 }
5296
5297 pub fn apply_code_action(
5298 &self,
5299 buffer_handle: Entity<Buffer>,
5300 mut action: CodeAction,
5301 push_to_history: bool,
5302 cx: &mut Context<Self>,
5303 ) -> Task<Result<ProjectTransaction>> {
5304 if let Some((upstream_client, project_id)) = self.upstream_client() {
5305 let request = proto::ApplyCodeAction {
5306 project_id,
5307 buffer_id: buffer_handle.read(cx).remote_id().into(),
5308 action: Some(Self::serialize_code_action(&action)),
5309 };
5310 let buffer_store = self.buffer_store();
5311 cx.spawn(async move |_, cx| {
5312 let response = upstream_client
5313 .request(request)
5314 .await?
5315 .transaction
5316 .context("missing transaction")?;
5317
5318 buffer_store
5319 .update(cx, |buffer_store, cx| {
5320 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5321 })
5322 .await
5323 })
5324 } else if self.mode.is_local() {
5325 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5326 let request_timeout = ProjectSettings::get_global(cx)
5327 .global_lsp_settings
5328 .get_request_timeout();
5329 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5330 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5331 }) else {
5332 return Task::ready(Ok(ProjectTransaction::default()));
5333 };
5334
5335 cx.spawn(async move |this, cx| {
5336 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5337 .await
5338 .context("resolving a code action")?;
5339 if let Some(edit) = action.lsp_action.edit()
5340 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5341 return LocalLspStore::deserialize_workspace_edit(
5342 this.upgrade().context("no app present")?,
5343 edit.clone(),
5344 push_to_history,
5345
5346 lang_server.clone(),
5347 cx,
5348 )
5349 .await;
5350 }
5351
5352 let Some(command) = action.lsp_action.command() else {
5353 return Ok(ProjectTransaction::default())
5354 };
5355
5356 let server_capabilities = lang_server.capabilities();
5357 let available_commands = server_capabilities
5358 .execute_command_provider
5359 .as_ref()
5360 .map(|options| options.commands.as_slice())
5361 .unwrap_or_default();
5362
5363 if !available_commands.contains(&command.command) {
5364 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5365 return Ok(ProjectTransaction::default())
5366 }
5367
5368 let request_timeout = cx.update(|app|
5369 ProjectSettings::get_global(app)
5370 .global_lsp_settings
5371 .get_request_timeout()
5372 );
5373
5374 this.update(cx, |this, _| {
5375 this.as_local_mut()
5376 .unwrap()
5377 .last_workspace_edits_by_language_server
5378 .remove(&lang_server.server_id());
5379 })?;
5380
5381 let _result = lang_server
5382 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5383 command: command.command.clone(),
5384 arguments: command.arguments.clone().unwrap_or_default(),
5385 ..lsp::ExecuteCommandParams::default()
5386 }, request_timeout)
5387 .await.into_response()
5388 .context("execute command")?;
5389
5390 return this.update(cx, |this, _| {
5391 this.as_local_mut()
5392 .unwrap()
5393 .last_workspace_edits_by_language_server
5394 .remove(&lang_server.server_id())
5395 .unwrap_or_default()
5396 });
5397 })
5398 } else {
5399 Task::ready(Err(anyhow!("no upstream client and not local")))
5400 }
5401 }
5402
5403 pub fn apply_code_action_kind(
5404 &mut self,
5405 buffers: HashSet<Entity<Buffer>>,
5406 kind: CodeActionKind,
5407 push_to_history: bool,
5408 cx: &mut Context<Self>,
5409 ) -> Task<anyhow::Result<ProjectTransaction>> {
5410 if self.as_local().is_some() {
5411 cx.spawn(async move |lsp_store, cx| {
5412 let buffers = buffers.into_iter().collect::<Vec<_>>();
5413 let result = LocalLspStore::execute_code_action_kind_locally(
5414 lsp_store.clone(),
5415 buffers,
5416 kind,
5417 push_to_history,
5418 cx,
5419 )
5420 .await;
5421 lsp_store.update(cx, |lsp_store, _| {
5422 lsp_store.update_last_formatting_failure(&result);
5423 })?;
5424 result
5425 })
5426 } else if let Some((client, project_id)) = self.upstream_client() {
5427 let buffer_store = self.buffer_store();
5428 cx.spawn(async move |lsp_store, cx| {
5429 let result = client
5430 .request(proto::ApplyCodeActionKind {
5431 project_id,
5432 kind: kind.as_str().to_owned(),
5433 buffer_ids: buffers
5434 .iter()
5435 .map(|buffer| {
5436 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5437 })
5438 .collect(),
5439 })
5440 .await
5441 .and_then(|result| result.transaction.context("missing transaction"));
5442 lsp_store.update(cx, |lsp_store, _| {
5443 lsp_store.update_last_formatting_failure(&result);
5444 })?;
5445
5446 let transaction_response = result?;
5447 buffer_store
5448 .update(cx, |buffer_store, cx| {
5449 buffer_store.deserialize_project_transaction(
5450 transaction_response,
5451 push_to_history,
5452 cx,
5453 )
5454 })
5455 .await
5456 })
5457 } else {
5458 Task::ready(Ok(ProjectTransaction::default()))
5459 }
5460 }
5461
5462 pub fn resolved_hint(
5463 &mut self,
5464 buffer_id: BufferId,
5465 id: InlayId,
5466 cx: &mut Context<Self>,
5467 ) -> Option<ResolvedHint> {
5468 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5469
5470 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5471 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5472 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5473 let (server_id, resolve_data) = match &hint.resolve_state {
5474 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5475 ResolveState::Resolving => {
5476 return Some(ResolvedHint::Resolving(
5477 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5478 ));
5479 }
5480 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5481 };
5482
5483 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5484 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5485 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5486 id,
5487 cx.spawn(async move |lsp_store, cx| {
5488 let resolved_hint = resolve_task.await;
5489 lsp_store
5490 .update(cx, |lsp_store, _| {
5491 if let Some(old_inlay_hint) = lsp_store
5492 .lsp_data
5493 .get_mut(&buffer_id)
5494 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5495 {
5496 match resolved_hint {
5497 Ok(resolved_hint) => {
5498 *old_inlay_hint = resolved_hint;
5499 }
5500 Err(e) => {
5501 old_inlay_hint.resolve_state =
5502 ResolveState::CanResolve(server_id, resolve_data);
5503 log::error!("Inlay hint resolve failed: {e:#}");
5504 }
5505 }
5506 }
5507 })
5508 .ok();
5509 })
5510 .shared(),
5511 );
5512 debug_assert!(
5513 previous_task.is_none(),
5514 "Did not change hint's resolve state after spawning its resolve"
5515 );
5516 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5517 None
5518 }
5519
5520 pub(crate) fn linked_edits(
5521 &mut self,
5522 buffer: &Entity<Buffer>,
5523 position: Anchor,
5524 cx: &mut Context<Self>,
5525 ) -> Task<Result<Vec<Range<Anchor>>>> {
5526 let snapshot = buffer.read(cx).snapshot();
5527 let scope = snapshot.language_scope_at(position);
5528 let Some(server_id) = self
5529 .as_local()
5530 .and_then(|local| {
5531 buffer.update(cx, |buffer, cx| {
5532 local
5533 .language_servers_for_buffer(buffer, cx)
5534 .filter(|(_, server)| {
5535 LinkedEditingRange::check_server_capabilities(server.capabilities())
5536 })
5537 .filter(|(adapter, _)| {
5538 scope
5539 .as_ref()
5540 .map(|scope| scope.language_allowed(&adapter.name))
5541 .unwrap_or(true)
5542 })
5543 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5544 .next()
5545 })
5546 })
5547 .or_else(|| {
5548 self.upstream_client()
5549 .is_some()
5550 .then_some(LanguageServerToQuery::FirstCapable)
5551 })
5552 .filter(|_| {
5553 maybe!({
5554 let language = buffer.read(cx).language_at(position)?;
5555 Some(
5556 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5557 .linked_edits,
5558 )
5559 }) == Some(true)
5560 })
5561 else {
5562 return Task::ready(Ok(Vec::new()));
5563 };
5564
5565 self.request_lsp(
5566 buffer.clone(),
5567 server_id,
5568 LinkedEditingRange { position },
5569 cx,
5570 )
5571 }
5572
5573 fn apply_on_type_formatting(
5574 &mut self,
5575 buffer: Entity<Buffer>,
5576 position: Anchor,
5577 trigger: String,
5578 cx: &mut Context<Self>,
5579 ) -> Task<Result<Option<Transaction>>> {
5580 if let Some((client, project_id)) = self.upstream_client() {
5581 if !self.check_if_capable_for_proto_request(
5582 &buffer,
5583 |capabilities| {
5584 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5585 },
5586 cx,
5587 ) {
5588 return Task::ready(Ok(None));
5589 }
5590 let request = proto::OnTypeFormatting {
5591 project_id,
5592 buffer_id: buffer.read(cx).remote_id().into(),
5593 position: Some(serialize_anchor(&position)),
5594 trigger,
5595 version: serialize_version(&buffer.read(cx).version()),
5596 };
5597 cx.background_spawn(async move {
5598 client
5599 .request(request)
5600 .await?
5601 .transaction
5602 .map(language::proto::deserialize_transaction)
5603 .transpose()
5604 })
5605 } else if let Some(local) = self.as_local_mut() {
5606 let buffer_id = buffer.read(cx).remote_id();
5607 local.buffers_being_formatted.insert(buffer_id);
5608 cx.spawn(async move |this, cx| {
5609 let _cleanup = defer({
5610 let this = this.clone();
5611 let mut cx = cx.clone();
5612 move || {
5613 this.update(&mut cx, |this, _| {
5614 if let Some(local) = this.as_local_mut() {
5615 local.buffers_being_formatted.remove(&buffer_id);
5616 }
5617 })
5618 .ok();
5619 }
5620 });
5621
5622 buffer
5623 .update(cx, |buffer, _| {
5624 buffer.wait_for_edits(Some(position.timestamp()))
5625 })
5626 .await?;
5627 this.update(cx, |this, cx| {
5628 let position = position.to_point_utf16(buffer.read(cx));
5629 this.on_type_format(buffer, position, trigger, false, cx)
5630 })?
5631 .await
5632 })
5633 } else {
5634 Task::ready(Err(anyhow!("No upstream client or local language server")))
5635 }
5636 }
5637
5638 pub fn on_type_format<T: ToPointUtf16>(
5639 &mut self,
5640 buffer: Entity<Buffer>,
5641 position: T,
5642 trigger: String,
5643 push_to_history: bool,
5644 cx: &mut Context<Self>,
5645 ) -> Task<Result<Option<Transaction>>> {
5646 let position = position.to_point_utf16(buffer.read(cx));
5647 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5648 }
5649
5650 fn on_type_format_impl(
5651 &mut self,
5652 buffer: Entity<Buffer>,
5653 position: PointUtf16,
5654 trigger: String,
5655 push_to_history: bool,
5656 cx: &mut Context<Self>,
5657 ) -> Task<Result<Option<Transaction>>> {
5658 let options = buffer.update(cx, |buffer, cx| {
5659 lsp_command::lsp_formatting_options(
5660 language_settings(
5661 buffer.language_at(position).map(|l| l.name()),
5662 buffer.file(),
5663 cx,
5664 )
5665 .as_ref(),
5666 )
5667 });
5668
5669 cx.spawn(async move |this, cx| {
5670 if let Some(waiter) =
5671 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5672 {
5673 waiter.await?;
5674 }
5675 cx.update(|cx| {
5676 this.update(cx, |this, cx| {
5677 this.request_lsp(
5678 buffer.clone(),
5679 LanguageServerToQuery::FirstCapable,
5680 OnTypeFormatting {
5681 position,
5682 trigger,
5683 options,
5684 push_to_history,
5685 },
5686 cx,
5687 )
5688 })
5689 })?
5690 .await
5691 })
5692 }
5693
5694 pub fn definitions(
5695 &mut self,
5696 buffer: &Entity<Buffer>,
5697 position: PointUtf16,
5698 cx: &mut Context<Self>,
5699 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5700 if let Some((upstream_client, project_id)) = self.upstream_client() {
5701 let request = GetDefinitions { position };
5702 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5703 return Task::ready(Ok(None));
5704 }
5705
5706 let request_timeout = ProjectSettings::get_global(cx)
5707 .global_lsp_settings
5708 .get_request_timeout();
5709
5710 let request_task = upstream_client.request_lsp(
5711 project_id,
5712 None,
5713 request_timeout,
5714 cx.background_executor().clone(),
5715 request.to_proto(project_id, buffer.read(cx)),
5716 );
5717 let buffer = buffer.clone();
5718 cx.spawn(async move |weak_lsp_store, cx| {
5719 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5720 return Ok(None);
5721 };
5722 let Some(responses) = request_task.await? else {
5723 return Ok(None);
5724 };
5725 let actions = join_all(responses.payload.into_iter().map(|response| {
5726 GetDefinitions { position }.response_from_proto(
5727 response.response,
5728 lsp_store.clone(),
5729 buffer.clone(),
5730 cx.clone(),
5731 )
5732 }))
5733 .await;
5734
5735 Ok(Some(
5736 actions
5737 .into_iter()
5738 .collect::<Result<Vec<Vec<_>>>>()?
5739 .into_iter()
5740 .flatten()
5741 .dedup()
5742 .collect(),
5743 ))
5744 })
5745 } else {
5746 let definitions_task = self.request_multiple_lsp_locally(
5747 buffer,
5748 Some(position),
5749 GetDefinitions { position },
5750 cx,
5751 );
5752 cx.background_spawn(async move {
5753 Ok(Some(
5754 definitions_task
5755 .await
5756 .into_iter()
5757 .flat_map(|(_, definitions)| definitions)
5758 .dedup()
5759 .collect(),
5760 ))
5761 })
5762 }
5763 }
5764
5765 pub fn declarations(
5766 &mut self,
5767 buffer: &Entity<Buffer>,
5768 position: PointUtf16,
5769 cx: &mut Context<Self>,
5770 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5771 if let Some((upstream_client, project_id)) = self.upstream_client() {
5772 let request = GetDeclarations { position };
5773 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5774 return Task::ready(Ok(None));
5775 }
5776 let request_timeout = ProjectSettings::get_global(cx)
5777 .global_lsp_settings
5778 .get_request_timeout();
5779 let request_task = upstream_client.request_lsp(
5780 project_id,
5781 None,
5782 request_timeout,
5783 cx.background_executor().clone(),
5784 request.to_proto(project_id, buffer.read(cx)),
5785 );
5786 let buffer = buffer.clone();
5787 cx.spawn(async move |weak_lsp_store, cx| {
5788 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5789 return Ok(None);
5790 };
5791 let Some(responses) = request_task.await? else {
5792 return Ok(None);
5793 };
5794 let actions = join_all(responses.payload.into_iter().map(|response| {
5795 GetDeclarations { position }.response_from_proto(
5796 response.response,
5797 lsp_store.clone(),
5798 buffer.clone(),
5799 cx.clone(),
5800 )
5801 }))
5802 .await;
5803
5804 Ok(Some(
5805 actions
5806 .into_iter()
5807 .collect::<Result<Vec<Vec<_>>>>()?
5808 .into_iter()
5809 .flatten()
5810 .dedup()
5811 .collect(),
5812 ))
5813 })
5814 } else {
5815 let declarations_task = self.request_multiple_lsp_locally(
5816 buffer,
5817 Some(position),
5818 GetDeclarations { position },
5819 cx,
5820 );
5821 cx.background_spawn(async move {
5822 Ok(Some(
5823 declarations_task
5824 .await
5825 .into_iter()
5826 .flat_map(|(_, declarations)| declarations)
5827 .dedup()
5828 .collect(),
5829 ))
5830 })
5831 }
5832 }
5833
5834 pub fn type_definitions(
5835 &mut self,
5836 buffer: &Entity<Buffer>,
5837 position: PointUtf16,
5838 cx: &mut Context<Self>,
5839 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5840 if let Some((upstream_client, project_id)) = self.upstream_client() {
5841 let request = GetTypeDefinitions { position };
5842 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5843 return Task::ready(Ok(None));
5844 }
5845 let request_timeout = ProjectSettings::get_global(cx)
5846 .global_lsp_settings
5847 .get_request_timeout();
5848 let request_task = upstream_client.request_lsp(
5849 project_id,
5850 None,
5851 request_timeout,
5852 cx.background_executor().clone(),
5853 request.to_proto(project_id, buffer.read(cx)),
5854 );
5855 let buffer = buffer.clone();
5856 cx.spawn(async move |weak_lsp_store, cx| {
5857 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5858 return Ok(None);
5859 };
5860 let Some(responses) = request_task.await? else {
5861 return Ok(None);
5862 };
5863 let actions = join_all(responses.payload.into_iter().map(|response| {
5864 GetTypeDefinitions { position }.response_from_proto(
5865 response.response,
5866 lsp_store.clone(),
5867 buffer.clone(),
5868 cx.clone(),
5869 )
5870 }))
5871 .await;
5872
5873 Ok(Some(
5874 actions
5875 .into_iter()
5876 .collect::<Result<Vec<Vec<_>>>>()?
5877 .into_iter()
5878 .flatten()
5879 .dedup()
5880 .collect(),
5881 ))
5882 })
5883 } else {
5884 let type_definitions_task = self.request_multiple_lsp_locally(
5885 buffer,
5886 Some(position),
5887 GetTypeDefinitions { position },
5888 cx,
5889 );
5890 cx.background_spawn(async move {
5891 Ok(Some(
5892 type_definitions_task
5893 .await
5894 .into_iter()
5895 .flat_map(|(_, type_definitions)| type_definitions)
5896 .dedup()
5897 .collect(),
5898 ))
5899 })
5900 }
5901 }
5902
5903 pub fn implementations(
5904 &mut self,
5905 buffer: &Entity<Buffer>,
5906 position: PointUtf16,
5907 cx: &mut Context<Self>,
5908 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5909 if let Some((upstream_client, project_id)) = self.upstream_client() {
5910 let request = GetImplementations { position };
5911 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5912 return Task::ready(Ok(None));
5913 }
5914
5915 let request_timeout = ProjectSettings::get_global(cx)
5916 .global_lsp_settings
5917 .get_request_timeout();
5918 let request_task = upstream_client.request_lsp(
5919 project_id,
5920 None,
5921 request_timeout,
5922 cx.background_executor().clone(),
5923 request.to_proto(project_id, buffer.read(cx)),
5924 );
5925 let buffer = buffer.clone();
5926 cx.spawn(async move |weak_lsp_store, cx| {
5927 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5928 return Ok(None);
5929 };
5930 let Some(responses) = request_task.await? else {
5931 return Ok(None);
5932 };
5933 let actions = join_all(responses.payload.into_iter().map(|response| {
5934 GetImplementations { position }.response_from_proto(
5935 response.response,
5936 lsp_store.clone(),
5937 buffer.clone(),
5938 cx.clone(),
5939 )
5940 }))
5941 .await;
5942
5943 Ok(Some(
5944 actions
5945 .into_iter()
5946 .collect::<Result<Vec<Vec<_>>>>()?
5947 .into_iter()
5948 .flatten()
5949 .dedup()
5950 .collect(),
5951 ))
5952 })
5953 } else {
5954 let implementations_task = self.request_multiple_lsp_locally(
5955 buffer,
5956 Some(position),
5957 GetImplementations { position },
5958 cx,
5959 );
5960 cx.background_spawn(async move {
5961 Ok(Some(
5962 implementations_task
5963 .await
5964 .into_iter()
5965 .flat_map(|(_, implementations)| implementations)
5966 .dedup()
5967 .collect(),
5968 ))
5969 })
5970 }
5971 }
5972
5973 pub fn references(
5974 &mut self,
5975 buffer: &Entity<Buffer>,
5976 position: PointUtf16,
5977 cx: &mut Context<Self>,
5978 ) -> Task<Result<Option<Vec<Location>>>> {
5979 if let Some((upstream_client, project_id)) = self.upstream_client() {
5980 let request = GetReferences { position };
5981 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5982 return Task::ready(Ok(None));
5983 }
5984
5985 let request_timeout = ProjectSettings::get_global(cx)
5986 .global_lsp_settings
5987 .get_request_timeout();
5988 let request_task = upstream_client.request_lsp(
5989 project_id,
5990 None,
5991 request_timeout,
5992 cx.background_executor().clone(),
5993 request.to_proto(project_id, buffer.read(cx)),
5994 );
5995 let buffer = buffer.clone();
5996 cx.spawn(async move |weak_lsp_store, cx| {
5997 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5998 return Ok(None);
5999 };
6000 let Some(responses) = request_task.await? else {
6001 return Ok(None);
6002 };
6003
6004 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6005 GetReferences { position }.response_from_proto(
6006 lsp_response.response,
6007 lsp_store.clone(),
6008 buffer.clone(),
6009 cx.clone(),
6010 )
6011 }))
6012 .await
6013 .into_iter()
6014 .collect::<Result<Vec<Vec<_>>>>()?
6015 .into_iter()
6016 .flatten()
6017 .dedup()
6018 .collect();
6019 Ok(Some(locations))
6020 })
6021 } else {
6022 let references_task = self.request_multiple_lsp_locally(
6023 buffer,
6024 Some(position),
6025 GetReferences { position },
6026 cx,
6027 );
6028 cx.background_spawn(async move {
6029 Ok(Some(
6030 references_task
6031 .await
6032 .into_iter()
6033 .flat_map(|(_, references)| references)
6034 .dedup()
6035 .collect(),
6036 ))
6037 })
6038 }
6039 }
6040
6041 pub fn code_actions(
6042 &mut self,
6043 buffer: &Entity<Buffer>,
6044 range: Range<Anchor>,
6045 kinds: Option<Vec<CodeActionKind>>,
6046 cx: &mut Context<Self>,
6047 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6048 if let Some((upstream_client, project_id)) = self.upstream_client() {
6049 let request = GetCodeActions {
6050 range: range.clone(),
6051 kinds: kinds.clone(),
6052 };
6053 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6054 return Task::ready(Ok(None));
6055 }
6056 let request_timeout = ProjectSettings::get_global(cx)
6057 .global_lsp_settings
6058 .get_request_timeout();
6059 let request_task = upstream_client.request_lsp(
6060 project_id,
6061 None,
6062 request_timeout,
6063 cx.background_executor().clone(),
6064 request.to_proto(project_id, buffer.read(cx)),
6065 );
6066 let buffer = buffer.clone();
6067 cx.spawn(async move |weak_lsp_store, cx| {
6068 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6069 return Ok(None);
6070 };
6071 let Some(responses) = request_task.await? else {
6072 return Ok(None);
6073 };
6074 let actions = join_all(responses.payload.into_iter().map(|response| {
6075 GetCodeActions {
6076 range: range.clone(),
6077 kinds: kinds.clone(),
6078 }
6079 .response_from_proto(
6080 response.response,
6081 lsp_store.clone(),
6082 buffer.clone(),
6083 cx.clone(),
6084 )
6085 }))
6086 .await;
6087
6088 Ok(Some(
6089 actions
6090 .into_iter()
6091 .collect::<Result<Vec<Vec<_>>>>()?
6092 .into_iter()
6093 .flatten()
6094 .collect(),
6095 ))
6096 })
6097 } else {
6098 let all_actions_task = self.request_multiple_lsp_locally(
6099 buffer,
6100 Some(range.start),
6101 GetCodeActions { range, kinds },
6102 cx,
6103 );
6104 cx.background_spawn(async move {
6105 Ok(Some(
6106 all_actions_task
6107 .await
6108 .into_iter()
6109 .flat_map(|(_, actions)| actions)
6110 .collect(),
6111 ))
6112 })
6113 }
6114 }
6115
6116 #[inline(never)]
6117 pub fn completions(
6118 &self,
6119 buffer: &Entity<Buffer>,
6120 position: PointUtf16,
6121 context: CompletionContext,
6122 cx: &mut Context<Self>,
6123 ) -> Task<Result<Vec<CompletionResponse>>> {
6124 let language_registry = self.languages.clone();
6125
6126 if let Some((upstream_client, project_id)) = self.upstream_client() {
6127 let snapshot = buffer.read(cx).snapshot();
6128 let offset = position.to_offset(&snapshot);
6129 let scope = snapshot.language_scope_at(offset);
6130 let capable_lsps = self.all_capable_for_proto_request(
6131 buffer,
6132 |server_name, capabilities| {
6133 capabilities.completion_provider.is_some()
6134 && scope
6135 .as_ref()
6136 .map(|scope| scope.language_allowed(server_name))
6137 .unwrap_or(true)
6138 },
6139 cx,
6140 );
6141 if capable_lsps.is_empty() {
6142 return Task::ready(Ok(Vec::new()));
6143 }
6144
6145 let language = buffer.read(cx).language().cloned();
6146
6147 let buffer = buffer.clone();
6148
6149 cx.spawn(async move |this, cx| {
6150 let requests = join_all(
6151 capable_lsps
6152 .into_iter()
6153 .map(|(id, server_name)| {
6154 let request = GetCompletions {
6155 position,
6156 context: context.clone(),
6157 server_id: Some(id),
6158 };
6159 let buffer = buffer.clone();
6160 let language = language.clone();
6161 let lsp_adapter = language.as_ref().and_then(|language| {
6162 let adapters = language_registry.lsp_adapters(&language.name());
6163 adapters
6164 .iter()
6165 .find(|adapter| adapter.name() == server_name)
6166 .or_else(|| adapters.first())
6167 .cloned()
6168 });
6169 let upstream_client = upstream_client.clone();
6170 let response = this
6171 .update(cx, |this, cx| {
6172 this.send_lsp_proto_request(
6173 buffer,
6174 upstream_client,
6175 project_id,
6176 request,
6177 cx,
6178 )
6179 })
6180 .log_err();
6181 async move {
6182 let response = response?.await.log_err()?;
6183
6184 let completions = populate_labels_for_completions(
6185 response.completions,
6186 language,
6187 lsp_adapter,
6188 )
6189 .await;
6190
6191 Some(CompletionResponse {
6192 completions,
6193 display_options: CompletionDisplayOptions::default(),
6194 is_incomplete: response.is_incomplete,
6195 })
6196 }
6197 })
6198 .collect::<Vec<_>>(),
6199 );
6200 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6201 })
6202 } else if let Some(local) = self.as_local() {
6203 let snapshot = buffer.read(cx).snapshot();
6204 let offset = position.to_offset(&snapshot);
6205 let scope = snapshot.language_scope_at(offset);
6206 let language = snapshot.language().cloned();
6207 let completion_settings = language_settings(
6208 language.as_ref().map(|language| language.name()),
6209 buffer.read(cx).file(),
6210 cx,
6211 )
6212 .completions
6213 .clone();
6214 if !completion_settings.lsp {
6215 return Task::ready(Ok(Vec::new()));
6216 }
6217
6218 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6219 local
6220 .language_servers_for_buffer(buffer, cx)
6221 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6222 .filter(|(adapter, _)| {
6223 scope
6224 .as_ref()
6225 .map(|scope| scope.language_allowed(&adapter.name))
6226 .unwrap_or(true)
6227 })
6228 .map(|(_, server)| server.server_id())
6229 .collect()
6230 });
6231
6232 let buffer = buffer.clone();
6233 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6234 let lsp_timeout = if lsp_timeout > 0 {
6235 Some(Duration::from_millis(lsp_timeout))
6236 } else {
6237 None
6238 };
6239 cx.spawn(async move |this, cx| {
6240 let mut tasks = Vec::with_capacity(server_ids.len());
6241 this.update(cx, |lsp_store, cx| {
6242 for server_id in server_ids {
6243 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6244 let lsp_timeout = lsp_timeout
6245 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6246 let mut timeout = cx.background_spawn(async move {
6247 match lsp_timeout {
6248 Some(lsp_timeout) => {
6249 lsp_timeout.await;
6250 true
6251 },
6252 None => false,
6253 }
6254 }).fuse();
6255 let mut lsp_request = lsp_store.request_lsp(
6256 buffer.clone(),
6257 LanguageServerToQuery::Other(server_id),
6258 GetCompletions {
6259 position,
6260 context: context.clone(),
6261 server_id: Some(server_id),
6262 },
6263 cx,
6264 ).fuse();
6265 let new_task = cx.background_spawn(async move {
6266 select_biased! {
6267 response = lsp_request => anyhow::Ok(Some(response?)),
6268 timeout_happened = timeout => {
6269 if timeout_happened {
6270 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6271 Ok(None)
6272 } else {
6273 let completions = lsp_request.await?;
6274 Ok(Some(completions))
6275 }
6276 },
6277 }
6278 });
6279 tasks.push((lsp_adapter, new_task));
6280 }
6281 })?;
6282
6283 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6284 let completion_response = task.await.ok()??;
6285 let completions = populate_labels_for_completions(
6286 completion_response.completions,
6287 language.clone(),
6288 lsp_adapter,
6289 )
6290 .await;
6291 Some(CompletionResponse {
6292 completions,
6293 display_options: CompletionDisplayOptions::default(),
6294 is_incomplete: completion_response.is_incomplete,
6295 })
6296 });
6297
6298 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6299
6300 Ok(responses.into_iter().flatten().collect())
6301 })
6302 } else {
6303 Task::ready(Err(anyhow!("No upstream client or local language server")))
6304 }
6305 }
6306
6307 pub fn resolve_completions(
6308 &self,
6309 buffer: Entity<Buffer>,
6310 completion_indices: Vec<usize>,
6311 completions: Rc<RefCell<Box<[Completion]>>>,
6312 cx: &mut Context<Self>,
6313 ) -> Task<Result<bool>> {
6314 let client = self.upstream_client();
6315 let buffer_id = buffer.read(cx).remote_id();
6316 let buffer_snapshot = buffer.read(cx).snapshot();
6317
6318 if !self.check_if_capable_for_proto_request(
6319 &buffer,
6320 GetCompletions::can_resolve_completions,
6321 cx,
6322 ) {
6323 return Task::ready(Ok(false));
6324 }
6325 cx.spawn(async move |lsp_store, cx| {
6326 let request_timeout = cx.update(|app| {
6327 ProjectSettings::get_global(app)
6328 .global_lsp_settings
6329 .get_request_timeout()
6330 });
6331
6332 let mut did_resolve = false;
6333 if let Some((client, project_id)) = client {
6334 for completion_index in completion_indices {
6335 let server_id = {
6336 let completion = &completions.borrow()[completion_index];
6337 completion.source.server_id()
6338 };
6339 if let Some(server_id) = server_id {
6340 if Self::resolve_completion_remote(
6341 project_id,
6342 server_id,
6343 buffer_id,
6344 completions.clone(),
6345 completion_index,
6346 client.clone(),
6347 )
6348 .await
6349 .log_err()
6350 .is_some()
6351 {
6352 did_resolve = true;
6353 }
6354 } else {
6355 resolve_word_completion(
6356 &buffer_snapshot,
6357 &mut completions.borrow_mut()[completion_index],
6358 );
6359 }
6360 }
6361 } else {
6362 for completion_index in completion_indices {
6363 let server_id = {
6364 let completion = &completions.borrow()[completion_index];
6365 completion.source.server_id()
6366 };
6367 if let Some(server_id) = server_id {
6368 let server_and_adapter = lsp_store
6369 .read_with(cx, |lsp_store, _| {
6370 let server = lsp_store.language_server_for_id(server_id)?;
6371 let adapter =
6372 lsp_store.language_server_adapter_for_id(server.server_id())?;
6373 Some((server, adapter))
6374 })
6375 .ok()
6376 .flatten();
6377 let Some((server, adapter)) = server_and_adapter else {
6378 continue;
6379 };
6380
6381 let resolved = Self::resolve_completion_local(
6382 server,
6383 completions.clone(),
6384 completion_index,
6385 request_timeout,
6386 )
6387 .await
6388 .log_err()
6389 .is_some();
6390 if resolved {
6391 Self::regenerate_completion_labels(
6392 adapter,
6393 &buffer_snapshot,
6394 completions.clone(),
6395 completion_index,
6396 )
6397 .await
6398 .log_err();
6399 did_resolve = true;
6400 }
6401 } else {
6402 resolve_word_completion(
6403 &buffer_snapshot,
6404 &mut completions.borrow_mut()[completion_index],
6405 );
6406 }
6407 }
6408 }
6409
6410 Ok(did_resolve)
6411 })
6412 }
6413
6414 async fn resolve_completion_local(
6415 server: Arc<lsp::LanguageServer>,
6416 completions: Rc<RefCell<Box<[Completion]>>>,
6417 completion_index: usize,
6418 request_timeout: Duration,
6419 ) -> Result<()> {
6420 let server_id = server.server_id();
6421 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6422 return Ok(());
6423 }
6424
6425 let request = {
6426 let completion = &completions.borrow()[completion_index];
6427 match &completion.source {
6428 CompletionSource::Lsp {
6429 lsp_completion,
6430 resolved,
6431 server_id: completion_server_id,
6432 ..
6433 } => {
6434 if *resolved {
6435 return Ok(());
6436 }
6437 anyhow::ensure!(
6438 server_id == *completion_server_id,
6439 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6440 );
6441 server.request::<lsp::request::ResolveCompletionItem>(
6442 *lsp_completion.clone(),
6443 request_timeout,
6444 )
6445 }
6446 CompletionSource::BufferWord { .. }
6447 | CompletionSource::Dap { .. }
6448 | CompletionSource::Custom => {
6449 return Ok(());
6450 }
6451 }
6452 };
6453 let resolved_completion = request
6454 .await
6455 .into_response()
6456 .context("resolve completion")?;
6457
6458 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6459 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6460
6461 let mut completions = completions.borrow_mut();
6462 let completion = &mut completions[completion_index];
6463 if let CompletionSource::Lsp {
6464 lsp_completion,
6465 resolved,
6466 server_id: completion_server_id,
6467 ..
6468 } = &mut completion.source
6469 {
6470 if *resolved {
6471 return Ok(());
6472 }
6473 anyhow::ensure!(
6474 server_id == *completion_server_id,
6475 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6476 );
6477 **lsp_completion = resolved_completion;
6478 *resolved = true;
6479 }
6480 Ok(())
6481 }
6482
6483 async fn regenerate_completion_labels(
6484 adapter: Arc<CachedLspAdapter>,
6485 snapshot: &BufferSnapshot,
6486 completions: Rc<RefCell<Box<[Completion]>>>,
6487 completion_index: usize,
6488 ) -> Result<()> {
6489 let completion_item = completions.borrow()[completion_index]
6490 .source
6491 .lsp_completion(true)
6492 .map(Cow::into_owned);
6493 if let Some(lsp_documentation) = completion_item
6494 .as_ref()
6495 .and_then(|completion_item| completion_item.documentation.clone())
6496 {
6497 let mut completions = completions.borrow_mut();
6498 let completion = &mut completions[completion_index];
6499 completion.documentation = Some(lsp_documentation.into());
6500 } else {
6501 let mut completions = completions.borrow_mut();
6502 let completion = &mut completions[completion_index];
6503 completion.documentation = Some(CompletionDocumentation::Undocumented);
6504 }
6505
6506 let mut new_label = match completion_item {
6507 Some(completion_item) => {
6508 // Some language servers always return `detail` lazily via resolve, regardless of
6509 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6510 // See: https://github.com/yioneko/vtsls/issues/213
6511 let language = snapshot.language();
6512 match language {
6513 Some(language) => {
6514 adapter
6515 .labels_for_completions(
6516 std::slice::from_ref(&completion_item),
6517 language,
6518 )
6519 .await?
6520 }
6521 None => Vec::new(),
6522 }
6523 .pop()
6524 .flatten()
6525 .unwrap_or_else(|| {
6526 CodeLabel::fallback_for_completion(
6527 &completion_item,
6528 language.map(|language| language.as_ref()),
6529 )
6530 })
6531 }
6532 None => CodeLabel::plain(
6533 completions.borrow()[completion_index].new_text.clone(),
6534 None,
6535 ),
6536 };
6537 ensure_uniform_list_compatible_label(&mut new_label);
6538
6539 let mut completions = completions.borrow_mut();
6540 let completion = &mut completions[completion_index];
6541 if completion.label.filter_text() == new_label.filter_text() {
6542 completion.label = new_label;
6543 } else {
6544 log::error!(
6545 "Resolved completion changed display label from {} to {}. \
6546 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6547 completion.label.text(),
6548 new_label.text(),
6549 completion.label.filter_text(),
6550 new_label.filter_text()
6551 );
6552 }
6553
6554 Ok(())
6555 }
6556
6557 async fn resolve_completion_remote(
6558 project_id: u64,
6559 server_id: LanguageServerId,
6560 buffer_id: BufferId,
6561 completions: Rc<RefCell<Box<[Completion]>>>,
6562 completion_index: usize,
6563 client: AnyProtoClient,
6564 ) -> Result<()> {
6565 let lsp_completion = {
6566 let completion = &completions.borrow()[completion_index];
6567 match &completion.source {
6568 CompletionSource::Lsp {
6569 lsp_completion,
6570 resolved,
6571 server_id: completion_server_id,
6572 ..
6573 } => {
6574 anyhow::ensure!(
6575 server_id == *completion_server_id,
6576 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6577 );
6578 if *resolved {
6579 return Ok(());
6580 }
6581 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6582 }
6583 CompletionSource::Custom
6584 | CompletionSource::Dap { .. }
6585 | CompletionSource::BufferWord { .. } => {
6586 return Ok(());
6587 }
6588 }
6589 };
6590 let request = proto::ResolveCompletionDocumentation {
6591 project_id,
6592 language_server_id: server_id.0 as u64,
6593 lsp_completion,
6594 buffer_id: buffer_id.into(),
6595 };
6596
6597 let response = client
6598 .request(request)
6599 .await
6600 .context("completion documentation resolve proto request")?;
6601 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6602
6603 let documentation = if response.documentation.is_empty() {
6604 CompletionDocumentation::Undocumented
6605 } else if response.documentation_is_markdown {
6606 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6607 } else if response.documentation.lines().count() <= 1 {
6608 CompletionDocumentation::SingleLine(response.documentation.into())
6609 } else {
6610 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6611 };
6612
6613 let mut completions = completions.borrow_mut();
6614 let completion = &mut completions[completion_index];
6615 completion.documentation = Some(documentation);
6616 if let CompletionSource::Lsp {
6617 insert_range,
6618 lsp_completion,
6619 resolved,
6620 server_id: completion_server_id,
6621 lsp_defaults: _,
6622 } = &mut completion.source
6623 {
6624 let completion_insert_range = response
6625 .old_insert_start
6626 .and_then(deserialize_anchor)
6627 .zip(response.old_insert_end.and_then(deserialize_anchor));
6628 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6629
6630 if *resolved {
6631 return Ok(());
6632 }
6633 anyhow::ensure!(
6634 server_id == *completion_server_id,
6635 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6636 );
6637 **lsp_completion = resolved_lsp_completion;
6638 *resolved = true;
6639 }
6640
6641 let replace_range = response
6642 .old_replace_start
6643 .and_then(deserialize_anchor)
6644 .zip(response.old_replace_end.and_then(deserialize_anchor));
6645 if let Some((old_replace_start, old_replace_end)) = replace_range
6646 && !response.new_text.is_empty()
6647 {
6648 completion.new_text = response.new_text;
6649 completion.replace_range = old_replace_start..old_replace_end;
6650 }
6651
6652 Ok(())
6653 }
6654
6655 pub fn apply_additional_edits_for_completion(
6656 &self,
6657 buffer_handle: Entity<Buffer>,
6658 completions: Rc<RefCell<Box<[Completion]>>>,
6659 completion_index: usize,
6660 push_to_history: bool,
6661 all_commit_ranges: Vec<Range<language::Anchor>>,
6662 cx: &mut Context<Self>,
6663 ) -> Task<Result<Option<Transaction>>> {
6664 if let Some((client, project_id)) = self.upstream_client() {
6665 let buffer = buffer_handle.read(cx);
6666 let buffer_id = buffer.remote_id();
6667 cx.spawn(async move |_, cx| {
6668 let request = {
6669 let completion = completions.borrow()[completion_index].clone();
6670 proto::ApplyCompletionAdditionalEdits {
6671 project_id,
6672 buffer_id: buffer_id.into(),
6673 completion: Some(Self::serialize_completion(&CoreCompletion {
6674 replace_range: completion.replace_range,
6675 new_text: completion.new_text,
6676 source: completion.source,
6677 })),
6678 all_commit_ranges: all_commit_ranges
6679 .iter()
6680 .cloned()
6681 .map(language::proto::serialize_anchor_range)
6682 .collect(),
6683 }
6684 };
6685
6686 let Some(transaction) = client.request(request).await?.transaction else {
6687 return Ok(None);
6688 };
6689
6690 let transaction = language::proto::deserialize_transaction(transaction)?;
6691 buffer_handle
6692 .update(cx, |buffer, _| {
6693 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6694 })
6695 .await?;
6696 if push_to_history {
6697 buffer_handle.update(cx, |buffer, _| {
6698 buffer.push_transaction(transaction.clone(), Instant::now());
6699 buffer.finalize_last_transaction();
6700 });
6701 }
6702 Ok(Some(transaction))
6703 })
6704 } else {
6705 let request_timeout = ProjectSettings::get_global(cx)
6706 .global_lsp_settings
6707 .get_request_timeout();
6708
6709 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6710 let completion = &completions.borrow()[completion_index];
6711 let server_id = completion.source.server_id()?;
6712 Some(
6713 self.language_server_for_local_buffer(buffer, server_id, cx)?
6714 .1
6715 .clone(),
6716 )
6717 }) else {
6718 return Task::ready(Ok(None));
6719 };
6720
6721 cx.spawn(async move |this, cx| {
6722 Self::resolve_completion_local(
6723 server.clone(),
6724 completions.clone(),
6725 completion_index,
6726 request_timeout,
6727 )
6728 .await
6729 .context("resolving completion")?;
6730 let completion = completions.borrow()[completion_index].clone();
6731 let additional_text_edits = completion
6732 .source
6733 .lsp_completion(true)
6734 .as_ref()
6735 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6736 if let Some(edits) = additional_text_edits {
6737 let edits = this
6738 .update(cx, |this, cx| {
6739 this.as_local_mut().unwrap().edits_from_lsp(
6740 &buffer_handle,
6741 edits,
6742 server.server_id(),
6743 None,
6744 cx,
6745 )
6746 })?
6747 .await?;
6748
6749 buffer_handle.update(cx, |buffer, cx| {
6750 buffer.finalize_last_transaction();
6751 buffer.start_transaction();
6752
6753 for (range, text) in edits {
6754 let primary = &completion.replace_range;
6755
6756 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6757 // and the primary completion is just an insertion (empty range), then this is likely
6758 // an auto-import scenario and should not be considered overlapping
6759 // https://github.com/zed-industries/zed/issues/26136
6760 let is_file_start_auto_import = {
6761 let snapshot = buffer.snapshot();
6762 let primary_start_point = primary.start.to_point(&snapshot);
6763 let range_start_point = range.start.to_point(&snapshot);
6764
6765 let result = primary_start_point.row == 0
6766 && primary_start_point.column == 0
6767 && range_start_point.row == 0
6768 && range_start_point.column == 0;
6769
6770 result
6771 };
6772
6773 let has_overlap = if is_file_start_auto_import {
6774 false
6775 } else {
6776 all_commit_ranges.iter().any(|commit_range| {
6777 let start_within =
6778 commit_range.start.cmp(&range.start, buffer).is_le()
6779 && commit_range.end.cmp(&range.start, buffer).is_ge();
6780 let end_within =
6781 range.start.cmp(&commit_range.end, buffer).is_le()
6782 && range.end.cmp(&commit_range.end, buffer).is_ge();
6783 start_within || end_within
6784 })
6785 };
6786
6787 //Skip additional edits which overlap with the primary completion edit
6788 //https://github.com/zed-industries/zed/pull/1871
6789 if !has_overlap {
6790 buffer.edit([(range, text)], None, cx);
6791 }
6792 }
6793
6794 let transaction = if buffer.end_transaction(cx).is_some() {
6795 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6796 if !push_to_history {
6797 buffer.forget_transaction(transaction.id);
6798 }
6799 Some(transaction)
6800 } else {
6801 None
6802 };
6803 Ok(transaction)
6804 })
6805 } else {
6806 Ok(None)
6807 }
6808 })
6809 }
6810 }
6811
6812 pub fn pull_diagnostics(
6813 &mut self,
6814 buffer: Entity<Buffer>,
6815 cx: &mut Context<Self>,
6816 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6817 let buffer_id = buffer.read(cx).remote_id();
6818
6819 if let Some((client, upstream_project_id)) = self.upstream_client() {
6820 let mut suitable_capabilities = None;
6821 // Are we capable for proto request?
6822 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6823 &buffer,
6824 |capabilities| {
6825 if let Some(caps) = &capabilities.diagnostic_provider {
6826 suitable_capabilities = Some(caps.clone());
6827 true
6828 } else {
6829 false
6830 }
6831 },
6832 cx,
6833 );
6834 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6835 let Some(dynamic_caps) = suitable_capabilities else {
6836 return Task::ready(Ok(None));
6837 };
6838 assert!(any_server_has_diagnostics_provider);
6839
6840 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6841 let request = GetDocumentDiagnostics {
6842 previous_result_id: None,
6843 identifier,
6844 registration_id: None,
6845 };
6846 let request_timeout = ProjectSettings::get_global(cx)
6847 .global_lsp_settings
6848 .get_request_timeout();
6849 let request_task = client.request_lsp(
6850 upstream_project_id,
6851 None,
6852 request_timeout,
6853 cx.background_executor().clone(),
6854 request.to_proto(upstream_project_id, buffer.read(cx)),
6855 );
6856 cx.background_spawn(async move {
6857 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6858 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6859 // Do not attempt to further process the dummy responses here.
6860 let _response = request_task.await?;
6861 Ok(None)
6862 })
6863 } else {
6864 let servers = buffer.update(cx, |buffer, cx| {
6865 self.running_language_servers_for_local_buffer(buffer, cx)
6866 .map(|(_, server)| server.clone())
6867 .collect::<Vec<_>>()
6868 });
6869
6870 let pull_diagnostics = servers
6871 .into_iter()
6872 .flat_map(|server| {
6873 let result = maybe!({
6874 let local = self.as_local()?;
6875 let server_id = server.server_id();
6876 let providers_with_identifiers = local
6877 .language_server_dynamic_registrations
6878 .get(&server_id)
6879 .into_iter()
6880 .flat_map(|registrations| registrations.diagnostics.clone())
6881 .collect::<Vec<_>>();
6882 Some(
6883 providers_with_identifiers
6884 .into_iter()
6885 .map(|(registration_id, dynamic_caps)| {
6886 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6887 let registration_id = registration_id.map(SharedString::from);
6888 let result_id = self.result_id_for_buffer_pull(
6889 server_id,
6890 buffer_id,
6891 ®istration_id,
6892 cx,
6893 );
6894 self.request_lsp(
6895 buffer.clone(),
6896 LanguageServerToQuery::Other(server_id),
6897 GetDocumentDiagnostics {
6898 previous_result_id: result_id,
6899 registration_id,
6900 identifier,
6901 },
6902 cx,
6903 )
6904 })
6905 .collect::<Vec<_>>(),
6906 )
6907 });
6908
6909 result.unwrap_or_default()
6910 })
6911 .collect::<Vec<_>>();
6912
6913 cx.background_spawn(async move {
6914 let mut responses = Vec::new();
6915 for diagnostics in join_all(pull_diagnostics).await {
6916 responses.extend(diagnostics?);
6917 }
6918 Ok(Some(responses))
6919 })
6920 }
6921 }
6922
6923 pub fn applicable_inlay_chunks(
6924 &mut self,
6925 buffer: &Entity<Buffer>,
6926 ranges: &[Range<text::Anchor>],
6927 cx: &mut Context<Self>,
6928 ) -> Vec<Range<BufferRow>> {
6929 let buffer_snapshot = buffer.read(cx).snapshot();
6930 let ranges = ranges
6931 .iter()
6932 .map(|range| range.to_point(&buffer_snapshot))
6933 .collect::<Vec<_>>();
6934
6935 self.latest_lsp_data(buffer, cx)
6936 .inlay_hints
6937 .applicable_chunks(ranges.as_slice())
6938 .map(|chunk| chunk.row_range())
6939 .collect()
6940 }
6941
6942 pub fn invalidate_inlay_hints<'a>(
6943 &'a mut self,
6944 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6945 ) {
6946 for buffer_id in for_buffers {
6947 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6948 lsp_data.inlay_hints.clear();
6949 }
6950 }
6951 }
6952
6953 pub fn inlay_hints(
6954 &mut self,
6955 invalidate: InvalidationStrategy,
6956 buffer: Entity<Buffer>,
6957 ranges: Vec<Range<text::Anchor>>,
6958 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6959 cx: &mut Context<Self>,
6960 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6961 let next_hint_id = self.next_hint_id.clone();
6962 let lsp_data = self.latest_lsp_data(&buffer, cx);
6963 let query_version = lsp_data.buffer_version.clone();
6964 let mut lsp_refresh_requested = false;
6965 let for_server = if let InvalidationStrategy::RefreshRequested {
6966 server_id,
6967 request_id,
6968 } = invalidate
6969 {
6970 let invalidated = lsp_data
6971 .inlay_hints
6972 .invalidate_for_server_refresh(server_id, request_id);
6973 lsp_refresh_requested = invalidated;
6974 Some(server_id)
6975 } else {
6976 None
6977 };
6978 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6979 let known_chunks = known_chunks
6980 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6981 .map(|(_, known_chunks)| known_chunks)
6982 .unwrap_or_default();
6983
6984 let buffer_snapshot = buffer.read(cx).snapshot();
6985 let ranges = ranges
6986 .iter()
6987 .map(|range| range.to_point(&buffer_snapshot))
6988 .collect::<Vec<_>>();
6989
6990 let mut hint_fetch_tasks = Vec::new();
6991 let mut cached_inlay_hints = None;
6992 let mut ranges_to_query = None;
6993 let applicable_chunks = existing_inlay_hints
6994 .applicable_chunks(ranges.as_slice())
6995 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6996 .collect::<Vec<_>>();
6997 if applicable_chunks.is_empty() {
6998 return HashMap::default();
6999 }
7000
7001 for row_chunk in applicable_chunks {
7002 match (
7003 existing_inlay_hints
7004 .cached_hints(&row_chunk)
7005 .filter(|_| !lsp_refresh_requested)
7006 .cloned(),
7007 existing_inlay_hints
7008 .fetched_hints(&row_chunk)
7009 .as_ref()
7010 .filter(|_| !lsp_refresh_requested)
7011 .cloned(),
7012 ) {
7013 (None, None) => {
7014 let chunk_range = row_chunk.anchor_range();
7015 ranges_to_query
7016 .get_or_insert_with(Vec::new)
7017 .push((row_chunk, chunk_range));
7018 }
7019 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7020 (Some(cached_hints), None) => {
7021 for (server_id, cached_hints) in cached_hints {
7022 if for_server.is_none_or(|for_server| for_server == server_id) {
7023 cached_inlay_hints
7024 .get_or_insert_with(HashMap::default)
7025 .entry(row_chunk.row_range())
7026 .or_insert_with(HashMap::default)
7027 .entry(server_id)
7028 .or_insert_with(Vec::new)
7029 .extend(cached_hints);
7030 }
7031 }
7032 }
7033 (Some(cached_hints), Some(fetched_hints)) => {
7034 hint_fetch_tasks.push((row_chunk, fetched_hints));
7035 for (server_id, cached_hints) in cached_hints {
7036 if for_server.is_none_or(|for_server| for_server == server_id) {
7037 cached_inlay_hints
7038 .get_or_insert_with(HashMap::default)
7039 .entry(row_chunk.row_range())
7040 .or_insert_with(HashMap::default)
7041 .entry(server_id)
7042 .or_insert_with(Vec::new)
7043 .extend(cached_hints);
7044 }
7045 }
7046 }
7047 }
7048 }
7049
7050 if hint_fetch_tasks.is_empty()
7051 && ranges_to_query
7052 .as_ref()
7053 .is_none_or(|ranges| ranges.is_empty())
7054 && let Some(cached_inlay_hints) = cached_inlay_hints
7055 {
7056 cached_inlay_hints
7057 .into_iter()
7058 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7059 .collect()
7060 } else {
7061 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7062 // When a server refresh was requested, other servers' cached hints
7063 // are unaffected by the refresh and must be included in the result.
7064 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7065 // removes all visible hints but only adds back the requesting
7066 // server's new hints, permanently losing other servers' hints.
7067 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7068 lsp_data
7069 .inlay_hints
7070 .cached_hints(&chunk)
7071 .cloned()
7072 .unwrap_or_default()
7073 } else {
7074 HashMap::default()
7075 };
7076
7077 let next_hint_id = next_hint_id.clone();
7078 let buffer = buffer.clone();
7079 let query_version = query_version.clone();
7080 let new_inlay_hints = cx
7081 .spawn(async move |lsp_store, cx| {
7082 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7083 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7084 })?;
7085 new_fetch_task
7086 .await
7087 .and_then(|new_hints_by_server| {
7088 lsp_store.update(cx, |lsp_store, cx| {
7089 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7090 let update_cache = lsp_data.buffer_version == query_version;
7091 if new_hints_by_server.is_empty() {
7092 if update_cache {
7093 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7094 }
7095 other_servers_cached
7096 } else {
7097 let mut result = other_servers_cached;
7098 for (server_id, new_hints) in new_hints_by_server {
7099 let new_hints = new_hints
7100 .into_iter()
7101 .map(|new_hint| {
7102 (
7103 InlayId::Hint(next_hint_id.fetch_add(
7104 1,
7105 atomic::Ordering::AcqRel,
7106 )),
7107 new_hint,
7108 )
7109 })
7110 .collect::<Vec<_>>();
7111 if update_cache {
7112 lsp_data.inlay_hints.insert_new_hints(
7113 chunk,
7114 server_id,
7115 new_hints.clone(),
7116 );
7117 }
7118 result.insert(server_id, new_hints);
7119 }
7120 result
7121 }
7122 })
7123 })
7124 .map_err(Arc::new)
7125 })
7126 .shared();
7127
7128 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7129 *fetch_task = Some(new_inlay_hints.clone());
7130 hint_fetch_tasks.push((chunk, new_inlay_hints));
7131 }
7132
7133 cached_inlay_hints
7134 .unwrap_or_default()
7135 .into_iter()
7136 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7137 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7138 (
7139 chunk.row_range(),
7140 cx.spawn(async move |_, _| {
7141 hints_fetch.await.map_err(|e| {
7142 if e.error_code() != ErrorCode::Internal {
7143 anyhow!(e.error_code())
7144 } else {
7145 anyhow!("{e:#}")
7146 }
7147 })
7148 }),
7149 )
7150 }))
7151 .collect()
7152 }
7153 }
7154
7155 fn fetch_inlay_hints(
7156 &mut self,
7157 for_server: Option<LanguageServerId>,
7158 buffer: &Entity<Buffer>,
7159 range: Range<Anchor>,
7160 cx: &mut Context<Self>,
7161 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7162 let request = InlayHints {
7163 range: range.clone(),
7164 };
7165 if let Some((upstream_client, project_id)) = self.upstream_client() {
7166 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7167 return Task::ready(Ok(HashMap::default()));
7168 }
7169 let request_timeout = ProjectSettings::get_global(cx)
7170 .global_lsp_settings
7171 .get_request_timeout();
7172 let request_task = upstream_client.request_lsp(
7173 project_id,
7174 for_server.map(|id| id.to_proto()),
7175 request_timeout,
7176 cx.background_executor().clone(),
7177 request.to_proto(project_id, buffer.read(cx)),
7178 );
7179 let buffer = buffer.clone();
7180 cx.spawn(async move |weak_lsp_store, cx| {
7181 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7182 return Ok(HashMap::default());
7183 };
7184 let Some(responses) = request_task.await? else {
7185 return Ok(HashMap::default());
7186 };
7187
7188 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7189 let lsp_store = lsp_store.clone();
7190 let buffer = buffer.clone();
7191 let cx = cx.clone();
7192 let request = request.clone();
7193 async move {
7194 (
7195 LanguageServerId::from_proto(response.server_id),
7196 request
7197 .response_from_proto(response.response, lsp_store, buffer, cx)
7198 .await,
7199 )
7200 }
7201 }))
7202 .await;
7203
7204 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7205 let mut has_errors = false;
7206 let inlay_hints = inlay_hints
7207 .into_iter()
7208 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7209 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7210 Err(e) => {
7211 has_errors = true;
7212 log::error!("{e:#}");
7213 None
7214 }
7215 })
7216 .map(|(server_id, mut new_hints)| {
7217 new_hints.retain(|hint| {
7218 hint.position.is_valid(&buffer_snapshot)
7219 && range.start.is_valid(&buffer_snapshot)
7220 && range.end.is_valid(&buffer_snapshot)
7221 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7222 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7223 });
7224 (server_id, new_hints)
7225 })
7226 .collect::<HashMap<_, _>>();
7227 anyhow::ensure!(
7228 !has_errors || !inlay_hints.is_empty(),
7229 "Failed to fetch inlay hints"
7230 );
7231 Ok(inlay_hints)
7232 })
7233 } else {
7234 let inlay_hints_task = match for_server {
7235 Some(server_id) => {
7236 let server_task = self.request_lsp(
7237 buffer.clone(),
7238 LanguageServerToQuery::Other(server_id),
7239 request,
7240 cx,
7241 );
7242 cx.background_spawn(async move {
7243 let mut responses = Vec::new();
7244 match server_task.await {
7245 Ok(response) => responses.push((server_id, response)),
7246 // rust-analyzer likes to error with this when its still loading up
7247 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7248 Err(e) => log::error!(
7249 "Error handling response for inlay hints request: {e:#}"
7250 ),
7251 }
7252 responses
7253 })
7254 }
7255 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7256 };
7257 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7258 cx.background_spawn(async move {
7259 Ok(inlay_hints_task
7260 .await
7261 .into_iter()
7262 .map(|(server_id, mut new_hints)| {
7263 new_hints.retain(|hint| {
7264 hint.position.is_valid(&buffer_snapshot)
7265 && range.start.is_valid(&buffer_snapshot)
7266 && range.end.is_valid(&buffer_snapshot)
7267 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7268 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7269 });
7270 (server_id, new_hints)
7271 })
7272 .collect())
7273 })
7274 }
7275 }
7276
7277 fn diagnostic_registration_exists(
7278 &self,
7279 server_id: LanguageServerId,
7280 registration_id: &Option<SharedString>,
7281 ) -> bool {
7282 let Some(local) = self.as_local() else {
7283 return false;
7284 };
7285 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7286 else {
7287 return false;
7288 };
7289 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7290 registrations.diagnostics.contains_key(®istration_key)
7291 }
7292
7293 pub fn pull_diagnostics_for_buffer(
7294 &mut self,
7295 buffer: Entity<Buffer>,
7296 cx: &mut Context<Self>,
7297 ) -> Task<anyhow::Result<()>> {
7298 let diagnostics = self.pull_diagnostics(buffer, cx);
7299 cx.spawn(async move |lsp_store, cx| {
7300 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7301 return Ok(());
7302 };
7303 lsp_store.update(cx, |lsp_store, cx| {
7304 if lsp_store.as_local().is_none() {
7305 return;
7306 }
7307
7308 let mut unchanged_buffers = HashMap::default();
7309 let server_diagnostics_updates = diagnostics
7310 .into_iter()
7311 .filter_map(|diagnostics_set| match diagnostics_set {
7312 LspPullDiagnostics::Response {
7313 server_id,
7314 uri,
7315 diagnostics,
7316 registration_id,
7317 } => Some((server_id, uri, diagnostics, registration_id)),
7318 LspPullDiagnostics::Default => None,
7319 })
7320 .filter(|(server_id, _, _, registration_id)| {
7321 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7322 })
7323 .fold(
7324 HashMap::default(),
7325 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7326 let (result_id, diagnostics) = match diagnostics {
7327 PulledDiagnostics::Unchanged { result_id } => {
7328 unchanged_buffers
7329 .entry(new_registration_id.clone())
7330 .or_insert_with(HashSet::default)
7331 .insert(uri.clone());
7332 (Some(result_id), Vec::new())
7333 }
7334 PulledDiagnostics::Changed {
7335 result_id,
7336 diagnostics,
7337 } => (result_id, diagnostics),
7338 };
7339 let disk_based_sources = Cow::Owned(
7340 lsp_store
7341 .language_server_adapter_for_id(server_id)
7342 .as_ref()
7343 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7344 .unwrap_or(&[])
7345 .to_vec(),
7346 );
7347 acc.entry(server_id)
7348 .or_insert_with(HashMap::default)
7349 .entry(new_registration_id.clone())
7350 .or_insert_with(Vec::new)
7351 .push(DocumentDiagnosticsUpdate {
7352 server_id,
7353 diagnostics: lsp::PublishDiagnosticsParams {
7354 uri,
7355 diagnostics,
7356 version: None,
7357 },
7358 result_id: result_id.map(SharedString::new),
7359 disk_based_sources,
7360 registration_id: new_registration_id,
7361 });
7362 acc
7363 },
7364 );
7365
7366 for diagnostic_updates in server_diagnostics_updates.into_values() {
7367 for (registration_id, diagnostic_updates) in diagnostic_updates {
7368 lsp_store
7369 .merge_lsp_diagnostics(
7370 DiagnosticSourceKind::Pulled,
7371 diagnostic_updates,
7372 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7373 DiagnosticSourceKind::Pulled => {
7374 old_diagnostic.registration_id != registration_id
7375 || unchanged_buffers
7376 .get(&old_diagnostic.registration_id)
7377 .is_some_and(|unchanged_buffers| {
7378 unchanged_buffers.contains(&document_uri)
7379 })
7380 }
7381 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7382 true
7383 }
7384 },
7385 cx,
7386 )
7387 .log_err();
7388 }
7389 }
7390 })
7391 })
7392 }
7393
7394 pub fn signature_help<T: ToPointUtf16>(
7395 &mut self,
7396 buffer: &Entity<Buffer>,
7397 position: T,
7398 cx: &mut Context<Self>,
7399 ) -> Task<Option<Vec<SignatureHelp>>> {
7400 let position = position.to_point_utf16(buffer.read(cx));
7401
7402 if let Some((client, upstream_project_id)) = self.upstream_client() {
7403 let request = GetSignatureHelp { position };
7404 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7405 return Task::ready(None);
7406 }
7407 let request_timeout = ProjectSettings::get_global(cx)
7408 .global_lsp_settings
7409 .get_request_timeout();
7410 let request_task = client.request_lsp(
7411 upstream_project_id,
7412 None,
7413 request_timeout,
7414 cx.background_executor().clone(),
7415 request.to_proto(upstream_project_id, buffer.read(cx)),
7416 );
7417 let buffer = buffer.clone();
7418 cx.spawn(async move |weak_lsp_store, cx| {
7419 let lsp_store = weak_lsp_store.upgrade()?;
7420 let signatures = join_all(
7421 request_task
7422 .await
7423 .log_err()
7424 .flatten()
7425 .map(|response| response.payload)
7426 .unwrap_or_default()
7427 .into_iter()
7428 .map(|response| {
7429 let response = GetSignatureHelp { position }.response_from_proto(
7430 response.response,
7431 lsp_store.clone(),
7432 buffer.clone(),
7433 cx.clone(),
7434 );
7435 async move { response.await.log_err().flatten() }
7436 }),
7437 )
7438 .await
7439 .into_iter()
7440 .flatten()
7441 .collect();
7442 Some(signatures)
7443 })
7444 } else {
7445 let all_actions_task = self.request_multiple_lsp_locally(
7446 buffer,
7447 Some(position),
7448 GetSignatureHelp { position },
7449 cx,
7450 );
7451 cx.background_spawn(async move {
7452 Some(
7453 all_actions_task
7454 .await
7455 .into_iter()
7456 .flat_map(|(_, actions)| actions)
7457 .collect::<Vec<_>>(),
7458 )
7459 })
7460 }
7461 }
7462
7463 pub fn hover(
7464 &mut self,
7465 buffer: &Entity<Buffer>,
7466 position: PointUtf16,
7467 cx: &mut Context<Self>,
7468 ) -> Task<Option<Vec<Hover>>> {
7469 if let Some((client, upstream_project_id)) = self.upstream_client() {
7470 let request = GetHover { position };
7471 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7472 return Task::ready(None);
7473 }
7474 let request_timeout = ProjectSettings::get_global(cx)
7475 .global_lsp_settings
7476 .get_request_timeout();
7477 let request_task = client.request_lsp(
7478 upstream_project_id,
7479 None,
7480 request_timeout,
7481 cx.background_executor().clone(),
7482 request.to_proto(upstream_project_id, buffer.read(cx)),
7483 );
7484 let buffer = buffer.clone();
7485 cx.spawn(async move |weak_lsp_store, cx| {
7486 let lsp_store = weak_lsp_store.upgrade()?;
7487 let hovers = join_all(
7488 request_task
7489 .await
7490 .log_err()
7491 .flatten()
7492 .map(|response| response.payload)
7493 .unwrap_or_default()
7494 .into_iter()
7495 .map(|response| {
7496 let response = GetHover { position }.response_from_proto(
7497 response.response,
7498 lsp_store.clone(),
7499 buffer.clone(),
7500 cx.clone(),
7501 );
7502 async move {
7503 response
7504 .await
7505 .log_err()
7506 .flatten()
7507 .and_then(remove_empty_hover_blocks)
7508 }
7509 }),
7510 )
7511 .await
7512 .into_iter()
7513 .flatten()
7514 .collect();
7515 Some(hovers)
7516 })
7517 } else {
7518 let all_actions_task = self.request_multiple_lsp_locally(
7519 buffer,
7520 Some(position),
7521 GetHover { position },
7522 cx,
7523 );
7524 cx.background_spawn(async move {
7525 Some(
7526 all_actions_task
7527 .await
7528 .into_iter()
7529 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7530 .collect::<Vec<Hover>>(),
7531 )
7532 })
7533 }
7534 }
7535
7536 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7537 let language_registry = self.languages.clone();
7538
7539 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7540 let request = upstream_client.request(proto::GetProjectSymbols {
7541 project_id: *project_id,
7542 query: query.to_string(),
7543 });
7544 cx.foreground_executor().spawn(async move {
7545 let response = request.await?;
7546 let mut symbols = Vec::new();
7547 let core_symbols = response
7548 .symbols
7549 .into_iter()
7550 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7551 .collect::<Vec<_>>();
7552 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7553 .await;
7554 Ok(symbols)
7555 })
7556 } else if let Some(local) = self.as_local() {
7557 struct WorkspaceSymbolsResult {
7558 server_id: LanguageServerId,
7559 lsp_adapter: Arc<CachedLspAdapter>,
7560 worktree: WeakEntity<Worktree>,
7561 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7562 }
7563
7564 let mut requests = Vec::new();
7565 let mut requested_servers = BTreeSet::new();
7566 let request_timeout = ProjectSettings::get_global(cx)
7567 .global_lsp_settings
7568 .get_request_timeout();
7569
7570 for (seed, state) in local.language_server_ids.iter() {
7571 let Some(worktree_handle) = self
7572 .worktree_store
7573 .read(cx)
7574 .worktree_for_id(seed.worktree_id, cx)
7575 else {
7576 continue;
7577 };
7578
7579 let worktree = worktree_handle.read(cx);
7580 if !worktree.is_visible() {
7581 continue;
7582 }
7583
7584 if !requested_servers.insert(state.id) {
7585 continue;
7586 }
7587
7588 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7589 Some(LanguageServerState::Running {
7590 adapter, server, ..
7591 }) => (adapter.clone(), server),
7592
7593 _ => continue,
7594 };
7595
7596 let supports_workspace_symbol_request =
7597 match server.capabilities().workspace_symbol_provider {
7598 Some(OneOf::Left(supported)) => supported,
7599 Some(OneOf::Right(_)) => true,
7600 None => false,
7601 };
7602
7603 if !supports_workspace_symbol_request {
7604 continue;
7605 }
7606
7607 let worktree_handle = worktree_handle.clone();
7608 let server_id = server.server_id();
7609 requests.push(
7610 server
7611 .request::<lsp::request::WorkspaceSymbolRequest>(
7612 lsp::WorkspaceSymbolParams {
7613 query: query.to_string(),
7614 ..Default::default()
7615 },
7616 request_timeout,
7617 )
7618 .map(move |response| {
7619 let lsp_symbols = response
7620 .into_response()
7621 .context("workspace symbols request")
7622 .log_err()
7623 .flatten()
7624 .map(|symbol_response| match symbol_response {
7625 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7626 flat_responses
7627 .into_iter()
7628 .map(|lsp_symbol| {
7629 (
7630 lsp_symbol.name,
7631 lsp_symbol.kind,
7632 lsp_symbol.location,
7633 lsp_symbol.container_name,
7634 )
7635 })
7636 .collect::<Vec<_>>()
7637 }
7638 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7639 nested_responses
7640 .into_iter()
7641 .filter_map(|lsp_symbol| {
7642 let location = match lsp_symbol.location {
7643 OneOf::Left(location) => location,
7644 OneOf::Right(_) => {
7645 log::error!(
7646 "Unexpected: client capabilities \
7647 forbid symbol resolutions in \
7648 workspace.symbol.resolveSupport"
7649 );
7650 return None;
7651 }
7652 };
7653 Some((
7654 lsp_symbol.name,
7655 lsp_symbol.kind,
7656 location,
7657 lsp_symbol.container_name,
7658 ))
7659 })
7660 .collect::<Vec<_>>()
7661 }
7662 })
7663 .unwrap_or_default();
7664
7665 WorkspaceSymbolsResult {
7666 server_id,
7667 lsp_adapter,
7668 worktree: worktree_handle.downgrade(),
7669 lsp_symbols,
7670 }
7671 }),
7672 );
7673 }
7674
7675 cx.spawn(async move |this, cx| {
7676 let responses = futures::future::join_all(requests).await;
7677 let this = match this.upgrade() {
7678 Some(this) => this,
7679 None => return Ok(Vec::new()),
7680 };
7681
7682 let mut symbols = Vec::new();
7683 for result in responses {
7684 let core_symbols = this.update(cx, |this, cx| {
7685 result
7686 .lsp_symbols
7687 .into_iter()
7688 .filter_map(
7689 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7690 let abs_path = symbol_location.uri.to_file_path().ok()?;
7691 let source_worktree = result.worktree.upgrade()?;
7692 let source_worktree_id = source_worktree.read(cx).id();
7693
7694 let path = if let Some((tree, rel_path)) =
7695 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7696 {
7697 let worktree_id = tree.read(cx).id();
7698 SymbolLocation::InProject(ProjectPath {
7699 worktree_id,
7700 path: rel_path,
7701 })
7702 } else {
7703 SymbolLocation::OutsideProject {
7704 signature: this.symbol_signature(&abs_path),
7705 abs_path: abs_path.into(),
7706 }
7707 };
7708
7709 Some(CoreSymbol {
7710 source_language_server_id: result.server_id,
7711 language_server_name: result.lsp_adapter.name.clone(),
7712 source_worktree_id,
7713 path,
7714 kind: symbol_kind,
7715 name: collapse_newlines(&symbol_name, "↵ "),
7716 range: range_from_lsp(symbol_location.range),
7717 container_name: container_name
7718 .map(|c| collapse_newlines(&c, "↵ ")),
7719 })
7720 },
7721 )
7722 .collect::<Vec<_>>()
7723 });
7724
7725 populate_labels_for_symbols(
7726 core_symbols,
7727 &language_registry,
7728 Some(result.lsp_adapter),
7729 &mut symbols,
7730 )
7731 .await;
7732 }
7733
7734 Ok(symbols)
7735 })
7736 } else {
7737 Task::ready(Err(anyhow!("No upstream client or local language server")))
7738 }
7739 }
7740
7741 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7742 let mut summary = DiagnosticSummary::default();
7743 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7744 summary.error_count += path_summary.error_count;
7745 summary.warning_count += path_summary.warning_count;
7746 }
7747 summary
7748 }
7749
7750 /// Returns the diagnostic summary for a specific project path.
7751 pub fn diagnostic_summary_for_path(
7752 &self,
7753 project_path: &ProjectPath,
7754 _: &App,
7755 ) -> DiagnosticSummary {
7756 if let Some(summaries) = self
7757 .diagnostic_summaries
7758 .get(&project_path.worktree_id)
7759 .and_then(|map| map.get(&project_path.path))
7760 {
7761 let (error_count, warning_count) = summaries.iter().fold(
7762 (0, 0),
7763 |(error_count, warning_count), (_language_server_id, summary)| {
7764 (
7765 error_count + summary.error_count,
7766 warning_count + summary.warning_count,
7767 )
7768 },
7769 );
7770
7771 DiagnosticSummary {
7772 error_count,
7773 warning_count,
7774 }
7775 } else {
7776 DiagnosticSummary::default()
7777 }
7778 }
7779
7780 pub fn diagnostic_summaries<'a>(
7781 &'a self,
7782 include_ignored: bool,
7783 cx: &'a App,
7784 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7785 self.worktree_store
7786 .read(cx)
7787 .visible_worktrees(cx)
7788 .filter_map(|worktree| {
7789 let worktree = worktree.read(cx);
7790 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7791 })
7792 .flat_map(move |(worktree, summaries)| {
7793 let worktree_id = worktree.id();
7794 summaries
7795 .iter()
7796 .filter(move |(path, _)| {
7797 include_ignored
7798 || worktree
7799 .entry_for_path(path.as_ref())
7800 .is_some_and(|entry| !entry.is_ignored)
7801 })
7802 .flat_map(move |(path, summaries)| {
7803 summaries.iter().map(move |(server_id, summary)| {
7804 (
7805 ProjectPath {
7806 worktree_id,
7807 path: path.clone(),
7808 },
7809 *server_id,
7810 *summary,
7811 )
7812 })
7813 })
7814 })
7815 }
7816
7817 pub fn on_buffer_edited(
7818 &mut self,
7819 buffer: Entity<Buffer>,
7820 cx: &mut Context<Self>,
7821 ) -> Option<()> {
7822 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7823 Some(
7824 self.as_local()?
7825 .language_servers_for_buffer(buffer, cx)
7826 .map(|i| i.1.clone())
7827 .collect(),
7828 )
7829 })?;
7830
7831 let buffer = buffer.read(cx);
7832 let file = File::from_dyn(buffer.file())?;
7833 let abs_path = file.as_local()?.abs_path(cx);
7834 let uri = lsp::Uri::from_file_path(&abs_path)
7835 .ok()
7836 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7837 .log_err()?;
7838 let next_snapshot = buffer.text_snapshot();
7839 for language_server in language_servers {
7840 let language_server = language_server.clone();
7841
7842 let buffer_snapshots = self
7843 .as_local_mut()?
7844 .buffer_snapshots
7845 .get_mut(&buffer.remote_id())
7846 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7847 let previous_snapshot = buffer_snapshots.last()?;
7848
7849 let build_incremental_change = || {
7850 buffer
7851 .edits_since::<Dimensions<PointUtf16, usize>>(
7852 previous_snapshot.snapshot.version(),
7853 )
7854 .map(|edit| {
7855 let edit_start = edit.new.start.0;
7856 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7857 let new_text = next_snapshot
7858 .text_for_range(edit.new.start.1..edit.new.end.1)
7859 .collect();
7860 lsp::TextDocumentContentChangeEvent {
7861 range: Some(lsp::Range::new(
7862 point_to_lsp(edit_start),
7863 point_to_lsp(edit_end),
7864 )),
7865 range_length: None,
7866 text: new_text,
7867 }
7868 })
7869 .collect()
7870 };
7871
7872 let document_sync_kind = language_server
7873 .capabilities()
7874 .text_document_sync
7875 .as_ref()
7876 .and_then(|sync| match sync {
7877 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7878 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7879 });
7880
7881 let content_changes: Vec<_> = match document_sync_kind {
7882 Some(lsp::TextDocumentSyncKind::FULL) => {
7883 vec![lsp::TextDocumentContentChangeEvent {
7884 range: None,
7885 range_length: None,
7886 text: next_snapshot.text(),
7887 }]
7888 }
7889 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7890 _ => {
7891 #[cfg(any(test, feature = "test-support"))]
7892 {
7893 build_incremental_change()
7894 }
7895
7896 #[cfg(not(any(test, feature = "test-support")))]
7897 {
7898 continue;
7899 }
7900 }
7901 };
7902
7903 let next_version = previous_snapshot.version + 1;
7904 buffer_snapshots.push(LspBufferSnapshot {
7905 version: next_version,
7906 snapshot: next_snapshot.clone(),
7907 });
7908
7909 language_server
7910 .notify::<lsp::notification::DidChangeTextDocument>(
7911 lsp::DidChangeTextDocumentParams {
7912 text_document: lsp::VersionedTextDocumentIdentifier::new(
7913 uri.clone(),
7914 next_version,
7915 ),
7916 content_changes,
7917 },
7918 )
7919 .ok();
7920 self.pull_workspace_diagnostics(language_server.server_id());
7921 }
7922
7923 None
7924 }
7925
7926 pub fn on_buffer_saved(
7927 &mut self,
7928 buffer: Entity<Buffer>,
7929 cx: &mut Context<Self>,
7930 ) -> Option<()> {
7931 let file = File::from_dyn(buffer.read(cx).file())?;
7932 let worktree_id = file.worktree_id(cx);
7933 let abs_path = file.as_local()?.abs_path(cx);
7934 let text_document = lsp::TextDocumentIdentifier {
7935 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7936 };
7937 let local = self.as_local()?;
7938
7939 for server in local.language_servers_for_worktree(worktree_id) {
7940 if let Some(include_text) = include_text(server.as_ref()) {
7941 let text = if include_text {
7942 Some(buffer.read(cx).text())
7943 } else {
7944 None
7945 };
7946 server
7947 .notify::<lsp::notification::DidSaveTextDocument>(
7948 lsp::DidSaveTextDocumentParams {
7949 text_document: text_document.clone(),
7950 text,
7951 },
7952 )
7953 .ok();
7954 }
7955 }
7956
7957 let language_servers = buffer.update(cx, |buffer, cx| {
7958 local.language_server_ids_for_buffer(buffer, cx)
7959 });
7960 for language_server_id in language_servers {
7961 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7962 }
7963
7964 None
7965 }
7966
7967 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
7968 let buffer_id = buffer.read(cx).remote_id();
7969 let task = self.pull_diagnostics_for_buffer(buffer, cx);
7970 self.buffer_reload_tasks.insert(buffer_id, task);
7971 }
7972
7973 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7974 maybe!(async move {
7975 let mut refreshed_servers = HashSet::default();
7976 let servers = lsp_store
7977 .update(cx, |lsp_store, cx| {
7978 let local = lsp_store.as_local()?;
7979
7980 let servers = local
7981 .language_server_ids
7982 .iter()
7983 .filter_map(|(seed, state)| {
7984 let worktree = lsp_store
7985 .worktree_store
7986 .read(cx)
7987 .worktree_for_id(seed.worktree_id, cx);
7988 let delegate: Arc<dyn LspAdapterDelegate> =
7989 worktree.map(|worktree| {
7990 LocalLspAdapterDelegate::new(
7991 local.languages.clone(),
7992 &local.environment,
7993 cx.weak_entity(),
7994 &worktree,
7995 local.http_client.clone(),
7996 local.fs.clone(),
7997 cx,
7998 )
7999 })?;
8000 let server_id = state.id;
8001
8002 let states = local.language_servers.get(&server_id)?;
8003
8004 match states {
8005 LanguageServerState::Starting { .. } => None,
8006 LanguageServerState::Running {
8007 adapter, server, ..
8008 } => {
8009 let adapter = adapter.clone();
8010 let server = server.clone();
8011 refreshed_servers.insert(server.name());
8012 let toolchain = seed.toolchain.clone();
8013 Some(cx.spawn(async move |_, cx| {
8014 let settings =
8015 LocalLspStore::workspace_configuration_for_adapter(
8016 adapter.adapter.clone(),
8017 &delegate,
8018 toolchain,
8019 None,
8020 cx,
8021 )
8022 .await
8023 .ok()?;
8024 server
8025 .notify::<lsp::notification::DidChangeConfiguration>(
8026 lsp::DidChangeConfigurationParams { settings },
8027 )
8028 .ok()?;
8029 Some(())
8030 }))
8031 }
8032 }
8033 })
8034 .collect::<Vec<_>>();
8035
8036 Some(servers)
8037 })
8038 .ok()
8039 .flatten()?;
8040
8041 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8042 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8043 // to stop and unregister its language server wrapper.
8044 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8045 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8046 let _: Vec<Option<()>> = join_all(servers).await;
8047
8048 Some(())
8049 })
8050 .await;
8051 }
8052
8053 fn maintain_workspace_config(
8054 external_refresh_requests: watch::Receiver<()>,
8055 cx: &mut Context<Self>,
8056 ) -> Task<Result<()>> {
8057 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8058 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8059
8060 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8061 *settings_changed_tx.borrow_mut() = ();
8062 });
8063
8064 let mut joint_future =
8065 futures::stream::select(settings_changed_rx, external_refresh_requests);
8066 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8067 // - 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).
8068 // - 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.
8069 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8070 // - 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,
8071 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8072 cx.spawn(async move |this, cx| {
8073 while let Some(()) = joint_future.next().await {
8074 this.update(cx, |this, cx| {
8075 this.refresh_server_tree(cx);
8076 })
8077 .ok();
8078
8079 Self::refresh_workspace_configurations(&this, cx).await;
8080 }
8081
8082 drop(settings_observation);
8083 anyhow::Ok(())
8084 })
8085 }
8086
8087 pub fn running_language_servers_for_local_buffer<'a>(
8088 &'a self,
8089 buffer: &Buffer,
8090 cx: &mut App,
8091 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8092 let local = self.as_local();
8093 let language_server_ids = local
8094 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8095 .unwrap_or_default();
8096
8097 language_server_ids
8098 .into_iter()
8099 .filter_map(
8100 move |server_id| match local?.language_servers.get(&server_id)? {
8101 LanguageServerState::Running {
8102 adapter, server, ..
8103 } => Some((adapter, server)),
8104 _ => None,
8105 },
8106 )
8107 }
8108
8109 pub fn language_servers_for_local_buffer(
8110 &self,
8111 buffer: &Buffer,
8112 cx: &mut App,
8113 ) -> Vec<LanguageServerId> {
8114 let local = self.as_local();
8115 local
8116 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8117 .unwrap_or_default()
8118 }
8119
8120 pub fn language_server_for_local_buffer<'a>(
8121 &'a self,
8122 buffer: &'a Buffer,
8123 server_id: LanguageServerId,
8124 cx: &'a mut App,
8125 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8126 self.as_local()?
8127 .language_servers_for_buffer(buffer, cx)
8128 .find(|(_, s)| s.server_id() == server_id)
8129 }
8130
8131 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8132 self.diagnostic_summaries.remove(&id_to_remove);
8133 if let Some(local) = self.as_local_mut() {
8134 let to_remove = local.remove_worktree(id_to_remove, cx);
8135 for server in to_remove {
8136 self.language_server_statuses.remove(&server);
8137 }
8138 }
8139 }
8140
8141 fn invalidate_diagnostic_summaries_for_removed_entries(
8142 &mut self,
8143 worktree_id: WorktreeId,
8144 changes: &UpdatedEntriesSet,
8145 cx: &mut Context<Self>,
8146 ) {
8147 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8148 return;
8149 };
8150
8151 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8152 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8153 let downstream = self.downstream_client.clone();
8154
8155 for (path, _, _) in changes
8156 .iter()
8157 .filter(|(_, _, change)| *change == PathChange::Removed)
8158 {
8159 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8160 for (server_id, _) in &summaries_by_server_id {
8161 cleared_server_ids.insert(*server_id);
8162 if let Some((client, project_id)) = &downstream {
8163 client
8164 .send(proto::UpdateDiagnosticSummary {
8165 project_id: *project_id,
8166 worktree_id: worktree_id.to_proto(),
8167 summary: Some(proto::DiagnosticSummary {
8168 path: path.as_ref().to_proto(),
8169 language_server_id: server_id.0 as u64,
8170 error_count: 0,
8171 warning_count: 0,
8172 }),
8173 more_summaries: Vec::new(),
8174 })
8175 .ok();
8176 }
8177 }
8178 cleared_paths.push(ProjectPath {
8179 worktree_id,
8180 path: path.clone(),
8181 });
8182 }
8183 }
8184
8185 if !cleared_paths.is_empty() {
8186 for server_id in cleared_server_ids {
8187 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8188 server_id,
8189 paths: cleared_paths.clone(),
8190 });
8191 }
8192 }
8193 }
8194
8195 pub fn shared(
8196 &mut self,
8197 project_id: u64,
8198 downstream_client: AnyProtoClient,
8199 _: &mut Context<Self>,
8200 ) {
8201 self.downstream_client = Some((downstream_client.clone(), project_id));
8202
8203 for (server_id, status) in &self.language_server_statuses {
8204 if let Some(server) = self.language_server_for_id(*server_id) {
8205 downstream_client
8206 .send(proto::StartLanguageServer {
8207 project_id,
8208 server: Some(proto::LanguageServer {
8209 id: server_id.to_proto(),
8210 name: status.name.to_string(),
8211 worktree_id: status.worktree.map(|id| id.to_proto()),
8212 }),
8213 capabilities: serde_json::to_string(&server.capabilities())
8214 .expect("serializing server LSP capabilities"),
8215 })
8216 .log_err();
8217 }
8218 }
8219 }
8220
8221 pub fn disconnected_from_host(&mut self) {
8222 self.downstream_client.take();
8223 }
8224
8225 pub fn disconnected_from_ssh_remote(&mut self) {
8226 if let LspStoreMode::Remote(RemoteLspStore {
8227 upstream_client, ..
8228 }) = &mut self.mode
8229 {
8230 upstream_client.take();
8231 }
8232 }
8233
8234 pub(crate) fn set_language_server_statuses_from_proto(
8235 &mut self,
8236 project: WeakEntity<Project>,
8237 language_servers: Vec<proto::LanguageServer>,
8238 server_capabilities: Vec<String>,
8239 cx: &mut Context<Self>,
8240 ) {
8241 let lsp_logs = cx
8242 .try_global::<GlobalLogStore>()
8243 .map(|lsp_store| lsp_store.0.clone());
8244
8245 self.language_server_statuses = language_servers
8246 .into_iter()
8247 .zip(server_capabilities)
8248 .map(|(server, server_capabilities)| {
8249 let server_id = LanguageServerId(server.id as usize);
8250 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8251 self.lsp_server_capabilities
8252 .insert(server_id, server_capabilities);
8253 }
8254
8255 let name = LanguageServerName::from_proto(server.name);
8256 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8257
8258 if let Some(lsp_logs) = &lsp_logs {
8259 lsp_logs.update(cx, |lsp_logs, cx| {
8260 lsp_logs.add_language_server(
8261 // Only remote clients get their language servers set from proto
8262 LanguageServerKind::Remote {
8263 project: project.clone(),
8264 },
8265 server_id,
8266 Some(name.clone()),
8267 worktree,
8268 None,
8269 cx,
8270 );
8271 });
8272 }
8273
8274 (
8275 server_id,
8276 LanguageServerStatus {
8277 name,
8278 server_version: None,
8279 server_readable_version: None,
8280 pending_work: Default::default(),
8281 has_pending_diagnostic_updates: false,
8282 progress_tokens: Default::default(),
8283 worktree,
8284 binary: None,
8285 configuration: None,
8286 workspace_folders: BTreeSet::new(),
8287 process_id: None,
8288 },
8289 )
8290 })
8291 .collect();
8292 }
8293
8294 #[cfg(feature = "test-support")]
8295 pub fn update_diagnostic_entries(
8296 &mut self,
8297 server_id: LanguageServerId,
8298 abs_path: PathBuf,
8299 result_id: Option<SharedString>,
8300 version: Option<i32>,
8301 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8302 cx: &mut Context<Self>,
8303 ) -> anyhow::Result<()> {
8304 self.merge_diagnostic_entries(
8305 vec![DocumentDiagnosticsUpdate {
8306 diagnostics: DocumentDiagnostics {
8307 diagnostics,
8308 document_abs_path: abs_path,
8309 version,
8310 },
8311 result_id,
8312 server_id,
8313 disk_based_sources: Cow::Borrowed(&[]),
8314 registration_id: None,
8315 }],
8316 |_, _, _| false,
8317 cx,
8318 )?;
8319 Ok(())
8320 }
8321
8322 pub fn merge_diagnostic_entries<'a>(
8323 &mut self,
8324 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8325 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8326 cx: &mut Context<Self>,
8327 ) -> anyhow::Result<()> {
8328 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8329 let mut updated_diagnostics_paths = HashMap::default();
8330 for mut update in diagnostic_updates {
8331 let abs_path = &update.diagnostics.document_abs_path;
8332 let server_id = update.server_id;
8333 let Some((worktree, relative_path)) =
8334 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8335 else {
8336 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8337 return Ok(());
8338 };
8339
8340 let worktree_id = worktree.read(cx).id();
8341 let project_path = ProjectPath {
8342 worktree_id,
8343 path: relative_path,
8344 };
8345
8346 let document_uri = lsp::Uri::from_file_path(abs_path)
8347 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8348 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8349 let snapshot = buffer_handle.read(cx).snapshot();
8350 let buffer = buffer_handle.read(cx);
8351 let reused_diagnostics = buffer
8352 .buffer_diagnostics(Some(server_id))
8353 .iter()
8354 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8355 .map(|v| {
8356 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8357 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8358 DiagnosticEntry {
8359 range: start..end,
8360 diagnostic: v.diagnostic.clone(),
8361 }
8362 })
8363 .collect::<Vec<_>>();
8364
8365 self.as_local_mut()
8366 .context("cannot merge diagnostics on a remote LspStore")?
8367 .update_buffer_diagnostics(
8368 &buffer_handle,
8369 server_id,
8370 Some(update.registration_id),
8371 update.result_id,
8372 update.diagnostics.version,
8373 update.diagnostics.diagnostics.clone(),
8374 reused_diagnostics.clone(),
8375 cx,
8376 )?;
8377
8378 update.diagnostics.diagnostics.extend(reused_diagnostics);
8379 } else if let Some(local) = self.as_local() {
8380 let reused_diagnostics = local
8381 .diagnostics
8382 .get(&worktree_id)
8383 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8384 .and_then(|diagnostics_by_server_id| {
8385 diagnostics_by_server_id
8386 .binary_search_by_key(&server_id, |e| e.0)
8387 .ok()
8388 .map(|ix| &diagnostics_by_server_id[ix].1)
8389 })
8390 .into_iter()
8391 .flatten()
8392 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8393
8394 update
8395 .diagnostics
8396 .diagnostics
8397 .extend(reused_diagnostics.cloned());
8398 }
8399
8400 let updated = worktree.update(cx, |worktree, cx| {
8401 self.update_worktree_diagnostics(
8402 worktree.id(),
8403 server_id,
8404 project_path.path.clone(),
8405 update.diagnostics.diagnostics,
8406 cx,
8407 )
8408 })?;
8409 match updated {
8410 ControlFlow::Continue(new_summary) => {
8411 if let Some((project_id, new_summary)) = new_summary {
8412 match &mut diagnostics_summary {
8413 Some(diagnostics_summary) => {
8414 diagnostics_summary
8415 .more_summaries
8416 .push(proto::DiagnosticSummary {
8417 path: project_path.path.as_ref().to_proto(),
8418 language_server_id: server_id.0 as u64,
8419 error_count: new_summary.error_count,
8420 warning_count: new_summary.warning_count,
8421 })
8422 }
8423 None => {
8424 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8425 project_id,
8426 worktree_id: worktree_id.to_proto(),
8427 summary: Some(proto::DiagnosticSummary {
8428 path: project_path.path.as_ref().to_proto(),
8429 language_server_id: server_id.0 as u64,
8430 error_count: new_summary.error_count,
8431 warning_count: new_summary.warning_count,
8432 }),
8433 more_summaries: Vec::new(),
8434 })
8435 }
8436 }
8437 }
8438 updated_diagnostics_paths
8439 .entry(server_id)
8440 .or_insert_with(Vec::new)
8441 .push(project_path);
8442 }
8443 ControlFlow::Break(()) => {}
8444 }
8445 }
8446
8447 if let Some((diagnostics_summary, (downstream_client, _))) =
8448 diagnostics_summary.zip(self.downstream_client.as_ref())
8449 {
8450 downstream_client.send(diagnostics_summary).log_err();
8451 }
8452 for (server_id, paths) in updated_diagnostics_paths {
8453 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8454 }
8455 Ok(())
8456 }
8457
8458 fn update_worktree_diagnostics(
8459 &mut self,
8460 worktree_id: WorktreeId,
8461 server_id: LanguageServerId,
8462 path_in_worktree: Arc<RelPath>,
8463 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8464 _: &mut Context<Worktree>,
8465 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8466 let local = match &mut self.mode {
8467 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8468 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8469 };
8470
8471 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8472 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8473 let summaries_by_server_id = summaries_for_tree
8474 .entry(path_in_worktree.clone())
8475 .or_default();
8476
8477 let old_summary = summaries_by_server_id
8478 .remove(&server_id)
8479 .unwrap_or_default();
8480
8481 let new_summary = DiagnosticSummary::new(&diagnostics);
8482 if diagnostics.is_empty() {
8483 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8484 {
8485 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8486 diagnostics_by_server_id.remove(ix);
8487 }
8488 if diagnostics_by_server_id.is_empty() {
8489 diagnostics_for_tree.remove(&path_in_worktree);
8490 }
8491 }
8492 } else {
8493 summaries_by_server_id.insert(server_id, new_summary);
8494 let diagnostics_by_server_id = diagnostics_for_tree
8495 .entry(path_in_worktree.clone())
8496 .or_default();
8497 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8498 Ok(ix) => {
8499 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8500 }
8501 Err(ix) => {
8502 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8503 }
8504 }
8505 }
8506
8507 if !old_summary.is_empty() || !new_summary.is_empty() {
8508 if let Some((_, project_id)) = &self.downstream_client {
8509 Ok(ControlFlow::Continue(Some((
8510 *project_id,
8511 proto::DiagnosticSummary {
8512 path: path_in_worktree.to_proto(),
8513 language_server_id: server_id.0 as u64,
8514 error_count: new_summary.error_count as u32,
8515 warning_count: new_summary.warning_count as u32,
8516 },
8517 ))))
8518 } else {
8519 Ok(ControlFlow::Continue(None))
8520 }
8521 } else {
8522 Ok(ControlFlow::Break(()))
8523 }
8524 }
8525
8526 pub fn open_buffer_for_symbol(
8527 &mut self,
8528 symbol: &Symbol,
8529 cx: &mut Context<Self>,
8530 ) -> Task<Result<Entity<Buffer>>> {
8531 if let Some((client, project_id)) = self.upstream_client() {
8532 let request = client.request(proto::OpenBufferForSymbol {
8533 project_id,
8534 symbol: Some(Self::serialize_symbol(symbol)),
8535 });
8536 cx.spawn(async move |this, cx| {
8537 let response = request.await?;
8538 let buffer_id = BufferId::new(response.buffer_id)?;
8539 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8540 .await
8541 })
8542 } else if let Some(local) = self.as_local() {
8543 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8544 seed.worktree_id == symbol.source_worktree_id
8545 && state.id == symbol.source_language_server_id
8546 && symbol.language_server_name == seed.name
8547 });
8548 if !is_valid {
8549 return Task::ready(Err(anyhow!(
8550 "language server for worktree and language not found"
8551 )));
8552 };
8553
8554 let symbol_abs_path = match &symbol.path {
8555 SymbolLocation::InProject(project_path) => self
8556 .worktree_store
8557 .read(cx)
8558 .absolutize(&project_path, cx)
8559 .context("no such worktree"),
8560 SymbolLocation::OutsideProject {
8561 abs_path,
8562 signature: _,
8563 } => Ok(abs_path.to_path_buf()),
8564 };
8565 let symbol_abs_path = match symbol_abs_path {
8566 Ok(abs_path) => abs_path,
8567 Err(err) => return Task::ready(Err(err)),
8568 };
8569 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8570 uri
8571 } else {
8572 return Task::ready(Err(anyhow!("invalid symbol path")));
8573 };
8574
8575 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8576 } else {
8577 Task::ready(Err(anyhow!("no upstream client or local store")))
8578 }
8579 }
8580
8581 pub(crate) fn open_local_buffer_via_lsp(
8582 &mut self,
8583 abs_path: lsp::Uri,
8584 language_server_id: LanguageServerId,
8585 cx: &mut Context<Self>,
8586 ) -> Task<Result<Entity<Buffer>>> {
8587 let path_style = self.worktree_store.read(cx).path_style();
8588 cx.spawn(async move |lsp_store, cx| {
8589 // Escape percent-encoded string.
8590 let current_scheme = abs_path.scheme().to_owned();
8591 // Uri is immutable, so we can't modify the scheme
8592
8593 let abs_path = abs_path
8594 .to_file_path_ext(path_style)
8595 .map_err(|()| anyhow!("can't convert URI to path"))?;
8596 let p = abs_path.clone();
8597 let yarn_worktree = lsp_store
8598 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8599 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8600 cx.spawn(async move |this, cx| {
8601 let t = this
8602 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8603 .ok()?;
8604 t.await
8605 })
8606 }),
8607 None => Task::ready(None),
8608 })?
8609 .await;
8610 let (worktree_root_target, known_relative_path) =
8611 if let Some((zip_root, relative_path)) = yarn_worktree {
8612 (zip_root, Some(relative_path))
8613 } else {
8614 (Arc::<Path>::from(abs_path.as_path()), None)
8615 };
8616 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8617 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8618 worktree_store.find_worktree(&worktree_root_target, cx)
8619 })
8620 })?;
8621 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8622 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8623 (result.0, relative_path, None)
8624 } else {
8625 let worktree = lsp_store
8626 .update(cx, |lsp_store, cx| {
8627 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8628 worktree_store.create_worktree(&worktree_root_target, false, cx)
8629 })
8630 })?
8631 .await?;
8632 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8633 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8634 lsp_store
8635 .update(cx, |lsp_store, cx| {
8636 if let Some(local) = lsp_store.as_local_mut() {
8637 local.register_language_server_for_invisible_worktree(
8638 &worktree,
8639 language_server_id,
8640 cx,
8641 )
8642 }
8643 match lsp_store.language_server_statuses.get(&language_server_id) {
8644 Some(status) => status.worktree,
8645 None => None,
8646 }
8647 })
8648 .ok()
8649 .flatten()
8650 .zip(Some(worktree_root.clone()))
8651 } else {
8652 None
8653 };
8654 let relative_path = if let Some(known_path) = known_relative_path {
8655 known_path
8656 } else {
8657 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8658 .into_arc()
8659 };
8660 (worktree, relative_path, source_ws)
8661 };
8662 let project_path = ProjectPath {
8663 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8664 path: relative_path,
8665 };
8666 let buffer = lsp_store
8667 .update(cx, |lsp_store, cx| {
8668 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8669 buffer_store.open_buffer(project_path, cx)
8670 })
8671 })?
8672 .await?;
8673 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8674 if let Some((source_ws, worktree_root)) = source_ws {
8675 buffer.update(cx, |buffer, cx| {
8676 let settings = WorktreeSettings::get(
8677 Some(
8678 (&ProjectPath {
8679 worktree_id: source_ws,
8680 path: Arc::from(RelPath::empty()),
8681 })
8682 .into(),
8683 ),
8684 cx,
8685 );
8686 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8687 if is_read_only {
8688 buffer.set_capability(Capability::ReadOnly, cx);
8689 }
8690 });
8691 }
8692 Ok(buffer)
8693 })
8694 }
8695
8696 fn local_lsp_servers_for_buffer(
8697 &self,
8698 buffer: &Entity<Buffer>,
8699 cx: &mut Context<Self>,
8700 ) -> Vec<LanguageServerId> {
8701 let Some(local) = self.as_local() else {
8702 return Vec::new();
8703 };
8704
8705 let snapshot = buffer.read(cx).snapshot();
8706
8707 buffer.update(cx, |buffer, cx| {
8708 local
8709 .language_servers_for_buffer(buffer, cx)
8710 .map(|(_, server)| server.server_id())
8711 .filter(|server_id| {
8712 self.as_local().is_none_or(|local| {
8713 local
8714 .buffers_opened_in_servers
8715 .get(&snapshot.remote_id())
8716 .is_some_and(|servers| servers.contains(server_id))
8717 })
8718 })
8719 .collect()
8720 })
8721 }
8722
8723 fn request_multiple_lsp_locally<P, R>(
8724 &mut self,
8725 buffer: &Entity<Buffer>,
8726 position: Option<P>,
8727 request: R,
8728 cx: &mut Context<Self>,
8729 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8730 where
8731 P: ToOffset,
8732 R: LspCommand + Clone,
8733 <R::LspRequest as lsp::request::Request>::Result: Send,
8734 <R::LspRequest as lsp::request::Request>::Params: Send,
8735 {
8736 let Some(local) = self.as_local() else {
8737 return Task::ready(Vec::new());
8738 };
8739
8740 let snapshot = buffer.read(cx).snapshot();
8741 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8742
8743 let server_ids = buffer.update(cx, |buffer, cx| {
8744 local
8745 .language_servers_for_buffer(buffer, cx)
8746 .filter(|(adapter, _)| {
8747 scope
8748 .as_ref()
8749 .map(|scope| scope.language_allowed(&adapter.name))
8750 .unwrap_or(true)
8751 })
8752 .map(|(_, server)| server.server_id())
8753 .filter(|server_id| {
8754 self.as_local().is_none_or(|local| {
8755 local
8756 .buffers_opened_in_servers
8757 .get(&snapshot.remote_id())
8758 .is_some_and(|servers| servers.contains(server_id))
8759 })
8760 })
8761 .collect::<Vec<_>>()
8762 });
8763
8764 let mut response_results = server_ids
8765 .into_iter()
8766 .map(|server_id| {
8767 let task = self.request_lsp(
8768 buffer.clone(),
8769 LanguageServerToQuery::Other(server_id),
8770 request.clone(),
8771 cx,
8772 );
8773 async move { (server_id, task.await) }
8774 })
8775 .collect::<FuturesUnordered<_>>();
8776
8777 cx.background_spawn(async move {
8778 let mut responses = Vec::with_capacity(response_results.len());
8779 while let Some((server_id, response_result)) = response_results.next().await {
8780 match response_result {
8781 Ok(response) => responses.push((server_id, response)),
8782 // rust-analyzer likes to error with this when its still loading up
8783 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8784 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8785 }
8786 }
8787 responses
8788 })
8789 }
8790
8791 async fn handle_lsp_get_completions(
8792 this: Entity<Self>,
8793 envelope: TypedEnvelope<proto::GetCompletions>,
8794 mut cx: AsyncApp,
8795 ) -> Result<proto::GetCompletionsResponse> {
8796 let sender_id = envelope.original_sender_id().unwrap_or_default();
8797
8798 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8799 let buffer_handle = this.update(&mut cx, |this, cx| {
8800 this.buffer_store.read(cx).get_existing(buffer_id)
8801 })?;
8802 let request = GetCompletions::from_proto(
8803 envelope.payload,
8804 this.clone(),
8805 buffer_handle.clone(),
8806 cx.clone(),
8807 )
8808 .await?;
8809
8810 let server_to_query = match request.server_id {
8811 Some(server_id) => LanguageServerToQuery::Other(server_id),
8812 None => LanguageServerToQuery::FirstCapable,
8813 };
8814
8815 let response = this
8816 .update(&mut cx, |this, cx| {
8817 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8818 })
8819 .await?;
8820 this.update(&mut cx, |this, cx| {
8821 Ok(GetCompletions::response_to_proto(
8822 response,
8823 this,
8824 sender_id,
8825 &buffer_handle.read(cx).version(),
8826 cx,
8827 ))
8828 })
8829 }
8830
8831 async fn handle_lsp_command<T: LspCommand>(
8832 this: Entity<Self>,
8833 envelope: TypedEnvelope<T::ProtoRequest>,
8834 mut cx: AsyncApp,
8835 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8836 where
8837 <T::LspRequest as lsp::request::Request>::Params: Send,
8838 <T::LspRequest as lsp::request::Request>::Result: Send,
8839 {
8840 let sender_id = envelope.original_sender_id().unwrap_or_default();
8841 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8842 let buffer_handle = this.update(&mut cx, |this, cx| {
8843 this.buffer_store.read(cx).get_existing(buffer_id)
8844 })?;
8845 let request = T::from_proto(
8846 envelope.payload,
8847 this.clone(),
8848 buffer_handle.clone(),
8849 cx.clone(),
8850 )
8851 .await?;
8852 let response = this
8853 .update(&mut cx, |this, cx| {
8854 this.request_lsp(
8855 buffer_handle.clone(),
8856 LanguageServerToQuery::FirstCapable,
8857 request,
8858 cx,
8859 )
8860 })
8861 .await?;
8862 this.update(&mut cx, |this, cx| {
8863 Ok(T::response_to_proto(
8864 response,
8865 this,
8866 sender_id,
8867 &buffer_handle.read(cx).version(),
8868 cx,
8869 ))
8870 })
8871 }
8872
8873 async fn handle_lsp_query(
8874 lsp_store: Entity<Self>,
8875 envelope: TypedEnvelope<proto::LspQuery>,
8876 mut cx: AsyncApp,
8877 ) -> Result<proto::Ack> {
8878 use proto::lsp_query::Request;
8879 let sender_id = envelope.original_sender_id().unwrap_or_default();
8880 let lsp_query = envelope.payload;
8881 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8882 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8883 match lsp_query.request.context("invalid LSP query request")? {
8884 Request::GetReferences(get_references) => {
8885 let position = get_references.position.clone().and_then(deserialize_anchor);
8886 Self::query_lsp_locally::<GetReferences>(
8887 lsp_store,
8888 server_id,
8889 sender_id,
8890 lsp_request_id,
8891 get_references,
8892 position,
8893 &mut cx,
8894 )
8895 .await?;
8896 }
8897 Request::GetDocumentColor(get_document_color) => {
8898 Self::query_lsp_locally::<GetDocumentColor>(
8899 lsp_store,
8900 server_id,
8901 sender_id,
8902 lsp_request_id,
8903 get_document_color,
8904 None,
8905 &mut cx,
8906 )
8907 .await?;
8908 }
8909 Request::GetFoldingRanges(get_folding_ranges) => {
8910 Self::query_lsp_locally::<GetFoldingRanges>(
8911 lsp_store,
8912 server_id,
8913 sender_id,
8914 lsp_request_id,
8915 get_folding_ranges,
8916 None,
8917 &mut cx,
8918 )
8919 .await?;
8920 }
8921 Request::GetDocumentSymbols(get_document_symbols) => {
8922 Self::query_lsp_locally::<GetDocumentSymbols>(
8923 lsp_store,
8924 server_id,
8925 sender_id,
8926 lsp_request_id,
8927 get_document_symbols,
8928 None,
8929 &mut cx,
8930 )
8931 .await?;
8932 }
8933 Request::GetHover(get_hover) => {
8934 let position = get_hover.position.clone().and_then(deserialize_anchor);
8935 Self::query_lsp_locally::<GetHover>(
8936 lsp_store,
8937 server_id,
8938 sender_id,
8939 lsp_request_id,
8940 get_hover,
8941 position,
8942 &mut cx,
8943 )
8944 .await?;
8945 }
8946 Request::GetCodeActions(get_code_actions) => {
8947 Self::query_lsp_locally::<GetCodeActions>(
8948 lsp_store,
8949 server_id,
8950 sender_id,
8951 lsp_request_id,
8952 get_code_actions,
8953 None,
8954 &mut cx,
8955 )
8956 .await?;
8957 }
8958 Request::GetSignatureHelp(get_signature_help) => {
8959 let position = get_signature_help
8960 .position
8961 .clone()
8962 .and_then(deserialize_anchor);
8963 Self::query_lsp_locally::<GetSignatureHelp>(
8964 lsp_store,
8965 server_id,
8966 sender_id,
8967 lsp_request_id,
8968 get_signature_help,
8969 position,
8970 &mut cx,
8971 )
8972 .await?;
8973 }
8974 Request::GetCodeLens(get_code_lens) => {
8975 Self::query_lsp_locally::<GetCodeLens>(
8976 lsp_store,
8977 server_id,
8978 sender_id,
8979 lsp_request_id,
8980 get_code_lens,
8981 None,
8982 &mut cx,
8983 )
8984 .await?;
8985 }
8986 Request::GetDefinition(get_definition) => {
8987 let position = get_definition.position.clone().and_then(deserialize_anchor);
8988 Self::query_lsp_locally::<GetDefinitions>(
8989 lsp_store,
8990 server_id,
8991 sender_id,
8992 lsp_request_id,
8993 get_definition,
8994 position,
8995 &mut cx,
8996 )
8997 .await?;
8998 }
8999 Request::GetDeclaration(get_declaration) => {
9000 let position = get_declaration
9001 .position
9002 .clone()
9003 .and_then(deserialize_anchor);
9004 Self::query_lsp_locally::<GetDeclarations>(
9005 lsp_store,
9006 server_id,
9007 sender_id,
9008 lsp_request_id,
9009 get_declaration,
9010 position,
9011 &mut cx,
9012 )
9013 .await?;
9014 }
9015 Request::GetTypeDefinition(get_type_definition) => {
9016 let position = get_type_definition
9017 .position
9018 .clone()
9019 .and_then(deserialize_anchor);
9020 Self::query_lsp_locally::<GetTypeDefinitions>(
9021 lsp_store,
9022 server_id,
9023 sender_id,
9024 lsp_request_id,
9025 get_type_definition,
9026 position,
9027 &mut cx,
9028 )
9029 .await?;
9030 }
9031 Request::GetImplementation(get_implementation) => {
9032 let position = get_implementation
9033 .position
9034 .clone()
9035 .and_then(deserialize_anchor);
9036 Self::query_lsp_locally::<GetImplementations>(
9037 lsp_store,
9038 server_id,
9039 sender_id,
9040 lsp_request_id,
9041 get_implementation,
9042 position,
9043 &mut cx,
9044 )
9045 .await?;
9046 }
9047 Request::InlayHints(inlay_hints) => {
9048 let query_start = inlay_hints
9049 .start
9050 .clone()
9051 .and_then(deserialize_anchor)
9052 .context("invalid inlay hints range start")?;
9053 let query_end = inlay_hints
9054 .end
9055 .clone()
9056 .and_then(deserialize_anchor)
9057 .context("invalid inlay hints range end")?;
9058 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9059 &lsp_store,
9060 server_id,
9061 lsp_request_id,
9062 &inlay_hints,
9063 query_start..query_end,
9064 &mut cx,
9065 )
9066 .await
9067 .context("preparing inlay hints request")?;
9068 Self::query_lsp_locally::<InlayHints>(
9069 lsp_store,
9070 server_id,
9071 sender_id,
9072 lsp_request_id,
9073 inlay_hints,
9074 None,
9075 &mut cx,
9076 )
9077 .await
9078 .context("querying for inlay hints")?
9079 }
9080 //////////////////////////////
9081 // Below are LSP queries that need to fetch more data,
9082 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9083 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9084 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9085 &lsp_store,
9086 &get_document_diagnostics,
9087 &mut cx,
9088 )
9089 .await?;
9090 lsp_store.update(&mut cx, |lsp_store, cx| {
9091 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9092 let key = LspKey {
9093 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9094 server_queried: server_id,
9095 };
9096 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9097 ) {
9098 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9099 lsp_requests.clear();
9100 };
9101 }
9102
9103 lsp_data.lsp_requests.entry(key).or_default().insert(
9104 lsp_request_id,
9105 cx.spawn(async move |lsp_store, cx| {
9106 let diagnostics_pull = lsp_store
9107 .update(cx, |lsp_store, cx| {
9108 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9109 })
9110 .ok();
9111 if let Some(diagnostics_pull) = diagnostics_pull {
9112 match diagnostics_pull.await {
9113 Ok(()) => {}
9114 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9115 };
9116 }
9117 }),
9118 );
9119 });
9120 }
9121 Request::SemanticTokens(semantic_tokens) => {
9122 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9123 &lsp_store,
9124 &semantic_tokens,
9125 &mut cx,
9126 )
9127 .await?;
9128 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9129 lsp_store.update(&mut cx, |lsp_store, cx| {
9130 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9131 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9132 let key = LspKey {
9133 request_type: TypeId::of::<SemanticTokensFull>(),
9134 server_queried: server_id,
9135 };
9136 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9137 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9138 lsp_requests.clear();
9139 };
9140 }
9141
9142 lsp_data.lsp_requests.entry(key).or_default().insert(
9143 lsp_request_id,
9144 cx.spawn(async move |lsp_store, cx| {
9145 let tokens_fetch = lsp_store
9146 .update(cx, |lsp_store, cx| {
9147 lsp_store
9148 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9149 })
9150 .ok();
9151 if let Some(tokens_fetch) = tokens_fetch {
9152 let new_tokens = tokens_fetch.await;
9153 if let Some(new_tokens) = new_tokens {
9154 lsp_store
9155 .update(cx, |lsp_store, cx| {
9156 let response = new_tokens
9157 .into_iter()
9158 .map(|(server_id, response)| {
9159 (
9160 server_id.to_proto(),
9161 SemanticTokensFull::response_to_proto(
9162 response,
9163 lsp_store,
9164 sender_id,
9165 &buffer_version,
9166 cx,
9167 ),
9168 )
9169 })
9170 .collect::<HashMap<_, _>>();
9171 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9172 project_id,
9173 lsp_request_id,
9174 response,
9175 ) {
9176 Ok(()) => {}
9177 Err(e) => {
9178 log::error!(
9179 "Failed to send semantic tokens LSP response: {e:#}",
9180 )
9181 }
9182 }
9183 })
9184 .ok();
9185 }
9186 }
9187 }),
9188 );
9189 }
9190 });
9191 }
9192 }
9193 Ok(proto::Ack {})
9194 }
9195
9196 async fn handle_lsp_query_response(
9197 lsp_store: Entity<Self>,
9198 envelope: TypedEnvelope<proto::LspQueryResponse>,
9199 cx: AsyncApp,
9200 ) -> Result<()> {
9201 lsp_store.read_with(&cx, |lsp_store, _| {
9202 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9203 upstream_client.handle_lsp_response(envelope.clone());
9204 }
9205 });
9206 Ok(())
9207 }
9208
9209 async fn handle_apply_code_action(
9210 this: Entity<Self>,
9211 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9212 mut cx: AsyncApp,
9213 ) -> Result<proto::ApplyCodeActionResponse> {
9214 let sender_id = envelope.original_sender_id().unwrap_or_default();
9215 let action =
9216 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9217 let apply_code_action = this.update(&mut cx, |this, cx| {
9218 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9219 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9220 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9221 })?;
9222
9223 let project_transaction = apply_code_action.await?;
9224 let project_transaction = this.update(&mut cx, |this, cx| {
9225 this.buffer_store.update(cx, |buffer_store, cx| {
9226 buffer_store.serialize_project_transaction_for_peer(
9227 project_transaction,
9228 sender_id,
9229 cx,
9230 )
9231 })
9232 });
9233 Ok(proto::ApplyCodeActionResponse {
9234 transaction: Some(project_transaction),
9235 })
9236 }
9237
9238 async fn handle_register_buffer_with_language_servers(
9239 this: Entity<Self>,
9240 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9241 mut cx: AsyncApp,
9242 ) -> Result<proto::Ack> {
9243 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9244 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9245 this.update(&mut cx, |this, cx| {
9246 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9247 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9248 project_id: upstream_project_id,
9249 buffer_id: buffer_id.to_proto(),
9250 only_servers: envelope.payload.only_servers,
9251 });
9252 }
9253
9254 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9255 anyhow::bail!("buffer is not open");
9256 };
9257
9258 let handle = this.register_buffer_with_language_servers(
9259 &buffer,
9260 envelope
9261 .payload
9262 .only_servers
9263 .into_iter()
9264 .filter_map(|selector| {
9265 Some(match selector.selector? {
9266 proto::language_server_selector::Selector::ServerId(server_id) => {
9267 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9268 }
9269 proto::language_server_selector::Selector::Name(name) => {
9270 LanguageServerSelector::Name(LanguageServerName(
9271 SharedString::from(name),
9272 ))
9273 }
9274 })
9275 })
9276 .collect(),
9277 false,
9278 cx,
9279 );
9280 // Pull diagnostics for the buffer even if it was already registered.
9281 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9282 // but it's unclear if we need it.
9283 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9284 .detach();
9285 this.buffer_store().update(cx, |buffer_store, _| {
9286 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9287 });
9288
9289 Ok(())
9290 })?;
9291 Ok(proto::Ack {})
9292 }
9293
9294 async fn handle_rename_project_entry(
9295 this: Entity<Self>,
9296 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9297 mut cx: AsyncApp,
9298 ) -> Result<proto::ProjectEntryResponse> {
9299 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9300 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9301 let new_path =
9302 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9303
9304 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9305 .update(&mut cx, |this, cx| {
9306 let (worktree, entry) = this
9307 .worktree_store
9308 .read(cx)
9309 .worktree_and_entry_for_id(entry_id, cx)?;
9310 let new_worktree = this
9311 .worktree_store
9312 .read(cx)
9313 .worktree_for_id(new_worktree_id, cx)?;
9314 Some((
9315 this.worktree_store.clone(),
9316 worktree,
9317 new_worktree,
9318 entry.clone(),
9319 ))
9320 })
9321 .context("worktree not found")?;
9322 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9323 (worktree.absolutize(&old_entry.path), worktree.id())
9324 });
9325 let new_abs_path =
9326 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9327
9328 let _transaction = Self::will_rename_entry(
9329 this.downgrade(),
9330 old_worktree_id,
9331 &old_abs_path,
9332 &new_abs_path,
9333 old_entry.is_dir(),
9334 cx.clone(),
9335 )
9336 .await;
9337 let response = WorktreeStore::handle_rename_project_entry(
9338 worktree_store,
9339 envelope.payload,
9340 cx.clone(),
9341 )
9342 .await;
9343 this.read_with(&cx, |this, _| {
9344 this.did_rename_entry(
9345 old_worktree_id,
9346 &old_abs_path,
9347 &new_abs_path,
9348 old_entry.is_dir(),
9349 );
9350 });
9351 response
9352 }
9353
9354 async fn handle_update_diagnostic_summary(
9355 this: Entity<Self>,
9356 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9357 mut cx: AsyncApp,
9358 ) -> Result<()> {
9359 this.update(&mut cx, |lsp_store, cx| {
9360 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9361 let mut updated_diagnostics_paths = HashMap::default();
9362 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9363 for message_summary in envelope
9364 .payload
9365 .summary
9366 .into_iter()
9367 .chain(envelope.payload.more_summaries)
9368 {
9369 let project_path = ProjectPath {
9370 worktree_id,
9371 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9372 };
9373 let path = project_path.path.clone();
9374 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9375 let summary = DiagnosticSummary {
9376 error_count: message_summary.error_count as usize,
9377 warning_count: message_summary.warning_count as usize,
9378 };
9379
9380 if summary.is_empty() {
9381 if let Some(worktree_summaries) =
9382 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9383 && let Some(summaries) = worktree_summaries.get_mut(&path)
9384 {
9385 summaries.remove(&server_id);
9386 if summaries.is_empty() {
9387 worktree_summaries.remove(&path);
9388 }
9389 }
9390 } else {
9391 lsp_store
9392 .diagnostic_summaries
9393 .entry(worktree_id)
9394 .or_default()
9395 .entry(path)
9396 .or_default()
9397 .insert(server_id, summary);
9398 }
9399
9400 if let Some((_, project_id)) = &lsp_store.downstream_client {
9401 match &mut diagnostics_summary {
9402 Some(diagnostics_summary) => {
9403 diagnostics_summary
9404 .more_summaries
9405 .push(proto::DiagnosticSummary {
9406 path: project_path.path.as_ref().to_proto(),
9407 language_server_id: server_id.0 as u64,
9408 error_count: summary.error_count as u32,
9409 warning_count: summary.warning_count as u32,
9410 })
9411 }
9412 None => {
9413 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9414 project_id: *project_id,
9415 worktree_id: worktree_id.to_proto(),
9416 summary: Some(proto::DiagnosticSummary {
9417 path: project_path.path.as_ref().to_proto(),
9418 language_server_id: server_id.0 as u64,
9419 error_count: summary.error_count as u32,
9420 warning_count: summary.warning_count as u32,
9421 }),
9422 more_summaries: Vec::new(),
9423 })
9424 }
9425 }
9426 }
9427 updated_diagnostics_paths
9428 .entry(server_id)
9429 .or_insert_with(Vec::new)
9430 .push(project_path);
9431 }
9432
9433 if let Some((diagnostics_summary, (downstream_client, _))) =
9434 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9435 {
9436 downstream_client.send(diagnostics_summary).log_err();
9437 }
9438 for (server_id, paths) in updated_diagnostics_paths {
9439 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9440 }
9441 Ok(())
9442 })
9443 }
9444
9445 async fn handle_start_language_server(
9446 lsp_store: Entity<Self>,
9447 envelope: TypedEnvelope<proto::StartLanguageServer>,
9448 mut cx: AsyncApp,
9449 ) -> Result<()> {
9450 let server = envelope.payload.server.context("invalid server")?;
9451 let server_capabilities =
9452 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9453 .with_context(|| {
9454 format!(
9455 "incorrect server capabilities {}",
9456 envelope.payload.capabilities
9457 )
9458 })?;
9459 lsp_store.update(&mut cx, |lsp_store, cx| {
9460 let server_id = LanguageServerId(server.id as usize);
9461 let server_name = LanguageServerName::from_proto(server.name.clone());
9462 lsp_store
9463 .lsp_server_capabilities
9464 .insert(server_id, server_capabilities);
9465 lsp_store.language_server_statuses.insert(
9466 server_id,
9467 LanguageServerStatus {
9468 name: server_name.clone(),
9469 server_version: None,
9470 server_readable_version: None,
9471 pending_work: Default::default(),
9472 has_pending_diagnostic_updates: false,
9473 progress_tokens: Default::default(),
9474 worktree: server.worktree_id.map(WorktreeId::from_proto),
9475 binary: None,
9476 configuration: None,
9477 workspace_folders: BTreeSet::new(),
9478 process_id: None,
9479 },
9480 );
9481 cx.emit(LspStoreEvent::LanguageServerAdded(
9482 server_id,
9483 server_name,
9484 server.worktree_id.map(WorktreeId::from_proto),
9485 ));
9486 cx.notify();
9487 });
9488 Ok(())
9489 }
9490
9491 async fn handle_update_language_server(
9492 lsp_store: Entity<Self>,
9493 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9494 mut cx: AsyncApp,
9495 ) -> Result<()> {
9496 lsp_store.update(&mut cx, |lsp_store, cx| {
9497 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9498
9499 match envelope.payload.variant.context("invalid variant")? {
9500 proto::update_language_server::Variant::WorkStart(payload) => {
9501 lsp_store.on_lsp_work_start(
9502 language_server_id,
9503 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9504 .context("invalid progress token value")?,
9505 LanguageServerProgress {
9506 title: payload.title,
9507 is_disk_based_diagnostics_progress: false,
9508 is_cancellable: payload.is_cancellable.unwrap_or(false),
9509 message: payload.message,
9510 percentage: payload.percentage.map(|p| p as usize),
9511 last_update_at: cx.background_executor().now(),
9512 },
9513 cx,
9514 );
9515 }
9516 proto::update_language_server::Variant::WorkProgress(payload) => {
9517 lsp_store.on_lsp_work_progress(
9518 language_server_id,
9519 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9520 .context("invalid progress token value")?,
9521 LanguageServerProgress {
9522 title: None,
9523 is_disk_based_diagnostics_progress: false,
9524 is_cancellable: payload.is_cancellable.unwrap_or(false),
9525 message: payload.message,
9526 percentage: payload.percentage.map(|p| p as usize),
9527 last_update_at: cx.background_executor().now(),
9528 },
9529 cx,
9530 );
9531 }
9532
9533 proto::update_language_server::Variant::WorkEnd(payload) => {
9534 lsp_store.on_lsp_work_end(
9535 language_server_id,
9536 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9537 .context("invalid progress token value")?,
9538 cx,
9539 );
9540 }
9541
9542 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9543 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9544 }
9545
9546 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9547 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9548 }
9549
9550 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9551 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9552 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9553 cx.emit(LspStoreEvent::LanguageServerUpdate {
9554 language_server_id,
9555 name: envelope
9556 .payload
9557 .server_name
9558 .map(SharedString::new)
9559 .map(LanguageServerName),
9560 message: non_lsp,
9561 });
9562 }
9563 }
9564
9565 Ok(())
9566 })
9567 }
9568
9569 async fn handle_language_server_log(
9570 this: Entity<Self>,
9571 envelope: TypedEnvelope<proto::LanguageServerLog>,
9572 mut cx: AsyncApp,
9573 ) -> Result<()> {
9574 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9575 let log_type = envelope
9576 .payload
9577 .log_type
9578 .map(LanguageServerLogType::from_proto)
9579 .context("invalid language server log type")?;
9580
9581 let message = envelope.payload.message;
9582
9583 this.update(&mut cx, |_, cx| {
9584 cx.emit(LspStoreEvent::LanguageServerLog(
9585 language_server_id,
9586 log_type,
9587 message,
9588 ));
9589 });
9590 Ok(())
9591 }
9592
9593 async fn handle_lsp_ext_cancel_flycheck(
9594 lsp_store: Entity<Self>,
9595 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9596 cx: AsyncApp,
9597 ) -> Result<proto::Ack> {
9598 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9599 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9600 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9601 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9602 } else {
9603 None
9604 }
9605 });
9606 if let Some(task) = task {
9607 task.context("handling lsp ext cancel flycheck")?;
9608 }
9609
9610 Ok(proto::Ack {})
9611 }
9612
9613 async fn handle_lsp_ext_run_flycheck(
9614 lsp_store: Entity<Self>,
9615 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9616 mut cx: AsyncApp,
9617 ) -> Result<proto::Ack> {
9618 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9619 lsp_store.update(&mut cx, |lsp_store, cx| {
9620 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9621 let text_document = if envelope.payload.current_file_only {
9622 let buffer_id = envelope
9623 .payload
9624 .buffer_id
9625 .map(|id| BufferId::new(id))
9626 .transpose()?;
9627 buffer_id
9628 .and_then(|buffer_id| {
9629 lsp_store
9630 .buffer_store()
9631 .read(cx)
9632 .get(buffer_id)
9633 .and_then(|buffer| {
9634 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9635 })
9636 .map(|path| make_text_document_identifier(&path))
9637 })
9638 .transpose()?
9639 } else {
9640 None
9641 };
9642 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9643 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9644 )?;
9645 }
9646 anyhow::Ok(())
9647 })?;
9648
9649 Ok(proto::Ack {})
9650 }
9651
9652 async fn handle_lsp_ext_clear_flycheck(
9653 lsp_store: Entity<Self>,
9654 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9655 cx: AsyncApp,
9656 ) -> Result<proto::Ack> {
9657 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9658 lsp_store.read_with(&cx, |lsp_store, _| {
9659 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9660 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9661 } else {
9662 None
9663 }
9664 });
9665
9666 Ok(proto::Ack {})
9667 }
9668
9669 pub fn disk_based_diagnostics_started(
9670 &mut self,
9671 language_server_id: LanguageServerId,
9672 cx: &mut Context<Self>,
9673 ) {
9674 if let Some(language_server_status) =
9675 self.language_server_statuses.get_mut(&language_server_id)
9676 {
9677 language_server_status.has_pending_diagnostic_updates = true;
9678 }
9679
9680 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9681 cx.emit(LspStoreEvent::LanguageServerUpdate {
9682 language_server_id,
9683 name: self
9684 .language_server_adapter_for_id(language_server_id)
9685 .map(|adapter| adapter.name()),
9686 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9687 Default::default(),
9688 ),
9689 })
9690 }
9691
9692 pub fn disk_based_diagnostics_finished(
9693 &mut self,
9694 language_server_id: LanguageServerId,
9695 cx: &mut Context<Self>,
9696 ) {
9697 if let Some(language_server_status) =
9698 self.language_server_statuses.get_mut(&language_server_id)
9699 {
9700 language_server_status.has_pending_diagnostic_updates = false;
9701 }
9702
9703 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9704 cx.emit(LspStoreEvent::LanguageServerUpdate {
9705 language_server_id,
9706 name: self
9707 .language_server_adapter_for_id(language_server_id)
9708 .map(|adapter| adapter.name()),
9709 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9710 Default::default(),
9711 ),
9712 })
9713 }
9714
9715 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9716 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9717 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9718 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9719 // the language server might take some time to publish diagnostics.
9720 fn simulate_disk_based_diagnostics_events_if_needed(
9721 &mut self,
9722 language_server_id: LanguageServerId,
9723 cx: &mut Context<Self>,
9724 ) {
9725 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9726
9727 let Some(LanguageServerState::Running {
9728 simulate_disk_based_diagnostics_completion,
9729 adapter,
9730 ..
9731 }) = self
9732 .as_local_mut()
9733 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9734 else {
9735 return;
9736 };
9737
9738 if adapter.disk_based_diagnostics_progress_token.is_some() {
9739 return;
9740 }
9741
9742 let prev_task =
9743 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9744 cx.background_executor()
9745 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9746 .await;
9747
9748 this.update(cx, |this, cx| {
9749 this.disk_based_diagnostics_finished(language_server_id, cx);
9750
9751 if let Some(LanguageServerState::Running {
9752 simulate_disk_based_diagnostics_completion,
9753 ..
9754 }) = this.as_local_mut().and_then(|local_store| {
9755 local_store.language_servers.get_mut(&language_server_id)
9756 }) {
9757 *simulate_disk_based_diagnostics_completion = None;
9758 }
9759 })
9760 .ok();
9761 }));
9762
9763 if prev_task.is_none() {
9764 self.disk_based_diagnostics_started(language_server_id, cx);
9765 }
9766 }
9767
9768 pub fn language_server_statuses(
9769 &self,
9770 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9771 self.language_server_statuses
9772 .iter()
9773 .map(|(key, value)| (*key, value))
9774 }
9775
9776 pub(super) fn did_rename_entry(
9777 &self,
9778 worktree_id: WorktreeId,
9779 old_path: &Path,
9780 new_path: &Path,
9781 is_dir: bool,
9782 ) {
9783 maybe!({
9784 let local_store = self.as_local()?;
9785
9786 let old_uri = lsp::Uri::from_file_path(old_path)
9787 .ok()
9788 .map(|uri| uri.to_string())?;
9789 let new_uri = lsp::Uri::from_file_path(new_path)
9790 .ok()
9791 .map(|uri| uri.to_string())?;
9792
9793 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9794 let Some(filter) = local_store
9795 .language_server_paths_watched_for_rename
9796 .get(&language_server.server_id())
9797 else {
9798 continue;
9799 };
9800
9801 if filter.should_send_did_rename(&old_uri, is_dir) {
9802 language_server
9803 .notify::<DidRenameFiles>(RenameFilesParams {
9804 files: vec![FileRename {
9805 old_uri: old_uri.clone(),
9806 new_uri: new_uri.clone(),
9807 }],
9808 })
9809 .ok();
9810 }
9811 }
9812 Some(())
9813 });
9814 }
9815
9816 pub(super) fn will_rename_entry(
9817 this: WeakEntity<Self>,
9818 worktree_id: WorktreeId,
9819 old_path: &Path,
9820 new_path: &Path,
9821 is_dir: bool,
9822 cx: AsyncApp,
9823 ) -> Task<ProjectTransaction> {
9824 let old_uri = lsp::Uri::from_file_path(old_path)
9825 .ok()
9826 .map(|uri| uri.to_string());
9827 let new_uri = lsp::Uri::from_file_path(new_path)
9828 .ok()
9829 .map(|uri| uri.to_string());
9830 cx.spawn(async move |cx| {
9831 let mut tasks = vec![];
9832 this.update(cx, |this, cx| {
9833 let local_store = this.as_local()?;
9834 let old_uri = old_uri?;
9835 let new_uri = new_uri?;
9836 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9837 let Some(filter) = local_store
9838 .language_server_paths_watched_for_rename
9839 .get(&language_server.server_id())
9840 else {
9841 continue;
9842 };
9843
9844 if !filter.should_send_will_rename(&old_uri, is_dir) {
9845 continue;
9846 }
9847 let request_timeout = ProjectSettings::get_global(cx)
9848 .global_lsp_settings
9849 .get_request_timeout();
9850
9851 let apply_edit = cx.spawn({
9852 let old_uri = old_uri.clone();
9853 let new_uri = new_uri.clone();
9854 let language_server = language_server.clone();
9855 async move |this, cx| {
9856 let edit = language_server
9857 .request::<WillRenameFiles>(
9858 RenameFilesParams {
9859 files: vec![FileRename { old_uri, new_uri }],
9860 },
9861 request_timeout,
9862 )
9863 .await
9864 .into_response()
9865 .context("will rename files")
9866 .log_err()
9867 .flatten()?;
9868
9869 LocalLspStore::deserialize_workspace_edit(
9870 this.upgrade()?,
9871 edit,
9872 false,
9873 language_server.clone(),
9874 cx,
9875 )
9876 .await
9877 .ok()
9878 }
9879 });
9880 tasks.push(apply_edit);
9881 }
9882 Some(())
9883 })
9884 .ok()
9885 .flatten();
9886 let mut merged_transaction = ProjectTransaction::default();
9887 for task in tasks {
9888 // Await on tasks sequentially so that the order of application of edits is deterministic
9889 // (at least with regards to the order of registration of language servers)
9890 if let Some(transaction) = task.await {
9891 for (buffer, buffer_transaction) in transaction.0 {
9892 merged_transaction.0.insert(buffer, buffer_transaction);
9893 }
9894 }
9895 }
9896 merged_transaction
9897 })
9898 }
9899
9900 fn lsp_notify_abs_paths_changed(
9901 &mut self,
9902 server_id: LanguageServerId,
9903 changes: Vec<PathEvent>,
9904 ) {
9905 maybe!({
9906 let server = self.language_server_for_id(server_id)?;
9907 let changes = changes
9908 .into_iter()
9909 .filter_map(|event| {
9910 let typ = match event.kind? {
9911 PathEventKind::Created => lsp::FileChangeType::CREATED,
9912 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9913 PathEventKind::Changed | PathEventKind::Rescan => {
9914 lsp::FileChangeType::CHANGED
9915 }
9916 };
9917 Some(lsp::FileEvent {
9918 uri: file_path_to_lsp_url(&event.path).log_err()?,
9919 typ,
9920 })
9921 })
9922 .collect::<Vec<_>>();
9923 if !changes.is_empty() {
9924 server
9925 .notify::<lsp::notification::DidChangeWatchedFiles>(
9926 lsp::DidChangeWatchedFilesParams { changes },
9927 )
9928 .ok();
9929 }
9930 Some(())
9931 });
9932 }
9933
9934 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9935 self.as_local()?.language_server_for_id(id)
9936 }
9937
9938 fn on_lsp_progress(
9939 &mut self,
9940 progress_params: lsp::ProgressParams,
9941 language_server_id: LanguageServerId,
9942 disk_based_diagnostics_progress_token: Option<String>,
9943 cx: &mut Context<Self>,
9944 ) {
9945 match progress_params.value {
9946 lsp::ProgressParamsValue::WorkDone(progress) => {
9947 self.handle_work_done_progress(
9948 progress,
9949 language_server_id,
9950 disk_based_diagnostics_progress_token,
9951 ProgressToken::from_lsp(progress_params.token),
9952 cx,
9953 );
9954 }
9955 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9956 let registration_id = match progress_params.token {
9957 lsp::NumberOrString::Number(_) => None,
9958 lsp::NumberOrString::String(token) => token
9959 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9960 .map(|(_, id)| id.to_owned()),
9961 };
9962 if let Some(LanguageServerState::Running {
9963 workspace_diagnostics_refresh_tasks,
9964 ..
9965 }) = self
9966 .as_local_mut()
9967 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9968 && let Some(workspace_diagnostics) =
9969 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9970 {
9971 workspace_diagnostics.progress_tx.try_send(()).ok();
9972 self.apply_workspace_diagnostic_report(
9973 language_server_id,
9974 report,
9975 registration_id.map(SharedString::from),
9976 cx,
9977 )
9978 }
9979 }
9980 }
9981 }
9982
9983 fn handle_work_done_progress(
9984 &mut self,
9985 progress: lsp::WorkDoneProgress,
9986 language_server_id: LanguageServerId,
9987 disk_based_diagnostics_progress_token: Option<String>,
9988 token: ProgressToken,
9989 cx: &mut Context<Self>,
9990 ) {
9991 let language_server_status =
9992 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9993 status
9994 } else {
9995 return;
9996 };
9997
9998 if !language_server_status.progress_tokens.contains(&token) {
9999 return;
10000 }
10001
10002 let is_disk_based_diagnostics_progress =
10003 if let (Some(disk_based_token), ProgressToken::String(token)) =
10004 (&disk_based_diagnostics_progress_token, &token)
10005 {
10006 token.starts_with(disk_based_token)
10007 } else {
10008 false
10009 };
10010
10011 match progress {
10012 lsp::WorkDoneProgress::Begin(report) => {
10013 if is_disk_based_diagnostics_progress {
10014 self.disk_based_diagnostics_started(language_server_id, cx);
10015 }
10016 self.on_lsp_work_start(
10017 language_server_id,
10018 token.clone(),
10019 LanguageServerProgress {
10020 title: Some(report.title),
10021 is_disk_based_diagnostics_progress,
10022 is_cancellable: report.cancellable.unwrap_or(false),
10023 message: report.message.clone(),
10024 percentage: report.percentage.map(|p| p as usize),
10025 last_update_at: cx.background_executor().now(),
10026 },
10027 cx,
10028 );
10029 }
10030 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10031 language_server_id,
10032 token,
10033 LanguageServerProgress {
10034 title: None,
10035 is_disk_based_diagnostics_progress,
10036 is_cancellable: report.cancellable.unwrap_or(false),
10037 message: report.message,
10038 percentage: report.percentage.map(|p| p as usize),
10039 last_update_at: cx.background_executor().now(),
10040 },
10041 cx,
10042 ),
10043 lsp::WorkDoneProgress::End(_) => {
10044 language_server_status.progress_tokens.remove(&token);
10045 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10046 if is_disk_based_diagnostics_progress {
10047 self.disk_based_diagnostics_finished(language_server_id, cx);
10048 }
10049 }
10050 }
10051 }
10052
10053 fn on_lsp_work_start(
10054 &mut self,
10055 language_server_id: LanguageServerId,
10056 token: ProgressToken,
10057 progress: LanguageServerProgress,
10058 cx: &mut Context<Self>,
10059 ) {
10060 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10061 status.pending_work.insert(token.clone(), progress.clone());
10062 cx.notify();
10063 }
10064 cx.emit(LspStoreEvent::LanguageServerUpdate {
10065 language_server_id,
10066 name: self
10067 .language_server_adapter_for_id(language_server_id)
10068 .map(|adapter| adapter.name()),
10069 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10070 token: Some(token.to_proto()),
10071 title: progress.title,
10072 message: progress.message,
10073 percentage: progress.percentage.map(|p| p as u32),
10074 is_cancellable: Some(progress.is_cancellable),
10075 }),
10076 })
10077 }
10078
10079 fn on_lsp_work_progress(
10080 &mut self,
10081 language_server_id: LanguageServerId,
10082 token: ProgressToken,
10083 progress: LanguageServerProgress,
10084 cx: &mut Context<Self>,
10085 ) {
10086 let mut did_update = false;
10087 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10088 match status.pending_work.entry(token.clone()) {
10089 btree_map::Entry::Vacant(entry) => {
10090 entry.insert(progress.clone());
10091 did_update = true;
10092 }
10093 btree_map::Entry::Occupied(mut entry) => {
10094 let entry = entry.get_mut();
10095 if (progress.last_update_at - entry.last_update_at)
10096 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10097 {
10098 entry.last_update_at = progress.last_update_at;
10099 if progress.message.is_some() {
10100 entry.message = progress.message.clone();
10101 }
10102 if progress.percentage.is_some() {
10103 entry.percentage = progress.percentage;
10104 }
10105 if progress.is_cancellable != entry.is_cancellable {
10106 entry.is_cancellable = progress.is_cancellable;
10107 }
10108 did_update = true;
10109 }
10110 }
10111 }
10112 }
10113
10114 if did_update {
10115 cx.emit(LspStoreEvent::LanguageServerUpdate {
10116 language_server_id,
10117 name: self
10118 .language_server_adapter_for_id(language_server_id)
10119 .map(|adapter| adapter.name()),
10120 message: proto::update_language_server::Variant::WorkProgress(
10121 proto::LspWorkProgress {
10122 token: Some(token.to_proto()),
10123 message: progress.message,
10124 percentage: progress.percentage.map(|p| p as u32),
10125 is_cancellable: Some(progress.is_cancellable),
10126 },
10127 ),
10128 })
10129 }
10130 }
10131
10132 fn on_lsp_work_end(
10133 &mut self,
10134 language_server_id: LanguageServerId,
10135 token: ProgressToken,
10136 cx: &mut Context<Self>,
10137 ) {
10138 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10139 if let Some(work) = status.pending_work.remove(&token)
10140 && !work.is_disk_based_diagnostics_progress
10141 {
10142 cx.emit(LspStoreEvent::RefreshInlayHints {
10143 server_id: language_server_id,
10144 request_id: None,
10145 });
10146 }
10147 cx.notify();
10148 }
10149
10150 cx.emit(LspStoreEvent::LanguageServerUpdate {
10151 language_server_id,
10152 name: self
10153 .language_server_adapter_for_id(language_server_id)
10154 .map(|adapter| adapter.name()),
10155 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10156 token: Some(token.to_proto()),
10157 }),
10158 })
10159 }
10160
10161 pub async fn handle_resolve_completion_documentation(
10162 this: Entity<Self>,
10163 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10164 mut cx: AsyncApp,
10165 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10166 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10167
10168 let completion = this
10169 .read_with(&cx, |this, cx| {
10170 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10171 let server = this
10172 .language_server_for_id(id)
10173 .with_context(|| format!("No language server {id}"))?;
10174
10175 let request_timeout = ProjectSettings::get_global(cx)
10176 .global_lsp_settings
10177 .get_request_timeout();
10178
10179 anyhow::Ok(cx.background_spawn(async move {
10180 let can_resolve = server
10181 .capabilities()
10182 .completion_provider
10183 .as_ref()
10184 .and_then(|options| options.resolve_provider)
10185 .unwrap_or(false);
10186 if can_resolve {
10187 server
10188 .request::<lsp::request::ResolveCompletionItem>(
10189 lsp_completion,
10190 request_timeout,
10191 )
10192 .await
10193 .into_response()
10194 .context("resolve completion item")
10195 } else {
10196 anyhow::Ok(lsp_completion)
10197 }
10198 }))
10199 })?
10200 .await?;
10201
10202 let mut documentation_is_markdown = false;
10203 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10204 let documentation = match completion.documentation {
10205 Some(lsp::Documentation::String(text)) => text,
10206
10207 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10208 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10209 value
10210 }
10211
10212 _ => String::new(),
10213 };
10214
10215 // If we have a new buffer_id, that means we're talking to a new client
10216 // and want to check for new text_edits in the completion too.
10217 let mut old_replace_start = None;
10218 let mut old_replace_end = None;
10219 let mut old_insert_start = None;
10220 let mut old_insert_end = None;
10221 let mut new_text = String::default();
10222 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10223 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10224 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10225 anyhow::Ok(buffer.read(cx).snapshot())
10226 })?;
10227
10228 if let Some(text_edit) = completion.text_edit.as_ref() {
10229 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10230
10231 if let Some(mut edit) = edit {
10232 LineEnding::normalize(&mut edit.new_text);
10233
10234 new_text = edit.new_text;
10235 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10236 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10237 if let Some(insert_range) = edit.insert_range {
10238 old_insert_start = Some(serialize_anchor(&insert_range.start));
10239 old_insert_end = Some(serialize_anchor(&insert_range.end));
10240 }
10241 }
10242 }
10243 }
10244
10245 Ok(proto::ResolveCompletionDocumentationResponse {
10246 documentation,
10247 documentation_is_markdown,
10248 old_replace_start,
10249 old_replace_end,
10250 new_text,
10251 lsp_completion,
10252 old_insert_start,
10253 old_insert_end,
10254 })
10255 }
10256
10257 async fn handle_on_type_formatting(
10258 this: Entity<Self>,
10259 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10260 mut cx: AsyncApp,
10261 ) -> Result<proto::OnTypeFormattingResponse> {
10262 let on_type_formatting = this.update(&mut cx, |this, cx| {
10263 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10264 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10265 let position = envelope
10266 .payload
10267 .position
10268 .and_then(deserialize_anchor)
10269 .context("invalid position")?;
10270 anyhow::Ok(this.apply_on_type_formatting(
10271 buffer,
10272 position,
10273 envelope.payload.trigger.clone(),
10274 cx,
10275 ))
10276 })?;
10277
10278 let transaction = on_type_formatting
10279 .await?
10280 .as_ref()
10281 .map(language::proto::serialize_transaction);
10282 Ok(proto::OnTypeFormattingResponse { transaction })
10283 }
10284
10285 async fn handle_pull_workspace_diagnostics(
10286 lsp_store: Entity<Self>,
10287 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10288 mut cx: AsyncApp,
10289 ) -> Result<proto::Ack> {
10290 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10291 lsp_store.update(&mut cx, |lsp_store, _| {
10292 lsp_store.pull_workspace_diagnostics(server_id);
10293 });
10294 Ok(proto::Ack {})
10295 }
10296
10297 async fn handle_open_buffer_for_symbol(
10298 this: Entity<Self>,
10299 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10300 mut cx: AsyncApp,
10301 ) -> Result<proto::OpenBufferForSymbolResponse> {
10302 let peer_id = envelope.original_sender_id().unwrap_or_default();
10303 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10304 let symbol = Self::deserialize_symbol(symbol)?;
10305 this.read_with(&cx, |this, _| {
10306 if let SymbolLocation::OutsideProject {
10307 abs_path,
10308 signature,
10309 } = &symbol.path
10310 {
10311 let new_signature = this.symbol_signature(&abs_path);
10312 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10313 }
10314 Ok(())
10315 })?;
10316 let buffer = this
10317 .update(&mut cx, |this, cx| {
10318 this.open_buffer_for_symbol(
10319 &Symbol {
10320 language_server_name: symbol.language_server_name,
10321 source_worktree_id: symbol.source_worktree_id,
10322 source_language_server_id: symbol.source_language_server_id,
10323 path: symbol.path,
10324 name: symbol.name,
10325 kind: symbol.kind,
10326 range: symbol.range,
10327 label: CodeLabel::default(),
10328 container_name: symbol.container_name,
10329 },
10330 cx,
10331 )
10332 })
10333 .await?;
10334
10335 this.update(&mut cx, |this, cx| {
10336 let is_private = buffer
10337 .read(cx)
10338 .file()
10339 .map(|f| f.is_private())
10340 .unwrap_or_default();
10341 if is_private {
10342 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10343 } else {
10344 this.buffer_store
10345 .update(cx, |buffer_store, cx| {
10346 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10347 })
10348 .detach_and_log_err(cx);
10349 let buffer_id = buffer.read(cx).remote_id().to_proto();
10350 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10351 }
10352 })
10353 }
10354
10355 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10356 let mut hasher = Sha256::new();
10357 hasher.update(abs_path.to_string_lossy().as_bytes());
10358 hasher.update(self.nonce.to_be_bytes());
10359 hasher.finalize().as_slice().try_into().unwrap()
10360 }
10361
10362 pub async fn handle_get_project_symbols(
10363 this: Entity<Self>,
10364 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10365 mut cx: AsyncApp,
10366 ) -> Result<proto::GetProjectSymbolsResponse> {
10367 let symbols = this
10368 .update(&mut cx, |this, cx| {
10369 this.symbols(&envelope.payload.query, cx)
10370 })
10371 .await?;
10372
10373 Ok(proto::GetProjectSymbolsResponse {
10374 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10375 })
10376 }
10377
10378 pub async fn handle_restart_language_servers(
10379 this: Entity<Self>,
10380 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10381 mut cx: AsyncApp,
10382 ) -> Result<proto::Ack> {
10383 this.update(&mut cx, |lsp_store, cx| {
10384 let buffers =
10385 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10386 lsp_store.restart_language_servers_for_buffers(
10387 buffers,
10388 envelope
10389 .payload
10390 .only_servers
10391 .into_iter()
10392 .filter_map(|selector| {
10393 Some(match selector.selector? {
10394 proto::language_server_selector::Selector::ServerId(server_id) => {
10395 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10396 }
10397 proto::language_server_selector::Selector::Name(name) => {
10398 LanguageServerSelector::Name(LanguageServerName(
10399 SharedString::from(name),
10400 ))
10401 }
10402 })
10403 })
10404 .collect(),
10405 cx,
10406 );
10407 });
10408
10409 Ok(proto::Ack {})
10410 }
10411
10412 pub async fn handle_stop_language_servers(
10413 lsp_store: Entity<Self>,
10414 envelope: TypedEnvelope<proto::StopLanguageServers>,
10415 mut cx: AsyncApp,
10416 ) -> Result<proto::Ack> {
10417 lsp_store.update(&mut cx, |lsp_store, cx| {
10418 if envelope.payload.all
10419 && envelope.payload.also_servers.is_empty()
10420 && envelope.payload.buffer_ids.is_empty()
10421 {
10422 lsp_store.stop_all_language_servers(cx);
10423 } else {
10424 let buffers =
10425 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10426 lsp_store
10427 .stop_language_servers_for_buffers(
10428 buffers,
10429 envelope
10430 .payload
10431 .also_servers
10432 .into_iter()
10433 .filter_map(|selector| {
10434 Some(match selector.selector? {
10435 proto::language_server_selector::Selector::ServerId(
10436 server_id,
10437 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10438 server_id,
10439 )),
10440 proto::language_server_selector::Selector::Name(name) => {
10441 LanguageServerSelector::Name(LanguageServerName(
10442 SharedString::from(name),
10443 ))
10444 }
10445 })
10446 })
10447 .collect(),
10448 cx,
10449 )
10450 .detach_and_log_err(cx);
10451 }
10452 });
10453
10454 Ok(proto::Ack {})
10455 }
10456
10457 pub async fn handle_cancel_language_server_work(
10458 lsp_store: Entity<Self>,
10459 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10460 mut cx: AsyncApp,
10461 ) -> Result<proto::Ack> {
10462 lsp_store.update(&mut cx, |lsp_store, cx| {
10463 if let Some(work) = envelope.payload.work {
10464 match work {
10465 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10466 let buffers =
10467 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10468 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10469 }
10470 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10471 let server_id = LanguageServerId::from_proto(work.language_server_id);
10472 let token = work
10473 .token
10474 .map(|token| {
10475 ProgressToken::from_proto(token)
10476 .context("invalid work progress token")
10477 })
10478 .transpose()?;
10479 lsp_store.cancel_language_server_work(server_id, token, cx);
10480 }
10481 }
10482 }
10483 anyhow::Ok(())
10484 })?;
10485
10486 Ok(proto::Ack {})
10487 }
10488
10489 fn buffer_ids_to_buffers(
10490 &mut self,
10491 buffer_ids: impl Iterator<Item = u64>,
10492 cx: &mut Context<Self>,
10493 ) -> Vec<Entity<Buffer>> {
10494 buffer_ids
10495 .into_iter()
10496 .flat_map(|buffer_id| {
10497 self.buffer_store
10498 .read(cx)
10499 .get(BufferId::new(buffer_id).log_err()?)
10500 })
10501 .collect::<Vec<_>>()
10502 }
10503
10504 async fn handle_apply_additional_edits_for_completion(
10505 this: Entity<Self>,
10506 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10507 mut cx: AsyncApp,
10508 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10509 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10510 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10511 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10512 let completion = Self::deserialize_completion(
10513 envelope.payload.completion.context("invalid completion")?,
10514 )?;
10515 let all_commit_ranges = envelope
10516 .payload
10517 .all_commit_ranges
10518 .into_iter()
10519 .map(language::proto::deserialize_anchor_range)
10520 .collect::<Result<Vec<_>, _>>()?;
10521 anyhow::Ok((buffer, completion, all_commit_ranges))
10522 })?;
10523
10524 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10525 this.apply_additional_edits_for_completion(
10526 buffer,
10527 Rc::new(RefCell::new(Box::new([Completion {
10528 replace_range: completion.replace_range,
10529 new_text: completion.new_text,
10530 source: completion.source,
10531 documentation: None,
10532 label: CodeLabel::default(),
10533 match_start: None,
10534 snippet_deduplication_key: None,
10535 insert_text_mode: None,
10536 icon_path: None,
10537 confirm: None,
10538 }]))),
10539 0,
10540 false,
10541 all_commit_ranges,
10542 cx,
10543 )
10544 });
10545
10546 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10547 transaction: apply_additional_edits
10548 .await?
10549 .as_ref()
10550 .map(language::proto::serialize_transaction),
10551 })
10552 }
10553
10554 pub fn last_formatting_failure(&self) -> Option<&str> {
10555 self.last_formatting_failure.as_deref()
10556 }
10557
10558 pub fn reset_last_formatting_failure(&mut self) {
10559 self.last_formatting_failure = None;
10560 }
10561
10562 pub fn environment_for_buffer(
10563 &self,
10564 buffer: &Entity<Buffer>,
10565 cx: &mut Context<Self>,
10566 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10567 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10568 environment.update(cx, |env, cx| {
10569 env.buffer_environment(buffer, &self.worktree_store, cx)
10570 })
10571 } else {
10572 Task::ready(None).shared()
10573 }
10574 }
10575
10576 pub fn format(
10577 &mut self,
10578 buffers: HashSet<Entity<Buffer>>,
10579 target: LspFormatTarget,
10580 push_to_history: bool,
10581 trigger: FormatTrigger,
10582 cx: &mut Context<Self>,
10583 ) -> Task<anyhow::Result<ProjectTransaction>> {
10584 let logger = zlog::scoped!("format");
10585 if self.as_local().is_some() {
10586 zlog::trace!(logger => "Formatting locally");
10587 let logger = zlog::scoped!(logger => "local");
10588 let buffers = buffers
10589 .into_iter()
10590 .map(|buffer_handle| {
10591 let buffer = buffer_handle.read(cx);
10592 let buffer_abs_path = File::from_dyn(buffer.file())
10593 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10594
10595 (buffer_handle, buffer_abs_path, buffer.remote_id())
10596 })
10597 .collect::<Vec<_>>();
10598
10599 cx.spawn(async move |lsp_store, cx| {
10600 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10601
10602 for (handle, abs_path, id) in buffers {
10603 let env = lsp_store
10604 .update(cx, |lsp_store, cx| {
10605 lsp_store.environment_for_buffer(&handle, cx)
10606 })?
10607 .await;
10608
10609 let ranges = match &target {
10610 LspFormatTarget::Buffers => None,
10611 LspFormatTarget::Ranges(ranges) => {
10612 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10613 }
10614 };
10615
10616 formattable_buffers.push(FormattableBuffer {
10617 handle,
10618 abs_path,
10619 env,
10620 ranges,
10621 });
10622 }
10623 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10624
10625 let format_timer = zlog::time!(logger => "Formatting buffers");
10626 let result = LocalLspStore::format_locally(
10627 lsp_store.clone(),
10628 formattable_buffers,
10629 push_to_history,
10630 trigger,
10631 logger,
10632 cx,
10633 )
10634 .await;
10635 format_timer.end();
10636
10637 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10638
10639 lsp_store.update(cx, |lsp_store, _| {
10640 lsp_store.update_last_formatting_failure(&result);
10641 })?;
10642
10643 result
10644 })
10645 } else if let Some((client, project_id)) = self.upstream_client() {
10646 zlog::trace!(logger => "Formatting remotely");
10647 let logger = zlog::scoped!(logger => "remote");
10648
10649 let buffer_ranges = match &target {
10650 LspFormatTarget::Buffers => Vec::new(),
10651 LspFormatTarget::Ranges(ranges) => ranges
10652 .iter()
10653 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10654 buffer_id: buffer_id.to_proto(),
10655 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10656 })
10657 .collect(),
10658 };
10659
10660 let buffer_store = self.buffer_store();
10661 cx.spawn(async move |lsp_store, cx| {
10662 zlog::trace!(logger => "Sending remote format request");
10663 let request_timer = zlog::time!(logger => "remote format request");
10664 let result = client
10665 .request(proto::FormatBuffers {
10666 project_id,
10667 trigger: trigger as i32,
10668 buffer_ids: buffers
10669 .iter()
10670 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10671 .collect(),
10672 buffer_ranges,
10673 })
10674 .await
10675 .and_then(|result| result.transaction.context("missing transaction"));
10676 request_timer.end();
10677
10678 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10679
10680 lsp_store.update(cx, |lsp_store, _| {
10681 lsp_store.update_last_formatting_failure(&result);
10682 })?;
10683
10684 let transaction_response = result?;
10685 let _timer = zlog::time!(logger => "deserializing project transaction");
10686 buffer_store
10687 .update(cx, |buffer_store, cx| {
10688 buffer_store.deserialize_project_transaction(
10689 transaction_response,
10690 push_to_history,
10691 cx,
10692 )
10693 })
10694 .await
10695 })
10696 } else {
10697 zlog::trace!(logger => "Not formatting");
10698 Task::ready(Ok(ProjectTransaction::default()))
10699 }
10700 }
10701
10702 async fn handle_format_buffers(
10703 this: Entity<Self>,
10704 envelope: TypedEnvelope<proto::FormatBuffers>,
10705 mut cx: AsyncApp,
10706 ) -> Result<proto::FormatBuffersResponse> {
10707 let sender_id = envelope.original_sender_id().unwrap_or_default();
10708 let format = this.update(&mut cx, |this, cx| {
10709 let mut buffers = HashSet::default();
10710 for buffer_id in &envelope.payload.buffer_ids {
10711 let buffer_id = BufferId::new(*buffer_id)?;
10712 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10713 }
10714
10715 let target = if envelope.payload.buffer_ranges.is_empty() {
10716 LspFormatTarget::Buffers
10717 } else {
10718 let mut ranges_map = BTreeMap::new();
10719 for buffer_range in &envelope.payload.buffer_ranges {
10720 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10721 let ranges: Result<Vec<_>> = buffer_range
10722 .ranges
10723 .iter()
10724 .map(|range| {
10725 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10726 })
10727 .collect();
10728 ranges_map.insert(buffer_id, ranges?);
10729 }
10730 LspFormatTarget::Ranges(ranges_map)
10731 };
10732
10733 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10734 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10735 })?;
10736
10737 let project_transaction = format.await?;
10738 let project_transaction = this.update(&mut cx, |this, cx| {
10739 this.buffer_store.update(cx, |buffer_store, cx| {
10740 buffer_store.serialize_project_transaction_for_peer(
10741 project_transaction,
10742 sender_id,
10743 cx,
10744 )
10745 })
10746 });
10747 Ok(proto::FormatBuffersResponse {
10748 transaction: Some(project_transaction),
10749 })
10750 }
10751
10752 async fn handle_apply_code_action_kind(
10753 this: Entity<Self>,
10754 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10755 mut cx: AsyncApp,
10756 ) -> Result<proto::ApplyCodeActionKindResponse> {
10757 let sender_id = envelope.original_sender_id().unwrap_or_default();
10758 let format = this.update(&mut cx, |this, cx| {
10759 let mut buffers = HashSet::default();
10760 for buffer_id in &envelope.payload.buffer_ids {
10761 let buffer_id = BufferId::new(*buffer_id)?;
10762 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10763 }
10764 let kind = match envelope.payload.kind.as_str() {
10765 "" => CodeActionKind::EMPTY,
10766 "quickfix" => CodeActionKind::QUICKFIX,
10767 "refactor" => CodeActionKind::REFACTOR,
10768 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10769 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10770 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10771 "source" => CodeActionKind::SOURCE,
10772 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10773 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10774 _ => anyhow::bail!(
10775 "Invalid code action kind {}",
10776 envelope.payload.kind.as_str()
10777 ),
10778 };
10779 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10780 })?;
10781
10782 let project_transaction = format.await?;
10783 let project_transaction = this.update(&mut cx, |this, cx| {
10784 this.buffer_store.update(cx, |buffer_store, cx| {
10785 buffer_store.serialize_project_transaction_for_peer(
10786 project_transaction,
10787 sender_id,
10788 cx,
10789 )
10790 })
10791 });
10792 Ok(proto::ApplyCodeActionKindResponse {
10793 transaction: Some(project_transaction),
10794 })
10795 }
10796
10797 async fn shutdown_language_server(
10798 server_state: Option<LanguageServerState>,
10799 name: LanguageServerName,
10800 cx: &mut AsyncApp,
10801 ) {
10802 let server = match server_state {
10803 Some(LanguageServerState::Starting { startup, .. }) => {
10804 let mut timer = cx
10805 .background_executor()
10806 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10807 .fuse();
10808
10809 select! {
10810 server = startup.fuse() => server,
10811 () = timer => {
10812 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10813 None
10814 },
10815 }
10816 }
10817
10818 Some(LanguageServerState::Running { server, .. }) => Some(server),
10819
10820 None => None,
10821 };
10822
10823 let Some(server) = server else { return };
10824 if let Some(shutdown) = server.shutdown() {
10825 shutdown.await;
10826 }
10827 }
10828
10829 // Returns a list of all of the worktrees which no longer have a language server and the root path
10830 // for the stopped server
10831 fn stop_local_language_server(
10832 &mut self,
10833 server_id: LanguageServerId,
10834 cx: &mut Context<Self>,
10835 ) -> Task<()> {
10836 let local = match &mut self.mode {
10837 LspStoreMode::Local(local) => local,
10838 _ => {
10839 return Task::ready(());
10840 }
10841 };
10842
10843 // Remove this server ID from all entries in the given worktree.
10844 local
10845 .language_server_ids
10846 .retain(|_, state| state.id != server_id);
10847 self.buffer_store.update(cx, |buffer_store, cx| {
10848 for buffer in buffer_store.buffers() {
10849 buffer.update(cx, |buffer, cx| {
10850 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10851 buffer.set_completion_triggers(server_id, Default::default(), cx);
10852 });
10853 }
10854 });
10855
10856 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10857 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10858 summaries.retain(|path, summaries_by_server_id| {
10859 if summaries_by_server_id.remove(&server_id).is_some() {
10860 if let Some((client, project_id)) = self.downstream_client.clone() {
10861 client
10862 .send(proto::UpdateDiagnosticSummary {
10863 project_id,
10864 worktree_id: worktree_id.to_proto(),
10865 summary: Some(proto::DiagnosticSummary {
10866 path: path.as_ref().to_proto(),
10867 language_server_id: server_id.0 as u64,
10868 error_count: 0,
10869 warning_count: 0,
10870 }),
10871 more_summaries: Vec::new(),
10872 })
10873 .log_err();
10874 }
10875 cleared_paths.push(ProjectPath {
10876 worktree_id: *worktree_id,
10877 path: path.clone(),
10878 });
10879 !summaries_by_server_id.is_empty()
10880 } else {
10881 true
10882 }
10883 });
10884 }
10885 if !cleared_paths.is_empty() {
10886 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10887 server_id,
10888 paths: cleared_paths,
10889 });
10890 }
10891
10892 let local = self.as_local_mut().unwrap();
10893 for diagnostics in local.diagnostics.values_mut() {
10894 diagnostics.retain(|_, diagnostics_by_server_id| {
10895 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10896 diagnostics_by_server_id.remove(ix);
10897 !diagnostics_by_server_id.is_empty()
10898 } else {
10899 true
10900 }
10901 });
10902 }
10903 local.language_server_watched_paths.remove(&server_id);
10904
10905 let server_state = local.language_servers.remove(&server_id);
10906 self.cleanup_lsp_data(server_id);
10907 let name = self
10908 .language_server_statuses
10909 .remove(&server_id)
10910 .map(|status| status.name)
10911 .or_else(|| {
10912 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10913 Some(adapter.name())
10914 } else {
10915 None
10916 }
10917 });
10918
10919 if let Some(name) = name {
10920 log::info!("stopping language server {name}");
10921 self.languages
10922 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10923 cx.notify();
10924
10925 return cx.spawn(async move |lsp_store, cx| {
10926 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10927 lsp_store
10928 .update(cx, |lsp_store, cx| {
10929 lsp_store
10930 .languages
10931 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10932 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10933 cx.notify();
10934 })
10935 .ok();
10936 });
10937 }
10938
10939 if server_state.is_some() {
10940 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10941 }
10942 Task::ready(())
10943 }
10944
10945 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10946 self.shutdown_all_language_servers(cx).detach();
10947 }
10948
10949 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10950 if let Some((client, project_id)) = self.upstream_client() {
10951 let request = client.request(proto::StopLanguageServers {
10952 project_id,
10953 buffer_ids: Vec::new(),
10954 also_servers: Vec::new(),
10955 all: true,
10956 });
10957 cx.background_spawn(async move {
10958 request.await.ok();
10959 })
10960 } else {
10961 let Some(local) = self.as_local_mut() else {
10962 return Task::ready(());
10963 };
10964 let language_servers_to_stop = local
10965 .language_server_ids
10966 .values()
10967 .map(|state| state.id)
10968 .collect();
10969 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10970 let tasks = language_servers_to_stop
10971 .into_iter()
10972 .map(|server| self.stop_local_language_server(server, cx))
10973 .collect::<Vec<_>>();
10974 cx.background_spawn(async move {
10975 futures::future::join_all(tasks).await;
10976 })
10977 }
10978 }
10979
10980 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10981 let buffers = self.buffer_store.read(cx).buffers().collect();
10982 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10983 }
10984
10985 pub fn restart_language_servers_for_buffers(
10986 &mut self,
10987 buffers: Vec<Entity<Buffer>>,
10988 only_restart_servers: HashSet<LanguageServerSelector>,
10989 cx: &mut Context<Self>,
10990 ) {
10991 if let Some((client, project_id)) = self.upstream_client() {
10992 let request = client.request(proto::RestartLanguageServers {
10993 project_id,
10994 buffer_ids: buffers
10995 .into_iter()
10996 .map(|b| b.read(cx).remote_id().to_proto())
10997 .collect(),
10998 only_servers: only_restart_servers
10999 .into_iter()
11000 .map(|selector| {
11001 let selector = match selector {
11002 LanguageServerSelector::Id(language_server_id) => {
11003 proto::language_server_selector::Selector::ServerId(
11004 language_server_id.to_proto(),
11005 )
11006 }
11007 LanguageServerSelector::Name(language_server_name) => {
11008 proto::language_server_selector::Selector::Name(
11009 language_server_name.to_string(),
11010 )
11011 }
11012 };
11013 proto::LanguageServerSelector {
11014 selector: Some(selector),
11015 }
11016 })
11017 .collect(),
11018 all: false,
11019 });
11020 cx.background_spawn(request).detach_and_log_err(cx);
11021 } else {
11022 let stop_task = if only_restart_servers.is_empty() {
11023 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11024 } else {
11025 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11026 };
11027 cx.spawn(async move |lsp_store, cx| {
11028 stop_task.await;
11029 lsp_store.update(cx, |lsp_store, cx| {
11030 for buffer in buffers {
11031 lsp_store.register_buffer_with_language_servers(
11032 &buffer,
11033 only_restart_servers.clone(),
11034 true,
11035 cx,
11036 );
11037 }
11038 })
11039 })
11040 .detach();
11041 }
11042 }
11043
11044 pub fn stop_language_servers_for_buffers(
11045 &mut self,
11046 buffers: Vec<Entity<Buffer>>,
11047 also_stop_servers: HashSet<LanguageServerSelector>,
11048 cx: &mut Context<Self>,
11049 ) -> Task<Result<()>> {
11050 if let Some((client, project_id)) = self.upstream_client() {
11051 let request = client.request(proto::StopLanguageServers {
11052 project_id,
11053 buffer_ids: buffers
11054 .into_iter()
11055 .map(|b| b.read(cx).remote_id().to_proto())
11056 .collect(),
11057 also_servers: also_stop_servers
11058 .into_iter()
11059 .map(|selector| {
11060 let selector = match selector {
11061 LanguageServerSelector::Id(language_server_id) => {
11062 proto::language_server_selector::Selector::ServerId(
11063 language_server_id.to_proto(),
11064 )
11065 }
11066 LanguageServerSelector::Name(language_server_name) => {
11067 proto::language_server_selector::Selector::Name(
11068 language_server_name.to_string(),
11069 )
11070 }
11071 };
11072 proto::LanguageServerSelector {
11073 selector: Some(selector),
11074 }
11075 })
11076 .collect(),
11077 all: false,
11078 });
11079 cx.background_spawn(async move {
11080 let _ = request.await?;
11081 Ok(())
11082 })
11083 } else {
11084 let task =
11085 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11086 cx.background_spawn(async move {
11087 task.await;
11088 Ok(())
11089 })
11090 }
11091 }
11092
11093 fn stop_local_language_servers_for_buffers(
11094 &mut self,
11095 buffers: &[Entity<Buffer>],
11096 also_stop_servers: HashSet<LanguageServerSelector>,
11097 cx: &mut Context<Self>,
11098 ) -> Task<()> {
11099 let Some(local) = self.as_local_mut() else {
11100 return Task::ready(());
11101 };
11102 let mut language_server_names_to_stop = BTreeSet::default();
11103 let mut language_servers_to_stop = also_stop_servers
11104 .into_iter()
11105 .flat_map(|selector| match selector {
11106 LanguageServerSelector::Id(id) => Some(id),
11107 LanguageServerSelector::Name(name) => {
11108 language_server_names_to_stop.insert(name);
11109 None
11110 }
11111 })
11112 .collect::<BTreeSet<_>>();
11113
11114 let mut covered_worktrees = HashSet::default();
11115 for buffer in buffers {
11116 buffer.update(cx, |buffer, cx| {
11117 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11118 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11119 && covered_worktrees.insert(worktree_id)
11120 {
11121 language_server_names_to_stop.retain(|name| {
11122 let old_ids_count = language_servers_to_stop.len();
11123 let all_language_servers_with_this_name = local
11124 .language_server_ids
11125 .iter()
11126 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11127 language_servers_to_stop.extend(all_language_servers_with_this_name);
11128 old_ids_count == language_servers_to_stop.len()
11129 });
11130 }
11131 });
11132 }
11133 for name in language_server_names_to_stop {
11134 language_servers_to_stop.extend(
11135 local
11136 .language_server_ids
11137 .iter()
11138 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11139 );
11140 }
11141
11142 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11143 let tasks = language_servers_to_stop
11144 .into_iter()
11145 .map(|server| self.stop_local_language_server(server, cx))
11146 .collect::<Vec<_>>();
11147
11148 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11149 }
11150
11151 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11152 let (worktree, relative_path) =
11153 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11154
11155 let project_path = ProjectPath {
11156 worktree_id: worktree.read(cx).id(),
11157 path: relative_path,
11158 };
11159
11160 Some(
11161 self.buffer_store()
11162 .read(cx)
11163 .get_by_path(&project_path)?
11164 .read(cx),
11165 )
11166 }
11167
11168 #[cfg(any(test, feature = "test-support"))]
11169 pub fn update_diagnostics(
11170 &mut self,
11171 server_id: LanguageServerId,
11172 diagnostics: lsp::PublishDiagnosticsParams,
11173 result_id: Option<SharedString>,
11174 source_kind: DiagnosticSourceKind,
11175 disk_based_sources: &[String],
11176 cx: &mut Context<Self>,
11177 ) -> Result<()> {
11178 self.merge_lsp_diagnostics(
11179 source_kind,
11180 vec![DocumentDiagnosticsUpdate {
11181 diagnostics,
11182 result_id,
11183 server_id,
11184 disk_based_sources: Cow::Borrowed(disk_based_sources),
11185 registration_id: None,
11186 }],
11187 |_, _, _| false,
11188 cx,
11189 )
11190 }
11191
11192 pub fn merge_lsp_diagnostics(
11193 &mut self,
11194 source_kind: DiagnosticSourceKind,
11195 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11196 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11197 cx: &mut Context<Self>,
11198 ) -> Result<()> {
11199 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11200 let updates = lsp_diagnostics
11201 .into_iter()
11202 .filter_map(|update| {
11203 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11204 Some(DocumentDiagnosticsUpdate {
11205 diagnostics: self.lsp_to_document_diagnostics(
11206 abs_path,
11207 source_kind,
11208 update.server_id,
11209 update.diagnostics,
11210 &update.disk_based_sources,
11211 update.registration_id.clone(),
11212 ),
11213 result_id: update.result_id,
11214 server_id: update.server_id,
11215 disk_based_sources: update.disk_based_sources,
11216 registration_id: update.registration_id,
11217 })
11218 })
11219 .collect();
11220 self.merge_diagnostic_entries(updates, merge, cx)?;
11221 Ok(())
11222 }
11223
11224 fn lsp_to_document_diagnostics(
11225 &mut self,
11226 document_abs_path: PathBuf,
11227 source_kind: DiagnosticSourceKind,
11228 server_id: LanguageServerId,
11229 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11230 disk_based_sources: &[String],
11231 registration_id: Option<SharedString>,
11232 ) -> DocumentDiagnostics {
11233 let mut diagnostics = Vec::default();
11234 let mut primary_diagnostic_group_ids = HashMap::default();
11235 let mut sources_by_group_id = HashMap::default();
11236 let mut supporting_diagnostics = HashMap::default();
11237
11238 let adapter = self.language_server_adapter_for_id(server_id);
11239
11240 // Ensure that primary diagnostics are always the most severe
11241 lsp_diagnostics
11242 .diagnostics
11243 .sort_by_key(|item| item.severity);
11244
11245 for diagnostic in &lsp_diagnostics.diagnostics {
11246 let source = diagnostic.source.as_ref();
11247 let range = range_from_lsp(diagnostic.range);
11248 let is_supporting = diagnostic
11249 .related_information
11250 .as_ref()
11251 .is_some_and(|infos| {
11252 infos.iter().any(|info| {
11253 primary_diagnostic_group_ids.contains_key(&(
11254 source,
11255 diagnostic.code.clone(),
11256 range_from_lsp(info.location.range),
11257 ))
11258 })
11259 });
11260
11261 let is_unnecessary = diagnostic
11262 .tags
11263 .as_ref()
11264 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11265
11266 let underline = self
11267 .language_server_adapter_for_id(server_id)
11268 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11269
11270 if is_supporting {
11271 supporting_diagnostics.insert(
11272 (source, diagnostic.code.clone(), range),
11273 (diagnostic.severity, is_unnecessary),
11274 );
11275 } else {
11276 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11277 let is_disk_based =
11278 source.is_some_and(|source| disk_based_sources.contains(source));
11279
11280 sources_by_group_id.insert(group_id, source);
11281 primary_diagnostic_group_ids
11282 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11283
11284 diagnostics.push(DiagnosticEntry {
11285 range,
11286 diagnostic: Diagnostic {
11287 source: diagnostic.source.clone(),
11288 source_kind,
11289 code: diagnostic.code.clone(),
11290 code_description: diagnostic
11291 .code_description
11292 .as_ref()
11293 .and_then(|d| d.href.clone()),
11294 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11295 markdown: adapter.as_ref().and_then(|adapter| {
11296 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11297 }),
11298 message: diagnostic.message.trim().to_string(),
11299 group_id,
11300 is_primary: true,
11301 is_disk_based,
11302 is_unnecessary,
11303 underline,
11304 data: diagnostic.data.clone(),
11305 registration_id: registration_id.clone(),
11306 },
11307 });
11308 if let Some(infos) = &diagnostic.related_information {
11309 for info in infos {
11310 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11311 let range = range_from_lsp(info.location.range);
11312 diagnostics.push(DiagnosticEntry {
11313 range,
11314 diagnostic: Diagnostic {
11315 source: diagnostic.source.clone(),
11316 source_kind,
11317 code: diagnostic.code.clone(),
11318 code_description: diagnostic
11319 .code_description
11320 .as_ref()
11321 .and_then(|d| d.href.clone()),
11322 severity: DiagnosticSeverity::INFORMATION,
11323 markdown: adapter.as_ref().and_then(|adapter| {
11324 adapter.diagnostic_message_to_markdown(&info.message)
11325 }),
11326 message: info.message.trim().to_string(),
11327 group_id,
11328 is_primary: false,
11329 is_disk_based,
11330 is_unnecessary: false,
11331 underline,
11332 data: diagnostic.data.clone(),
11333 registration_id: registration_id.clone(),
11334 },
11335 });
11336 }
11337 }
11338 }
11339 }
11340 }
11341
11342 for entry in &mut diagnostics {
11343 let diagnostic = &mut entry.diagnostic;
11344 if !diagnostic.is_primary {
11345 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11346 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11347 source,
11348 diagnostic.code.clone(),
11349 entry.range.clone(),
11350 )) {
11351 if let Some(severity) = severity {
11352 diagnostic.severity = severity;
11353 }
11354 diagnostic.is_unnecessary = is_unnecessary;
11355 }
11356 }
11357 }
11358
11359 DocumentDiagnostics {
11360 diagnostics,
11361 document_abs_path,
11362 version: lsp_diagnostics.version,
11363 }
11364 }
11365
11366 fn insert_newly_running_language_server(
11367 &mut self,
11368 adapter: Arc<CachedLspAdapter>,
11369 language_server: Arc<LanguageServer>,
11370 server_id: LanguageServerId,
11371 key: LanguageServerSeed,
11372 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11373 cx: &mut Context<Self>,
11374 ) {
11375 let Some(local) = self.as_local_mut() else {
11376 return;
11377 };
11378 // If the language server for this key doesn't match the server id, don't store the
11379 // server. Which will cause it to be dropped, killing the process
11380 if local
11381 .language_server_ids
11382 .get(&key)
11383 .map(|state| state.id != server_id)
11384 .unwrap_or(false)
11385 {
11386 return;
11387 }
11388
11389 // Update language_servers collection with Running variant of LanguageServerState
11390 // indicating that the server is up and running and ready
11391 let workspace_folders = workspace_folders.lock().clone();
11392 language_server.set_workspace_folders(workspace_folders);
11393
11394 let workspace_diagnostics_refresh_tasks = language_server
11395 .capabilities()
11396 .diagnostic_provider
11397 .and_then(|provider| {
11398 local
11399 .language_server_dynamic_registrations
11400 .entry(server_id)
11401 .or_default()
11402 .diagnostics
11403 .entry(None)
11404 .or_insert(provider.clone());
11405 let workspace_refresher =
11406 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11407
11408 Some((None, workspace_refresher))
11409 })
11410 .into_iter()
11411 .collect();
11412 local.language_servers.insert(
11413 server_id,
11414 LanguageServerState::Running {
11415 workspace_diagnostics_refresh_tasks,
11416 adapter: adapter.clone(),
11417 server: language_server.clone(),
11418 simulate_disk_based_diagnostics_completion: None,
11419 },
11420 );
11421 local
11422 .languages
11423 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11424 if let Some(file_ops_caps) = language_server
11425 .capabilities()
11426 .workspace
11427 .as_ref()
11428 .and_then(|ws| ws.file_operations.as_ref())
11429 {
11430 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11431 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11432 if did_rename_caps.or(will_rename_caps).is_some() {
11433 let watcher = RenamePathsWatchedForServer::default()
11434 .with_did_rename_patterns(did_rename_caps)
11435 .with_will_rename_patterns(will_rename_caps);
11436 local
11437 .language_server_paths_watched_for_rename
11438 .insert(server_id, watcher);
11439 }
11440 }
11441
11442 self.language_server_statuses.insert(
11443 server_id,
11444 LanguageServerStatus {
11445 name: language_server.name(),
11446 server_version: language_server.version(),
11447 server_readable_version: language_server.readable_version(),
11448 pending_work: Default::default(),
11449 has_pending_diagnostic_updates: false,
11450 progress_tokens: Default::default(),
11451 worktree: Some(key.worktree_id),
11452 binary: Some(language_server.binary().clone()),
11453 configuration: Some(language_server.configuration().clone()),
11454 workspace_folders: language_server.workspace_folders(),
11455 process_id: language_server.process_id(),
11456 },
11457 );
11458
11459 cx.emit(LspStoreEvent::LanguageServerAdded(
11460 server_id,
11461 language_server.name(),
11462 Some(key.worktree_id),
11463 ));
11464
11465 let server_capabilities = language_server.capabilities();
11466 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11467 downstream_client
11468 .send(proto::StartLanguageServer {
11469 project_id: *project_id,
11470 server: Some(proto::LanguageServer {
11471 id: server_id.to_proto(),
11472 name: language_server.name().to_string(),
11473 worktree_id: Some(key.worktree_id.to_proto()),
11474 }),
11475 capabilities: serde_json::to_string(&server_capabilities)
11476 .expect("serializing server LSP capabilities"),
11477 })
11478 .log_err();
11479 }
11480 self.lsp_server_capabilities
11481 .insert(server_id, server_capabilities);
11482
11483 // Tell the language server about every open buffer in the worktree that matches the language.
11484 // Also check for buffers in worktrees that reused this server
11485 let mut worktrees_using_server = vec![key.worktree_id];
11486 if let Some(local) = self.as_local() {
11487 // Find all worktrees that have this server in their language server tree
11488 for (worktree_id, servers) in &local.lsp_tree.instances {
11489 if *worktree_id != key.worktree_id {
11490 for server_map in servers.roots.values() {
11491 if server_map
11492 .values()
11493 .any(|(node, _)| node.id() == Some(server_id))
11494 {
11495 worktrees_using_server.push(*worktree_id);
11496 }
11497 }
11498 }
11499 }
11500 }
11501
11502 let mut buffer_paths_registered = Vec::new();
11503 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11504 let mut lsp_adapters = HashMap::default();
11505 for buffer_handle in buffer_store.buffers() {
11506 let buffer = buffer_handle.read(cx);
11507 let file = match File::from_dyn(buffer.file()) {
11508 Some(file) => file,
11509 None => continue,
11510 };
11511 let language = match buffer.language() {
11512 Some(language) => language,
11513 None => continue,
11514 };
11515
11516 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11517 || !lsp_adapters
11518 .entry(language.name())
11519 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11520 .iter()
11521 .any(|a| a.name == key.name)
11522 {
11523 continue;
11524 }
11525 // didOpen
11526 let file = match file.as_local() {
11527 Some(file) => file,
11528 None => continue,
11529 };
11530
11531 let local = self.as_local_mut().unwrap();
11532
11533 let buffer_id = buffer.remote_id();
11534 if local.registered_buffers.contains_key(&buffer_id) {
11535 let abs_path = file.abs_path(cx);
11536 let uri = match lsp::Uri::from_file_path(&abs_path) {
11537 Ok(uri) => uri,
11538 Err(()) => {
11539 log::error!("failed to convert path to URI: {:?}", abs_path);
11540 continue;
11541 }
11542 };
11543
11544 let versions = local
11545 .buffer_snapshots
11546 .entry(buffer_id)
11547 .or_default()
11548 .entry(server_id)
11549 .and_modify(|_| {
11550 assert!(
11551 false,
11552 "There should not be an existing snapshot for a newly inserted buffer"
11553 )
11554 })
11555 .or_insert_with(|| {
11556 vec![LspBufferSnapshot {
11557 version: 0,
11558 snapshot: buffer.text_snapshot(),
11559 }]
11560 });
11561
11562 let snapshot = versions.last().unwrap();
11563 let version = snapshot.version;
11564 let initial_snapshot = &snapshot.snapshot;
11565 language_server.register_buffer(
11566 uri,
11567 adapter.language_id(&language.name()),
11568 version,
11569 initial_snapshot.text(),
11570 );
11571 buffer_paths_registered.push((buffer_id, abs_path));
11572 local
11573 .buffers_opened_in_servers
11574 .entry(buffer_id)
11575 .or_default()
11576 .insert(server_id);
11577 }
11578 buffer_handle.update(cx, |buffer, cx| {
11579 buffer.set_completion_triggers(
11580 server_id,
11581 language_server
11582 .capabilities()
11583 .completion_provider
11584 .as_ref()
11585 .and_then(|provider| {
11586 provider
11587 .trigger_characters
11588 .as_ref()
11589 .map(|characters| characters.iter().cloned().collect())
11590 })
11591 .unwrap_or_default(),
11592 cx,
11593 )
11594 });
11595 }
11596 });
11597
11598 for (buffer_id, abs_path) in buffer_paths_registered {
11599 cx.emit(LspStoreEvent::LanguageServerUpdate {
11600 language_server_id: server_id,
11601 name: Some(adapter.name()),
11602 message: proto::update_language_server::Variant::RegisteredForBuffer(
11603 proto::RegisteredForBuffer {
11604 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11605 buffer_id: buffer_id.to_proto(),
11606 },
11607 ),
11608 });
11609 }
11610
11611 cx.notify();
11612 }
11613
11614 pub fn language_servers_running_disk_based_diagnostics(
11615 &self,
11616 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11617 self.language_server_statuses
11618 .iter()
11619 .filter_map(|(id, status)| {
11620 if status.has_pending_diagnostic_updates {
11621 Some(*id)
11622 } else {
11623 None
11624 }
11625 })
11626 }
11627
11628 pub(crate) fn cancel_language_server_work_for_buffers(
11629 &mut self,
11630 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11631 cx: &mut Context<Self>,
11632 ) {
11633 if let Some((client, project_id)) = self.upstream_client() {
11634 let request = client.request(proto::CancelLanguageServerWork {
11635 project_id,
11636 work: Some(proto::cancel_language_server_work::Work::Buffers(
11637 proto::cancel_language_server_work::Buffers {
11638 buffer_ids: buffers
11639 .into_iter()
11640 .map(|b| b.read(cx).remote_id().to_proto())
11641 .collect(),
11642 },
11643 )),
11644 });
11645 cx.background_spawn(request).detach_and_log_err(cx);
11646 } else if let Some(local) = self.as_local() {
11647 let servers = buffers
11648 .into_iter()
11649 .flat_map(|buffer| {
11650 buffer.update(cx, |buffer, cx| {
11651 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11652 })
11653 })
11654 .collect::<HashSet<_>>();
11655 for server_id in servers {
11656 self.cancel_language_server_work(server_id, None, cx);
11657 }
11658 }
11659 }
11660
11661 pub(crate) fn cancel_language_server_work(
11662 &mut self,
11663 server_id: LanguageServerId,
11664 token_to_cancel: Option<ProgressToken>,
11665 cx: &mut Context<Self>,
11666 ) {
11667 if let Some(local) = self.as_local() {
11668 let status = self.language_server_statuses.get(&server_id);
11669 let server = local.language_servers.get(&server_id);
11670 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11671 {
11672 for (token, progress) in &status.pending_work {
11673 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11674 && token != token_to_cancel
11675 {
11676 continue;
11677 }
11678 if progress.is_cancellable {
11679 server
11680 .notify::<lsp::notification::WorkDoneProgressCancel>(
11681 WorkDoneProgressCancelParams {
11682 token: token.to_lsp(),
11683 },
11684 )
11685 .ok();
11686 }
11687 }
11688 }
11689 } else if let Some((client, project_id)) = self.upstream_client() {
11690 let request = client.request(proto::CancelLanguageServerWork {
11691 project_id,
11692 work: Some(
11693 proto::cancel_language_server_work::Work::LanguageServerWork(
11694 proto::cancel_language_server_work::LanguageServerWork {
11695 language_server_id: server_id.to_proto(),
11696 token: token_to_cancel.map(|token| token.to_proto()),
11697 },
11698 ),
11699 ),
11700 });
11701 cx.background_spawn(request).detach_and_log_err(cx);
11702 }
11703 }
11704
11705 fn register_supplementary_language_server(
11706 &mut self,
11707 id: LanguageServerId,
11708 name: LanguageServerName,
11709 server: Arc<LanguageServer>,
11710 cx: &mut Context<Self>,
11711 ) {
11712 if let Some(local) = self.as_local_mut() {
11713 local
11714 .supplementary_language_servers
11715 .insert(id, (name.clone(), server));
11716 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11717 }
11718 }
11719
11720 fn unregister_supplementary_language_server(
11721 &mut self,
11722 id: LanguageServerId,
11723 cx: &mut Context<Self>,
11724 ) {
11725 if let Some(local) = self.as_local_mut() {
11726 local.supplementary_language_servers.remove(&id);
11727 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11728 }
11729 }
11730
11731 pub(crate) fn supplementary_language_servers(
11732 &self,
11733 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11734 self.as_local().into_iter().flat_map(|local| {
11735 local
11736 .supplementary_language_servers
11737 .iter()
11738 .map(|(id, (name, _))| (*id, name.clone()))
11739 })
11740 }
11741
11742 pub fn language_server_adapter_for_id(
11743 &self,
11744 id: LanguageServerId,
11745 ) -> Option<Arc<CachedLspAdapter>> {
11746 self.as_local()
11747 .and_then(|local| local.language_servers.get(&id))
11748 .and_then(|language_server_state| match language_server_state {
11749 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11750 _ => None,
11751 })
11752 }
11753
11754 pub(super) fn update_local_worktree_language_servers(
11755 &mut self,
11756 worktree_handle: &Entity<Worktree>,
11757 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11758 cx: &mut Context<Self>,
11759 ) {
11760 if changes.is_empty() {
11761 return;
11762 }
11763
11764 let Some(local) = self.as_local() else { return };
11765
11766 local.prettier_store.update(cx, |prettier_store, cx| {
11767 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11768 });
11769
11770 let worktree_id = worktree_handle.read(cx).id();
11771 let mut language_server_ids = local
11772 .language_server_ids
11773 .iter()
11774 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11775 .collect::<Vec<_>>();
11776 language_server_ids.sort();
11777 language_server_ids.dedup();
11778
11779 // let abs_path = worktree_handle.read(cx).abs_path();
11780 for server_id in &language_server_ids {
11781 if let Some(LanguageServerState::Running { server, .. }) =
11782 local.language_servers.get(server_id)
11783 && let Some(watched_paths) = local
11784 .language_server_watched_paths
11785 .get(server_id)
11786 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11787 {
11788 let params = lsp::DidChangeWatchedFilesParams {
11789 changes: changes
11790 .iter()
11791 .filter_map(|(path, _, change)| {
11792 if !watched_paths.is_match(path.as_std_path()) {
11793 return None;
11794 }
11795 let typ = match change {
11796 PathChange::Loaded => return None,
11797 PathChange::Added => lsp::FileChangeType::CREATED,
11798 PathChange::Removed => lsp::FileChangeType::DELETED,
11799 PathChange::Updated => lsp::FileChangeType::CHANGED,
11800 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11801 };
11802 let uri = lsp::Uri::from_file_path(
11803 worktree_handle.read(cx).absolutize(&path),
11804 )
11805 .ok()?;
11806 Some(lsp::FileEvent { uri, typ })
11807 })
11808 .collect(),
11809 };
11810 if !params.changes.is_empty() {
11811 server
11812 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11813 .ok();
11814 }
11815 }
11816 }
11817 for (path, _, _) in changes {
11818 if let Some(file_name) = path.file_name()
11819 && local.watched_manifest_filenames.contains(file_name)
11820 {
11821 self.request_workspace_config_refresh();
11822 break;
11823 }
11824 }
11825 }
11826
11827 pub fn wait_for_remote_buffer(
11828 &mut self,
11829 id: BufferId,
11830 cx: &mut Context<Self>,
11831 ) -> Task<Result<Entity<Buffer>>> {
11832 self.buffer_store.update(cx, |buffer_store, cx| {
11833 buffer_store.wait_for_remote_buffer(id, cx)
11834 })
11835 }
11836
11837 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11838 let mut result = proto::Symbol {
11839 language_server_name: symbol.language_server_name.0.to_string(),
11840 source_worktree_id: symbol.source_worktree_id.to_proto(),
11841 language_server_id: symbol.source_language_server_id.to_proto(),
11842 name: symbol.name.clone(),
11843 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11844 start: Some(proto::PointUtf16 {
11845 row: symbol.range.start.0.row,
11846 column: symbol.range.start.0.column,
11847 }),
11848 end: Some(proto::PointUtf16 {
11849 row: symbol.range.end.0.row,
11850 column: symbol.range.end.0.column,
11851 }),
11852 worktree_id: Default::default(),
11853 path: Default::default(),
11854 signature: Default::default(),
11855 container_name: symbol.container_name.clone(),
11856 };
11857 match &symbol.path {
11858 SymbolLocation::InProject(path) => {
11859 result.worktree_id = path.worktree_id.to_proto();
11860 result.path = path.path.to_proto();
11861 }
11862 SymbolLocation::OutsideProject {
11863 abs_path,
11864 signature,
11865 } => {
11866 result.path = abs_path.to_string_lossy().into_owned();
11867 result.signature = signature.to_vec();
11868 }
11869 }
11870 result
11871 }
11872
11873 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11874 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11875 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11876 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11877
11878 let path = if serialized_symbol.signature.is_empty() {
11879 SymbolLocation::InProject(ProjectPath {
11880 worktree_id,
11881 path: RelPath::from_proto(&serialized_symbol.path)
11882 .context("invalid symbol path")?,
11883 })
11884 } else {
11885 SymbolLocation::OutsideProject {
11886 abs_path: Path::new(&serialized_symbol.path).into(),
11887 signature: serialized_symbol
11888 .signature
11889 .try_into()
11890 .map_err(|_| anyhow!("invalid signature"))?,
11891 }
11892 };
11893
11894 let start = serialized_symbol.start.context("invalid start")?;
11895 let end = serialized_symbol.end.context("invalid end")?;
11896 Ok(CoreSymbol {
11897 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11898 source_worktree_id,
11899 source_language_server_id: LanguageServerId::from_proto(
11900 serialized_symbol.language_server_id,
11901 ),
11902 path,
11903 name: serialized_symbol.name,
11904 range: Unclipped(PointUtf16::new(start.row, start.column))
11905 ..Unclipped(PointUtf16::new(end.row, end.column)),
11906 kind,
11907 container_name: serialized_symbol.container_name,
11908 })
11909 }
11910
11911 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11912 let mut serialized_completion = proto::Completion {
11913 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11914 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11915 new_text: completion.new_text.clone(),
11916 ..proto::Completion::default()
11917 };
11918 match &completion.source {
11919 CompletionSource::Lsp {
11920 insert_range,
11921 server_id,
11922 lsp_completion,
11923 lsp_defaults,
11924 resolved,
11925 } => {
11926 let (old_insert_start, old_insert_end) = insert_range
11927 .as_ref()
11928 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11929 .unzip();
11930
11931 serialized_completion.old_insert_start = old_insert_start;
11932 serialized_completion.old_insert_end = old_insert_end;
11933 serialized_completion.source = proto::completion::Source::Lsp as i32;
11934 serialized_completion.server_id = server_id.0 as u64;
11935 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11936 serialized_completion.lsp_defaults = lsp_defaults
11937 .as_deref()
11938 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11939 serialized_completion.resolved = *resolved;
11940 }
11941 CompletionSource::BufferWord {
11942 word_range,
11943 resolved,
11944 } => {
11945 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11946 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11947 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11948 serialized_completion.resolved = *resolved;
11949 }
11950 CompletionSource::Custom => {
11951 serialized_completion.source = proto::completion::Source::Custom as i32;
11952 serialized_completion.resolved = true;
11953 }
11954 CompletionSource::Dap { sort_text } => {
11955 serialized_completion.source = proto::completion::Source::Dap as i32;
11956 serialized_completion.sort_text = Some(sort_text.clone());
11957 }
11958 }
11959
11960 serialized_completion
11961 }
11962
11963 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11964 let old_replace_start = completion
11965 .old_replace_start
11966 .and_then(deserialize_anchor)
11967 .context("invalid old start")?;
11968 let old_replace_end = completion
11969 .old_replace_end
11970 .and_then(deserialize_anchor)
11971 .context("invalid old end")?;
11972 let insert_range = {
11973 match completion.old_insert_start.zip(completion.old_insert_end) {
11974 Some((start, end)) => {
11975 let start = deserialize_anchor(start).context("invalid insert old start")?;
11976 let end = deserialize_anchor(end).context("invalid insert old end")?;
11977 Some(start..end)
11978 }
11979 None => None,
11980 }
11981 };
11982 Ok(CoreCompletion {
11983 replace_range: old_replace_start..old_replace_end,
11984 new_text: completion.new_text,
11985 source: match proto::completion::Source::from_i32(completion.source) {
11986 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11987 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11988 insert_range,
11989 server_id: LanguageServerId::from_proto(completion.server_id),
11990 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11991 lsp_defaults: completion
11992 .lsp_defaults
11993 .as_deref()
11994 .map(serde_json::from_slice)
11995 .transpose()?,
11996 resolved: completion.resolved,
11997 },
11998 Some(proto::completion::Source::BufferWord) => {
11999 let word_range = completion
12000 .buffer_word_start
12001 .and_then(deserialize_anchor)
12002 .context("invalid buffer word start")?
12003 ..completion
12004 .buffer_word_end
12005 .and_then(deserialize_anchor)
12006 .context("invalid buffer word end")?;
12007 CompletionSource::BufferWord {
12008 word_range,
12009 resolved: completion.resolved,
12010 }
12011 }
12012 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12013 sort_text: completion
12014 .sort_text
12015 .context("expected sort text to exist")?,
12016 },
12017 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12018 },
12019 })
12020 }
12021
12022 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12023 let (kind, lsp_action) = match &action.lsp_action {
12024 LspAction::Action(code_action) => (
12025 proto::code_action::Kind::Action as i32,
12026 serde_json::to_vec(code_action).unwrap(),
12027 ),
12028 LspAction::Command(command) => (
12029 proto::code_action::Kind::Command as i32,
12030 serde_json::to_vec(command).unwrap(),
12031 ),
12032 LspAction::CodeLens(code_lens) => (
12033 proto::code_action::Kind::CodeLens as i32,
12034 serde_json::to_vec(code_lens).unwrap(),
12035 ),
12036 };
12037
12038 proto::CodeAction {
12039 server_id: action.server_id.0 as u64,
12040 start: Some(serialize_anchor(&action.range.start)),
12041 end: Some(serialize_anchor(&action.range.end)),
12042 lsp_action,
12043 kind,
12044 resolved: action.resolved,
12045 }
12046 }
12047
12048 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12049 let start = action
12050 .start
12051 .and_then(deserialize_anchor)
12052 .context("invalid start")?;
12053 let end = action
12054 .end
12055 .and_then(deserialize_anchor)
12056 .context("invalid end")?;
12057 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12058 Some(proto::code_action::Kind::Action) => {
12059 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12060 }
12061 Some(proto::code_action::Kind::Command) => {
12062 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12063 }
12064 Some(proto::code_action::Kind::CodeLens) => {
12065 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12066 }
12067 None => anyhow::bail!("Unknown action kind {}", action.kind),
12068 };
12069 Ok(CodeAction {
12070 server_id: LanguageServerId(action.server_id as usize),
12071 range: start..end,
12072 resolved: action.resolved,
12073 lsp_action,
12074 })
12075 }
12076
12077 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12078 match &formatting_result {
12079 Ok(_) => self.last_formatting_failure = None,
12080 Err(error) => {
12081 let error_string = format!("{error:#}");
12082 log::error!("Formatting failed: {error_string}");
12083 self.last_formatting_failure
12084 .replace(error_string.lines().join(" "));
12085 }
12086 }
12087 }
12088
12089 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12090 self.lsp_server_capabilities.remove(&for_server);
12091 self.semantic_token_config.remove_server_data(for_server);
12092 for lsp_data in self.lsp_data.values_mut() {
12093 lsp_data.remove_server_data(for_server);
12094 }
12095 if let Some(local) = self.as_local_mut() {
12096 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12097 local
12098 .workspace_pull_diagnostics_result_ids
12099 .remove(&for_server);
12100 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12101 buffer_servers.remove(&for_server);
12102 }
12103 }
12104 }
12105
12106 pub fn result_id_for_buffer_pull(
12107 &self,
12108 server_id: LanguageServerId,
12109 buffer_id: BufferId,
12110 registration_id: &Option<SharedString>,
12111 cx: &App,
12112 ) -> Option<SharedString> {
12113 let abs_path = self
12114 .buffer_store
12115 .read(cx)
12116 .get(buffer_id)
12117 .and_then(|b| File::from_dyn(b.read(cx).file()))
12118 .map(|f| f.abs_path(cx))?;
12119 self.as_local()?
12120 .buffer_pull_diagnostics_result_ids
12121 .get(&server_id)?
12122 .get(registration_id)?
12123 .get(&abs_path)?
12124 .clone()
12125 }
12126
12127 /// Gets all result_ids for a workspace diagnostics pull request.
12128 /// 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.
12129 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12130 pub fn result_ids_for_workspace_refresh(
12131 &self,
12132 server_id: LanguageServerId,
12133 registration_id: &Option<SharedString>,
12134 ) -> HashMap<PathBuf, SharedString> {
12135 let Some(local) = self.as_local() else {
12136 return HashMap::default();
12137 };
12138 local
12139 .workspace_pull_diagnostics_result_ids
12140 .get(&server_id)
12141 .into_iter()
12142 .filter_map(|diagnostics| diagnostics.get(registration_id))
12143 .flatten()
12144 .filter_map(|(abs_path, result_id)| {
12145 let result_id = local
12146 .buffer_pull_diagnostics_result_ids
12147 .get(&server_id)
12148 .and_then(|buffer_ids_result_ids| {
12149 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12150 })
12151 .cloned()
12152 .flatten()
12153 .or_else(|| result_id.clone())?;
12154 Some((abs_path.clone(), result_id))
12155 })
12156 .collect()
12157 }
12158
12159 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12160 if let Some(LanguageServerState::Running {
12161 workspace_diagnostics_refresh_tasks,
12162 ..
12163 }) = self
12164 .as_local_mut()
12165 .and_then(|local| local.language_servers.get_mut(&server_id))
12166 {
12167 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12168 diagnostics.refresh_tx.try_send(()).ok();
12169 }
12170 }
12171 }
12172
12173 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12174 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12175 /// which requires refreshing both workspace and document diagnostics.
12176 pub fn pull_document_diagnostics_for_server(
12177 &mut self,
12178 server_id: LanguageServerId,
12179 source_buffer_id: Option<BufferId>,
12180 cx: &mut Context<Self>,
12181 ) -> Shared<Task<()>> {
12182 let Some(local) = self.as_local_mut() else {
12183 return Task::ready(()).shared();
12184 };
12185 let mut buffers_to_refresh = HashSet::default();
12186 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12187 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12188 buffers_to_refresh.insert(*buffer_id);
12189 }
12190 }
12191
12192 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12193 }
12194
12195 pub fn pull_document_diagnostics_for_buffer_edit(
12196 &mut self,
12197 buffer_id: BufferId,
12198 cx: &mut Context<Self>,
12199 ) {
12200 let Some(local) = self.as_local_mut() else {
12201 return;
12202 };
12203 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12204 else {
12205 return;
12206 };
12207 for server_id in languages_servers {
12208 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12209 }
12210 }
12211
12212 fn apply_workspace_diagnostic_report(
12213 &mut self,
12214 server_id: LanguageServerId,
12215 report: lsp::WorkspaceDiagnosticReportResult,
12216 registration_id: Option<SharedString>,
12217 cx: &mut Context<Self>,
12218 ) {
12219 let mut workspace_diagnostics =
12220 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12221 report,
12222 server_id,
12223 registration_id,
12224 );
12225 workspace_diagnostics.retain(|d| match &d.diagnostics {
12226 LspPullDiagnostics::Response {
12227 server_id,
12228 registration_id,
12229 ..
12230 } => self.diagnostic_registration_exists(*server_id, registration_id),
12231 LspPullDiagnostics::Default => false,
12232 });
12233 let mut unchanged_buffers = HashMap::default();
12234 let workspace_diagnostics_updates = workspace_diagnostics
12235 .into_iter()
12236 .filter_map(
12237 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12238 LspPullDiagnostics::Response {
12239 server_id,
12240 uri,
12241 diagnostics,
12242 registration_id,
12243 } => Some((
12244 server_id,
12245 uri,
12246 diagnostics,
12247 workspace_diagnostics.version,
12248 registration_id,
12249 )),
12250 LspPullDiagnostics::Default => None,
12251 },
12252 )
12253 .fold(
12254 HashMap::default(),
12255 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12256 let (result_id, diagnostics) = match diagnostics {
12257 PulledDiagnostics::Unchanged { result_id } => {
12258 unchanged_buffers
12259 .entry(new_registration_id.clone())
12260 .or_insert_with(HashSet::default)
12261 .insert(uri.clone());
12262 (Some(result_id), Vec::new())
12263 }
12264 PulledDiagnostics::Changed {
12265 result_id,
12266 diagnostics,
12267 } => (result_id, diagnostics),
12268 };
12269 let disk_based_sources = Cow::Owned(
12270 self.language_server_adapter_for_id(server_id)
12271 .as_ref()
12272 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12273 .unwrap_or(&[])
12274 .to_vec(),
12275 );
12276
12277 let Some(abs_path) = uri.to_file_path().ok() else {
12278 return acc;
12279 };
12280 let Some((worktree, relative_path)) =
12281 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12282 else {
12283 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12284 return acc;
12285 };
12286 let worktree_id = worktree.read(cx).id();
12287 let project_path = ProjectPath {
12288 worktree_id,
12289 path: relative_path,
12290 };
12291 if let Some(local_lsp_store) = self.as_local_mut() {
12292 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12293 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12294 }
12295 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12296 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12297 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12298 acc.entry(server_id)
12299 .or_insert_with(HashMap::default)
12300 .entry(new_registration_id.clone())
12301 .or_insert_with(Vec::new)
12302 .push(DocumentDiagnosticsUpdate {
12303 server_id,
12304 diagnostics: lsp::PublishDiagnosticsParams {
12305 uri,
12306 diagnostics,
12307 version,
12308 },
12309 result_id: result_id.map(SharedString::new),
12310 disk_based_sources,
12311 registration_id: new_registration_id,
12312 });
12313 }
12314 acc
12315 },
12316 );
12317
12318 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12319 for (registration_id, diagnostic_updates) in diagnostic_updates {
12320 self.merge_lsp_diagnostics(
12321 DiagnosticSourceKind::Pulled,
12322 diagnostic_updates,
12323 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12324 DiagnosticSourceKind::Pulled => {
12325 old_diagnostic.registration_id != registration_id
12326 || unchanged_buffers
12327 .get(&old_diagnostic.registration_id)
12328 .is_some_and(|unchanged_buffers| {
12329 unchanged_buffers.contains(&document_uri)
12330 })
12331 }
12332 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12333 },
12334 cx,
12335 )
12336 .log_err();
12337 }
12338 }
12339 }
12340
12341 fn register_server_capabilities(
12342 &mut self,
12343 server_id: LanguageServerId,
12344 params: lsp::RegistrationParams,
12345 cx: &mut Context<Self>,
12346 ) -> anyhow::Result<()> {
12347 let server = self
12348 .language_server_for_id(server_id)
12349 .with_context(|| format!("no server {server_id} found"))?;
12350 for reg in params.registrations {
12351 match reg.method.as_str() {
12352 "workspace/didChangeWatchedFiles" => {
12353 if let Some(options) = reg.register_options {
12354 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12355 let caps = serde_json::from_value(options)?;
12356 local_lsp_store
12357 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12358 true
12359 } else {
12360 false
12361 };
12362 if notify {
12363 notify_server_capabilities_updated(&server, cx);
12364 }
12365 }
12366 }
12367 "workspace/didChangeConfiguration" => {
12368 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12369 }
12370 "workspace/didChangeWorkspaceFolders" => {
12371 // In this case register options is an empty object, we can ignore it
12372 let caps = lsp::WorkspaceFoldersServerCapabilities {
12373 supported: Some(true),
12374 change_notifications: Some(OneOf::Right(reg.id)),
12375 };
12376 server.update_capabilities(|capabilities| {
12377 capabilities
12378 .workspace
12379 .get_or_insert_default()
12380 .workspace_folders = Some(caps);
12381 });
12382 notify_server_capabilities_updated(&server, cx);
12383 }
12384 "workspace/symbol" => {
12385 let options = parse_register_capabilities(reg)?;
12386 server.update_capabilities(|capabilities| {
12387 capabilities.workspace_symbol_provider = Some(options);
12388 });
12389 notify_server_capabilities_updated(&server, cx);
12390 }
12391 "workspace/fileOperations" => {
12392 if let Some(options) = reg.register_options {
12393 let caps = serde_json::from_value(options)?;
12394 server.update_capabilities(|capabilities| {
12395 capabilities
12396 .workspace
12397 .get_or_insert_default()
12398 .file_operations = Some(caps);
12399 });
12400 notify_server_capabilities_updated(&server, cx);
12401 }
12402 }
12403 "workspace/executeCommand" => {
12404 if let Some(options) = reg.register_options {
12405 let options = serde_json::from_value(options)?;
12406 server.update_capabilities(|capabilities| {
12407 capabilities.execute_command_provider = Some(options);
12408 });
12409 notify_server_capabilities_updated(&server, cx);
12410 }
12411 }
12412 "textDocument/rangeFormatting" => {
12413 let options = parse_register_capabilities(reg)?;
12414 server.update_capabilities(|capabilities| {
12415 capabilities.document_range_formatting_provider = Some(options);
12416 });
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 "textDocument/onTypeFormatting" => {
12420 if let Some(options) = reg
12421 .register_options
12422 .map(serde_json::from_value)
12423 .transpose()?
12424 {
12425 server.update_capabilities(|capabilities| {
12426 capabilities.document_on_type_formatting_provider = Some(options);
12427 });
12428 notify_server_capabilities_updated(&server, cx);
12429 }
12430 }
12431 "textDocument/formatting" => {
12432 let options = parse_register_capabilities(reg)?;
12433 server.update_capabilities(|capabilities| {
12434 capabilities.document_formatting_provider = Some(options);
12435 });
12436 notify_server_capabilities_updated(&server, cx);
12437 }
12438 "textDocument/rename" => {
12439 let options = parse_register_capabilities(reg)?;
12440 server.update_capabilities(|capabilities| {
12441 capabilities.rename_provider = Some(options);
12442 });
12443 notify_server_capabilities_updated(&server, cx);
12444 }
12445 "textDocument/inlayHint" => {
12446 let options = parse_register_capabilities(reg)?;
12447 server.update_capabilities(|capabilities| {
12448 capabilities.inlay_hint_provider = Some(options);
12449 });
12450 notify_server_capabilities_updated(&server, cx);
12451 }
12452 "textDocument/documentSymbol" => {
12453 let options = parse_register_capabilities(reg)?;
12454 server.update_capabilities(|capabilities| {
12455 capabilities.document_symbol_provider = Some(options);
12456 });
12457 notify_server_capabilities_updated(&server, cx);
12458 }
12459 "textDocument/codeAction" => {
12460 let options = parse_register_capabilities(reg)?;
12461 let provider = match options {
12462 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12463 OneOf::Right(caps) => caps,
12464 };
12465 server.update_capabilities(|capabilities| {
12466 capabilities.code_action_provider = Some(provider);
12467 });
12468 notify_server_capabilities_updated(&server, cx);
12469 }
12470 "textDocument/definition" => {
12471 let options = parse_register_capabilities(reg)?;
12472 server.update_capabilities(|capabilities| {
12473 capabilities.definition_provider = Some(options);
12474 });
12475 notify_server_capabilities_updated(&server, cx);
12476 }
12477 "textDocument/completion" => {
12478 if let Some(caps) = reg
12479 .register_options
12480 .map(serde_json::from_value::<CompletionOptions>)
12481 .transpose()?
12482 {
12483 server.update_capabilities(|capabilities| {
12484 capabilities.completion_provider = Some(caps.clone());
12485 });
12486
12487 if let Some(local) = self.as_local() {
12488 let mut buffers_with_language_server = Vec::new();
12489 for handle in self.buffer_store.read(cx).buffers() {
12490 let buffer_id = handle.read(cx).remote_id();
12491 if local
12492 .buffers_opened_in_servers
12493 .get(&buffer_id)
12494 .filter(|s| s.contains(&server_id))
12495 .is_some()
12496 {
12497 buffers_with_language_server.push(handle);
12498 }
12499 }
12500 let triggers = caps
12501 .trigger_characters
12502 .unwrap_or_default()
12503 .into_iter()
12504 .collect::<BTreeSet<_>>();
12505 for handle in buffers_with_language_server {
12506 let triggers = triggers.clone();
12507 let _ = handle.update(cx, move |buffer, cx| {
12508 buffer.set_completion_triggers(server_id, triggers, cx);
12509 });
12510 }
12511 }
12512 notify_server_capabilities_updated(&server, cx);
12513 }
12514 }
12515 "textDocument/hover" => {
12516 let options = parse_register_capabilities(reg)?;
12517 let provider = match options {
12518 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12519 OneOf::Right(caps) => caps,
12520 };
12521 server.update_capabilities(|capabilities| {
12522 capabilities.hover_provider = Some(provider);
12523 });
12524 notify_server_capabilities_updated(&server, cx);
12525 }
12526 "textDocument/signatureHelp" => {
12527 if let Some(caps) = reg
12528 .register_options
12529 .map(serde_json::from_value)
12530 .transpose()?
12531 {
12532 server.update_capabilities(|capabilities| {
12533 capabilities.signature_help_provider = Some(caps);
12534 });
12535 notify_server_capabilities_updated(&server, cx);
12536 }
12537 }
12538 "textDocument/didChange" => {
12539 if let Some(sync_kind) = reg
12540 .register_options
12541 .and_then(|opts| opts.get("syncKind").cloned())
12542 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12543 .transpose()?
12544 {
12545 server.update_capabilities(|capabilities| {
12546 let mut sync_options =
12547 Self::take_text_document_sync_options(capabilities);
12548 sync_options.change = Some(sync_kind);
12549 capabilities.text_document_sync =
12550 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12551 });
12552 notify_server_capabilities_updated(&server, cx);
12553 }
12554 }
12555 "textDocument/didSave" => {
12556 if let Some(include_text) = reg
12557 .register_options
12558 .map(|opts| {
12559 let transpose = opts
12560 .get("includeText")
12561 .cloned()
12562 .map(serde_json::from_value::<Option<bool>>)
12563 .transpose();
12564 match transpose {
12565 Ok(value) => Ok(value.flatten()),
12566 Err(e) => Err(e),
12567 }
12568 })
12569 .transpose()?
12570 {
12571 server.update_capabilities(|capabilities| {
12572 let mut sync_options =
12573 Self::take_text_document_sync_options(capabilities);
12574 sync_options.save =
12575 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12576 include_text,
12577 }));
12578 capabilities.text_document_sync =
12579 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12580 });
12581 notify_server_capabilities_updated(&server, cx);
12582 }
12583 }
12584 "textDocument/codeLens" => {
12585 if let Some(caps) = reg
12586 .register_options
12587 .map(serde_json::from_value)
12588 .transpose()?
12589 {
12590 server.update_capabilities(|capabilities| {
12591 capabilities.code_lens_provider = Some(caps);
12592 });
12593 notify_server_capabilities_updated(&server, cx);
12594 }
12595 }
12596 "textDocument/diagnostic" => {
12597 if let Some(caps) = reg
12598 .register_options
12599 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12600 .transpose()?
12601 {
12602 let local = self
12603 .as_local_mut()
12604 .context("Expected LSP Store to be local")?;
12605 let state = local
12606 .language_servers
12607 .get_mut(&server_id)
12608 .context("Could not obtain Language Servers state")?;
12609 local
12610 .language_server_dynamic_registrations
12611 .entry(server_id)
12612 .or_default()
12613 .diagnostics
12614 .insert(Some(reg.id.clone()), caps.clone());
12615
12616 let supports_workspace_diagnostics =
12617 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12618 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12619 diagnostic_options.workspace_diagnostics
12620 }
12621 DiagnosticServerCapabilities::RegistrationOptions(
12622 diagnostic_registration_options,
12623 ) => {
12624 diagnostic_registration_options
12625 .diagnostic_options
12626 .workspace_diagnostics
12627 }
12628 };
12629
12630 if supports_workspace_diagnostics(&caps) {
12631 if let LanguageServerState::Running {
12632 workspace_diagnostics_refresh_tasks,
12633 ..
12634 } = state
12635 && let Some(task) = lsp_workspace_diagnostics_refresh(
12636 Some(reg.id.clone()),
12637 caps.clone(),
12638 server.clone(),
12639 cx,
12640 )
12641 {
12642 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12643 }
12644 }
12645
12646 server.update_capabilities(|capabilities| {
12647 capabilities.diagnostic_provider = Some(caps);
12648 });
12649
12650 notify_server_capabilities_updated(&server, cx);
12651
12652 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12653 }
12654 }
12655 "textDocument/documentColor" => {
12656 let options = parse_register_capabilities(reg)?;
12657 let provider = match options {
12658 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12659 OneOf::Right(caps) => caps,
12660 };
12661 server.update_capabilities(|capabilities| {
12662 capabilities.color_provider = Some(provider);
12663 });
12664 notify_server_capabilities_updated(&server, cx);
12665 }
12666 "textDocument/foldingRange" => {
12667 let options = parse_register_capabilities(reg)?;
12668 let provider = match options {
12669 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12670 OneOf::Right(caps) => caps,
12671 };
12672 server.update_capabilities(|capabilities| {
12673 capabilities.folding_range_provider = Some(provider);
12674 });
12675 notify_server_capabilities_updated(&server, cx);
12676 }
12677 _ => log::warn!("unhandled capability registration: {reg:?}"),
12678 }
12679 }
12680
12681 Ok(())
12682 }
12683
12684 fn unregister_server_capabilities(
12685 &mut self,
12686 server_id: LanguageServerId,
12687 params: lsp::UnregistrationParams,
12688 cx: &mut Context<Self>,
12689 ) -> anyhow::Result<()> {
12690 let server = self
12691 .language_server_for_id(server_id)
12692 .with_context(|| format!("no server {server_id} found"))?;
12693 for unreg in params.unregisterations.iter() {
12694 match unreg.method.as_str() {
12695 "workspace/didChangeWatchedFiles" => {
12696 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12697 local_lsp_store
12698 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12699 true
12700 } else {
12701 false
12702 };
12703 if notify {
12704 notify_server_capabilities_updated(&server, cx);
12705 }
12706 }
12707 "workspace/didChangeConfiguration" => {
12708 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12709 }
12710 "workspace/didChangeWorkspaceFolders" => {
12711 server.update_capabilities(|capabilities| {
12712 capabilities
12713 .workspace
12714 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12715 workspace_folders: None,
12716 file_operations: None,
12717 })
12718 .workspace_folders = None;
12719 });
12720 notify_server_capabilities_updated(&server, cx);
12721 }
12722 "workspace/symbol" => {
12723 server.update_capabilities(|capabilities| {
12724 capabilities.workspace_symbol_provider = None
12725 });
12726 notify_server_capabilities_updated(&server, cx);
12727 }
12728 "workspace/fileOperations" => {
12729 server.update_capabilities(|capabilities| {
12730 capabilities
12731 .workspace
12732 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12733 workspace_folders: None,
12734 file_operations: None,
12735 })
12736 .file_operations = None;
12737 });
12738 notify_server_capabilities_updated(&server, cx);
12739 }
12740 "workspace/executeCommand" => {
12741 server.update_capabilities(|capabilities| {
12742 capabilities.execute_command_provider = None;
12743 });
12744 notify_server_capabilities_updated(&server, cx);
12745 }
12746 "textDocument/rangeFormatting" => {
12747 server.update_capabilities(|capabilities| {
12748 capabilities.document_range_formatting_provider = None
12749 });
12750 notify_server_capabilities_updated(&server, cx);
12751 }
12752 "textDocument/onTypeFormatting" => {
12753 server.update_capabilities(|capabilities| {
12754 capabilities.document_on_type_formatting_provider = None;
12755 });
12756 notify_server_capabilities_updated(&server, cx);
12757 }
12758 "textDocument/formatting" => {
12759 server.update_capabilities(|capabilities| {
12760 capabilities.document_formatting_provider = None;
12761 });
12762 notify_server_capabilities_updated(&server, cx);
12763 }
12764 "textDocument/rename" => {
12765 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12766 notify_server_capabilities_updated(&server, cx);
12767 }
12768 "textDocument/codeAction" => {
12769 server.update_capabilities(|capabilities| {
12770 capabilities.code_action_provider = None;
12771 });
12772 notify_server_capabilities_updated(&server, cx);
12773 }
12774 "textDocument/definition" => {
12775 server.update_capabilities(|capabilities| {
12776 capabilities.definition_provider = None;
12777 });
12778 notify_server_capabilities_updated(&server, cx);
12779 }
12780 "textDocument/completion" => {
12781 server.update_capabilities(|capabilities| {
12782 capabilities.completion_provider = None;
12783 });
12784 notify_server_capabilities_updated(&server, cx);
12785 }
12786 "textDocument/hover" => {
12787 server.update_capabilities(|capabilities| {
12788 capabilities.hover_provider = None;
12789 });
12790 notify_server_capabilities_updated(&server, cx);
12791 }
12792 "textDocument/signatureHelp" => {
12793 server.update_capabilities(|capabilities| {
12794 capabilities.signature_help_provider = None;
12795 });
12796 notify_server_capabilities_updated(&server, cx);
12797 }
12798 "textDocument/didChange" => {
12799 server.update_capabilities(|capabilities| {
12800 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12801 sync_options.change = None;
12802 capabilities.text_document_sync =
12803 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12804 });
12805 notify_server_capabilities_updated(&server, cx);
12806 }
12807 "textDocument/didSave" => {
12808 server.update_capabilities(|capabilities| {
12809 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12810 sync_options.save = None;
12811 capabilities.text_document_sync =
12812 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12813 });
12814 notify_server_capabilities_updated(&server, cx);
12815 }
12816 "textDocument/codeLens" => {
12817 server.update_capabilities(|capabilities| {
12818 capabilities.code_lens_provider = None;
12819 });
12820 notify_server_capabilities_updated(&server, cx);
12821 }
12822 "textDocument/diagnostic" => {
12823 let local = self
12824 .as_local_mut()
12825 .context("Expected LSP Store to be local")?;
12826
12827 let state = local
12828 .language_servers
12829 .get_mut(&server_id)
12830 .context("Could not obtain Language Servers state")?;
12831 let registrations = local
12832 .language_server_dynamic_registrations
12833 .get_mut(&server_id)
12834 .with_context(|| {
12835 format!("Expected dynamic registration to exist for server {server_id}")
12836 })?;
12837 registrations.diagnostics
12838 .remove(&Some(unreg.id.clone()))
12839 .with_context(|| format!(
12840 "Attempted to unregister non-existent diagnostic registration with ID {}",
12841 unreg.id)
12842 )?;
12843 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12844
12845 if let LanguageServerState::Running {
12846 workspace_diagnostics_refresh_tasks,
12847 ..
12848 } = state
12849 {
12850 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12851 }
12852
12853 self.clear_unregistered_diagnostics(
12854 server_id,
12855 SharedString::from(unreg.id.clone()),
12856 cx,
12857 )?;
12858
12859 if removed_last_diagnostic_provider {
12860 server.update_capabilities(|capabilities| {
12861 debug_assert!(capabilities.diagnostic_provider.is_some());
12862 capabilities.diagnostic_provider = None;
12863 });
12864 }
12865
12866 notify_server_capabilities_updated(&server, cx);
12867 }
12868 "textDocument/documentColor" => {
12869 server.update_capabilities(|capabilities| {
12870 capabilities.color_provider = None;
12871 });
12872 notify_server_capabilities_updated(&server, cx);
12873 }
12874 "textDocument/foldingRange" => {
12875 server.update_capabilities(|capabilities| {
12876 capabilities.folding_range_provider = None;
12877 });
12878 notify_server_capabilities_updated(&server, cx);
12879 }
12880 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12881 }
12882 }
12883
12884 Ok(())
12885 }
12886
12887 fn clear_unregistered_diagnostics(
12888 &mut self,
12889 server_id: LanguageServerId,
12890 cleared_registration_id: SharedString,
12891 cx: &mut Context<Self>,
12892 ) -> anyhow::Result<()> {
12893 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12894
12895 self.buffer_store.update(cx, |buffer_store, cx| {
12896 for buffer_handle in buffer_store.buffers() {
12897 let buffer = buffer_handle.read(cx);
12898 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12899 let Some(abs_path) = abs_path else {
12900 continue;
12901 };
12902 affected_abs_paths.insert(abs_path);
12903 }
12904 });
12905
12906 let local = self.as_local().context("Expected LSP Store to be local")?;
12907 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12908 let Some(worktree) = self
12909 .worktree_store
12910 .read(cx)
12911 .worktree_for_id(*worktree_id, cx)
12912 else {
12913 continue;
12914 };
12915
12916 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12917 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12918 let has_matching_registration =
12919 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12920 entry.diagnostic.registration_id.as_ref()
12921 == Some(&cleared_registration_id)
12922 });
12923 if has_matching_registration {
12924 let abs_path = worktree.read(cx).absolutize(rel_path);
12925 affected_abs_paths.insert(abs_path);
12926 }
12927 }
12928 }
12929 }
12930
12931 if affected_abs_paths.is_empty() {
12932 return Ok(());
12933 }
12934
12935 // Send a fake diagnostic update which clears the state for the registration ID
12936 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12937 affected_abs_paths
12938 .into_iter()
12939 .map(|abs_path| DocumentDiagnosticsUpdate {
12940 diagnostics: DocumentDiagnostics {
12941 diagnostics: Vec::new(),
12942 document_abs_path: abs_path,
12943 version: None,
12944 },
12945 result_id: None,
12946 registration_id: Some(cleared_registration_id.clone()),
12947 server_id,
12948 disk_based_sources: Cow::Borrowed(&[]),
12949 })
12950 .collect();
12951
12952 let merge_registration_id = cleared_registration_id.clone();
12953 self.merge_diagnostic_entries(
12954 clears,
12955 move |_, diagnostic, _| {
12956 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12957 diagnostic.registration_id != Some(merge_registration_id.clone())
12958 } else {
12959 true
12960 }
12961 },
12962 cx,
12963 )?;
12964
12965 Ok(())
12966 }
12967
12968 async fn deduplicate_range_based_lsp_requests<T>(
12969 lsp_store: &Entity<Self>,
12970 server_id: Option<LanguageServerId>,
12971 lsp_request_id: LspRequestId,
12972 proto_request: &T::ProtoRequest,
12973 range: Range<Anchor>,
12974 cx: &mut AsyncApp,
12975 ) -> Result<()>
12976 where
12977 T: LspCommand,
12978 T::ProtoRequest: proto::LspRequestMessage,
12979 {
12980 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12981 let version = deserialize_version(proto_request.buffer_version());
12982 let buffer = lsp_store.update(cx, |this, cx| {
12983 this.buffer_store.read(cx).get_existing(buffer_id)
12984 })?;
12985 buffer
12986 .update(cx, |buffer, _| buffer.wait_for_version(version))
12987 .await?;
12988 lsp_store.update(cx, |lsp_store, cx| {
12989 let buffer_snapshot = buffer.read(cx).snapshot();
12990 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12991 let chunks_queried_for = lsp_data
12992 .inlay_hints
12993 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12994 .collect::<Vec<_>>();
12995 match chunks_queried_for.as_slice() {
12996 &[chunk] => {
12997 let key = LspKey {
12998 request_type: TypeId::of::<T>(),
12999 server_queried: server_id,
13000 };
13001 let previous_request = lsp_data
13002 .chunk_lsp_requests
13003 .entry(key)
13004 .or_default()
13005 .insert(chunk, lsp_request_id);
13006 if let Some((previous_request, running_requests)) =
13007 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13008 {
13009 running_requests.remove(&previous_request);
13010 }
13011 }
13012 _ambiguous_chunks => {
13013 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13014 // there, a buffer version-based check will be performed and outdated requests discarded.
13015 }
13016 }
13017 anyhow::Ok(())
13018 })?;
13019
13020 Ok(())
13021 }
13022
13023 async fn query_lsp_locally<T>(
13024 lsp_store: Entity<Self>,
13025 for_server_id: Option<LanguageServerId>,
13026 sender_id: proto::PeerId,
13027 lsp_request_id: LspRequestId,
13028 proto_request: T::ProtoRequest,
13029 position: Option<Anchor>,
13030 cx: &mut AsyncApp,
13031 ) -> Result<()>
13032 where
13033 T: LspCommand + Clone,
13034 T::ProtoRequest: proto::LspRequestMessage,
13035 <T::ProtoRequest as proto::RequestMessage>::Response:
13036 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13037 {
13038 let (buffer_version, buffer) =
13039 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13040 let request =
13041 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13042 let key = LspKey {
13043 request_type: TypeId::of::<T>(),
13044 server_queried: for_server_id,
13045 };
13046 lsp_store.update(cx, |lsp_store, cx| {
13047 let request_task = match for_server_id {
13048 Some(server_id) => {
13049 let server_task = lsp_store.request_lsp(
13050 buffer.clone(),
13051 LanguageServerToQuery::Other(server_id),
13052 request.clone(),
13053 cx,
13054 );
13055 cx.background_spawn(async move {
13056 let mut responses = Vec::new();
13057 match server_task.await {
13058 Ok(response) => responses.push((server_id, response)),
13059 // rust-analyzer likes to error with this when its still loading up
13060 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13061 Err(e) => log::error!(
13062 "Error handling response for request {request:?}: {e:#}"
13063 ),
13064 }
13065 responses
13066 })
13067 }
13068 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13069 };
13070 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13071 if T::ProtoRequest::stop_previous_requests() {
13072 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13073 lsp_requests.clear();
13074 }
13075 }
13076 lsp_data.lsp_requests.entry(key).or_default().insert(
13077 lsp_request_id,
13078 cx.spawn(async move |lsp_store, cx| {
13079 let response = request_task.await;
13080 lsp_store
13081 .update(cx, |lsp_store, cx| {
13082 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13083 {
13084 let response = response
13085 .into_iter()
13086 .map(|(server_id, response)| {
13087 (
13088 server_id.to_proto(),
13089 T::response_to_proto(
13090 response,
13091 lsp_store,
13092 sender_id,
13093 &buffer_version,
13094 cx,
13095 )
13096 .into(),
13097 )
13098 })
13099 .collect::<HashMap<_, _>>();
13100 match client.send_lsp_response::<T::ProtoRequest>(
13101 project_id,
13102 lsp_request_id,
13103 response,
13104 ) {
13105 Ok(()) => {}
13106 Err(e) => {
13107 log::error!("Failed to send LSP response: {e:#}",)
13108 }
13109 }
13110 }
13111 })
13112 .ok();
13113 }),
13114 );
13115 });
13116 Ok(())
13117 }
13118
13119 async fn wait_for_buffer_version<T>(
13120 lsp_store: &Entity<Self>,
13121 proto_request: &T::ProtoRequest,
13122 cx: &mut AsyncApp,
13123 ) -> Result<(Global, Entity<Buffer>)>
13124 where
13125 T: LspCommand,
13126 T::ProtoRequest: proto::LspRequestMessage,
13127 {
13128 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13129 let version = deserialize_version(proto_request.buffer_version());
13130 let buffer = lsp_store.update(cx, |this, cx| {
13131 this.buffer_store.read(cx).get_existing(buffer_id)
13132 })?;
13133 buffer
13134 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13135 .await?;
13136 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13137 Ok((buffer_version, buffer))
13138 }
13139
13140 fn take_text_document_sync_options(
13141 capabilities: &mut lsp::ServerCapabilities,
13142 ) -> lsp::TextDocumentSyncOptions {
13143 match capabilities.text_document_sync.take() {
13144 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13145 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13146 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13147 sync_options.change = Some(sync_kind);
13148 sync_options
13149 }
13150 None => lsp::TextDocumentSyncOptions::default(),
13151 }
13152 }
13153
13154 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13155 self.downstream_client.clone()
13156 }
13157
13158 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13159 self.worktree_store.clone()
13160 }
13161
13162 /// Gets what's stored in the LSP data for the given buffer.
13163 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13164 self.lsp_data.get_mut(&buffer_id)
13165 }
13166
13167 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13168 /// new [`BufferLspData`] will be created to replace the previous state.
13169 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13170 let (buffer_id, buffer_version) =
13171 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13172 let lsp_data = self
13173 .lsp_data
13174 .entry(buffer_id)
13175 .or_insert_with(|| BufferLspData::new(buffer, cx));
13176 if buffer_version.changed_since(&lsp_data.buffer_version) {
13177 // To send delta requests for semantic tokens, the previous tokens
13178 // need to be kept between buffer changes.
13179 let semantic_tokens = lsp_data.semantic_tokens.take();
13180 *lsp_data = BufferLspData::new(buffer, cx);
13181 lsp_data.semantic_tokens = semantic_tokens;
13182 }
13183 lsp_data
13184 }
13185}
13186
13187// Registration with registerOptions as null, should fallback to true.
13188// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13189fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13190 reg: lsp::Registration,
13191) -> Result<OneOf<bool, T>> {
13192 Ok(match reg.register_options {
13193 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13194 None => OneOf::Left(true),
13195 })
13196}
13197
13198fn subscribe_to_binary_statuses(
13199 languages: &Arc<LanguageRegistry>,
13200 cx: &mut Context<'_, LspStore>,
13201) -> Task<()> {
13202 let mut server_statuses = languages.language_server_binary_statuses();
13203 cx.spawn(async move |lsp_store, cx| {
13204 while let Some((server_name, binary_status)) = server_statuses.next().await {
13205 if lsp_store
13206 .update(cx, |_, cx| {
13207 let mut message = None;
13208 let binary_status = match binary_status {
13209 BinaryStatus::None => proto::ServerBinaryStatus::None,
13210 BinaryStatus::CheckingForUpdate => {
13211 proto::ServerBinaryStatus::CheckingForUpdate
13212 }
13213 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13214 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13215 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13216 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13217 BinaryStatus::Failed { error } => {
13218 message = Some(error);
13219 proto::ServerBinaryStatus::Failed
13220 }
13221 };
13222 cx.emit(LspStoreEvent::LanguageServerUpdate {
13223 // Binary updates are about the binary that might not have any language server id at that point.
13224 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13225 language_server_id: LanguageServerId(0),
13226 name: Some(server_name),
13227 message: proto::update_language_server::Variant::StatusUpdate(
13228 proto::StatusUpdate {
13229 message,
13230 status: Some(proto::status_update::Status::Binary(
13231 binary_status as i32,
13232 )),
13233 },
13234 ),
13235 });
13236 })
13237 .is_err()
13238 {
13239 break;
13240 }
13241 }
13242 })
13243}
13244
13245fn lsp_workspace_diagnostics_refresh(
13246 registration_id: Option<String>,
13247 options: DiagnosticServerCapabilities,
13248 server: Arc<LanguageServer>,
13249 cx: &mut Context<'_, LspStore>,
13250) -> Option<WorkspaceRefreshTask> {
13251 let identifier = workspace_diagnostic_identifier(&options)?;
13252 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13253
13254 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13255 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13256 refresh_tx.try_send(()).ok();
13257
13258 let request_timeout = ProjectSettings::get_global(cx)
13259 .global_lsp_settings
13260 .get_request_timeout();
13261
13262 // 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.
13263 // This allows users to increase the duration if need be
13264 let timeout = if request_timeout != Duration::ZERO {
13265 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13266 } else {
13267 request_timeout
13268 };
13269
13270 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13271 let mut attempts = 0;
13272 let max_attempts = 50;
13273 let mut requests = 0;
13274
13275 loop {
13276 let Some(()) = refresh_rx.recv().await else {
13277 return;
13278 };
13279
13280 'request: loop {
13281 requests += 1;
13282 if attempts > max_attempts {
13283 log::error!(
13284 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13285 );
13286 return;
13287 }
13288 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13289 cx.background_executor()
13290 .timer(Duration::from_millis(backoff_millis))
13291 .await;
13292 attempts += 1;
13293
13294 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13295 lsp_store
13296 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13297 .into_iter()
13298 .filter_map(|(abs_path, result_id)| {
13299 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13300 Some(lsp::PreviousResultId {
13301 uri,
13302 value: result_id.to_string(),
13303 })
13304 })
13305 .collect()
13306 }) else {
13307 return;
13308 };
13309
13310 let token = if let Some(registration_id) = ®istration_id {
13311 format!(
13312 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13313 server.server_id(),
13314 )
13315 } else {
13316 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13317 };
13318
13319 progress_rx.try_recv().ok();
13320 let timer = server.request_timer(timeout).fuse();
13321 let progress = pin!(progress_rx.recv().fuse());
13322 let response_result = server
13323 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13324 lsp::WorkspaceDiagnosticParams {
13325 previous_result_ids,
13326 identifier: identifier.clone(),
13327 work_done_progress_params: Default::default(),
13328 partial_result_params: lsp::PartialResultParams {
13329 partial_result_token: Some(lsp::ProgressToken::String(token)),
13330 },
13331 },
13332 select(timer, progress).then(|either| match either {
13333 Either::Left((message, ..)) => ready(message).left_future(),
13334 Either::Right(..) => pending::<String>().right_future(),
13335 }),
13336 )
13337 .await;
13338
13339 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13340 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13341 match response_result {
13342 ConnectionResult::Timeout => {
13343 log::error!("Timeout during workspace diagnostics pull");
13344 continue 'request;
13345 }
13346 ConnectionResult::ConnectionReset => {
13347 log::error!("Server closed a workspace diagnostics pull request");
13348 continue 'request;
13349 }
13350 ConnectionResult::Result(Err(e)) => {
13351 log::error!("Error during workspace diagnostics pull: {e:#}");
13352 break 'request;
13353 }
13354 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13355 attempts = 0;
13356 if lsp_store
13357 .update(cx, |lsp_store, cx| {
13358 lsp_store.apply_workspace_diagnostic_report(
13359 server.server_id(),
13360 pulled_diagnostics,
13361 registration_id_shared.clone(),
13362 cx,
13363 )
13364 })
13365 .is_err()
13366 {
13367 return;
13368 }
13369 break 'request;
13370 }
13371 }
13372 }
13373 }
13374 });
13375
13376 Some(WorkspaceRefreshTask {
13377 refresh_tx,
13378 progress_tx,
13379 task: workspace_query_language_server,
13380 })
13381}
13382
13383fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13384 match &options {
13385 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13386 .identifier
13387 .as_deref()
13388 .map(SharedString::new),
13389 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13390 let diagnostic_options = ®istration_options.diagnostic_options;
13391 diagnostic_options
13392 .identifier
13393 .as_deref()
13394 .map(SharedString::new)
13395 }
13396 }
13397}
13398
13399fn workspace_diagnostic_identifier(
13400 options: &DiagnosticServerCapabilities,
13401) -> Option<Option<String>> {
13402 match &options {
13403 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13404 if !diagnostic_options.workspace_diagnostics {
13405 return None;
13406 }
13407 Some(diagnostic_options.identifier.clone())
13408 }
13409 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13410 let diagnostic_options = ®istration_options.diagnostic_options;
13411 if !diagnostic_options.workspace_diagnostics {
13412 return None;
13413 }
13414 Some(diagnostic_options.identifier.clone())
13415 }
13416 }
13417}
13418
13419fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13420 let CompletionSource::BufferWord {
13421 word_range,
13422 resolved,
13423 } = &mut completion.source
13424 else {
13425 return;
13426 };
13427 if *resolved {
13428 return;
13429 }
13430
13431 if completion.new_text
13432 != snapshot
13433 .text_for_range(word_range.clone())
13434 .collect::<String>()
13435 {
13436 return;
13437 }
13438
13439 let mut offset = 0;
13440 for chunk in snapshot.chunks(word_range.clone(), true) {
13441 let end_offset = offset + chunk.text.len();
13442 if let Some(highlight_id) = chunk.syntax_highlight_id {
13443 completion
13444 .label
13445 .runs
13446 .push((offset..end_offset, highlight_id));
13447 }
13448 offset = end_offset;
13449 }
13450 *resolved = true;
13451}
13452
13453impl EventEmitter<LspStoreEvent> for LspStore {}
13454
13455fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13456 hover
13457 .contents
13458 .retain(|hover_block| !hover_block.text.trim().is_empty());
13459 if hover.contents.is_empty() {
13460 None
13461 } else {
13462 Some(hover)
13463 }
13464}
13465
13466async fn populate_labels_for_completions(
13467 new_completions: Vec<CoreCompletion>,
13468 language: Option<Arc<Language>>,
13469 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13470) -> Vec<Completion> {
13471 let lsp_completions = new_completions
13472 .iter()
13473 .filter_map(|new_completion| {
13474 new_completion
13475 .source
13476 .lsp_completion(true)
13477 .map(|lsp_completion| lsp_completion.into_owned())
13478 })
13479 .collect::<Vec<_>>();
13480
13481 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13482 lsp_adapter
13483 .labels_for_completions(&lsp_completions, language)
13484 .await
13485 .log_err()
13486 .unwrap_or_default()
13487 } else {
13488 Vec::new()
13489 }
13490 .into_iter()
13491 .fuse();
13492
13493 let mut completions = Vec::new();
13494 for completion in new_completions {
13495 match completion.source.lsp_completion(true) {
13496 Some(lsp_completion) => {
13497 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13498
13499 let mut label = labels.next().flatten().unwrap_or_else(|| {
13500 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13501 });
13502 ensure_uniform_list_compatible_label(&mut label);
13503 completions.push(Completion {
13504 label,
13505 documentation,
13506 replace_range: completion.replace_range,
13507 new_text: completion.new_text,
13508 insert_text_mode: lsp_completion.insert_text_mode,
13509 source: completion.source,
13510 icon_path: None,
13511 confirm: None,
13512 match_start: None,
13513 snippet_deduplication_key: None,
13514 });
13515 }
13516 None => {
13517 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13518 ensure_uniform_list_compatible_label(&mut label);
13519 completions.push(Completion {
13520 label,
13521 documentation: None,
13522 replace_range: completion.replace_range,
13523 new_text: completion.new_text,
13524 source: completion.source,
13525 insert_text_mode: None,
13526 icon_path: None,
13527 confirm: None,
13528 match_start: None,
13529 snippet_deduplication_key: None,
13530 });
13531 }
13532 }
13533 }
13534 completions
13535}
13536
13537#[derive(Debug)]
13538pub enum LanguageServerToQuery {
13539 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13540 FirstCapable,
13541 /// Query a specific language server.
13542 Other(LanguageServerId),
13543}
13544
13545#[derive(Default)]
13546struct RenamePathsWatchedForServer {
13547 did_rename: Vec<RenameActionPredicate>,
13548 will_rename: Vec<RenameActionPredicate>,
13549}
13550
13551impl RenamePathsWatchedForServer {
13552 fn with_did_rename_patterns(
13553 mut self,
13554 did_rename: Option<&FileOperationRegistrationOptions>,
13555 ) -> Self {
13556 if let Some(did_rename) = did_rename {
13557 self.did_rename = did_rename
13558 .filters
13559 .iter()
13560 .filter_map(|filter| filter.try_into().log_err())
13561 .collect();
13562 }
13563 self
13564 }
13565 fn with_will_rename_patterns(
13566 mut self,
13567 will_rename: Option<&FileOperationRegistrationOptions>,
13568 ) -> Self {
13569 if let Some(will_rename) = will_rename {
13570 self.will_rename = will_rename
13571 .filters
13572 .iter()
13573 .filter_map(|filter| filter.try_into().log_err())
13574 .collect();
13575 }
13576 self
13577 }
13578
13579 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13580 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13581 }
13582 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13583 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13584 }
13585}
13586
13587impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13588 type Error = globset::Error;
13589 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13590 Ok(Self {
13591 kind: ops.pattern.matches.clone(),
13592 glob: GlobBuilder::new(&ops.pattern.glob)
13593 .case_insensitive(
13594 ops.pattern
13595 .options
13596 .as_ref()
13597 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13598 )
13599 .build()?
13600 .compile_matcher(),
13601 })
13602 }
13603}
13604struct RenameActionPredicate {
13605 glob: GlobMatcher,
13606 kind: Option<FileOperationPatternKind>,
13607}
13608
13609impl RenameActionPredicate {
13610 // Returns true if language server should be notified
13611 fn eval(&self, path: &str, is_dir: bool) -> bool {
13612 self.kind.as_ref().is_none_or(|kind| {
13613 let expected_kind = if is_dir {
13614 FileOperationPatternKind::Folder
13615 } else {
13616 FileOperationPatternKind::File
13617 };
13618 kind == &expected_kind
13619 }) && self.glob.is_match(path)
13620 }
13621}
13622
13623#[derive(Default)]
13624struct LanguageServerWatchedPaths {
13625 worktree_paths: HashMap<WorktreeId, GlobSet>,
13626 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13627}
13628
13629#[derive(Default)]
13630struct LanguageServerWatchedPathsBuilder {
13631 worktree_paths: HashMap<WorktreeId, GlobSet>,
13632 abs_paths: HashMap<Arc<Path>, GlobSet>,
13633}
13634
13635impl LanguageServerWatchedPathsBuilder {
13636 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13637 self.worktree_paths.insert(worktree_id, glob_set);
13638 }
13639 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13640 self.abs_paths.insert(path, glob_set);
13641 }
13642 fn build(
13643 self,
13644 fs: Arc<dyn Fs>,
13645 language_server_id: LanguageServerId,
13646 cx: &mut Context<LspStore>,
13647 ) -> LanguageServerWatchedPaths {
13648 let lsp_store = cx.weak_entity();
13649
13650 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13651 let abs_paths = self
13652 .abs_paths
13653 .into_iter()
13654 .map(|(abs_path, globset)| {
13655 let task = cx.spawn({
13656 let abs_path = abs_path.clone();
13657 let fs = fs.clone();
13658
13659 let lsp_store = lsp_store.clone();
13660 async move |_, cx| {
13661 maybe!(async move {
13662 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13663 while let Some(update) = push_updates.0.next().await {
13664 let action = lsp_store
13665 .update(cx, |this, _| {
13666 let Some(local) = this.as_local() else {
13667 return ControlFlow::Break(());
13668 };
13669 let Some(watcher) = local
13670 .language_server_watched_paths
13671 .get(&language_server_id)
13672 else {
13673 return ControlFlow::Break(());
13674 };
13675 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13676 "Watched abs path is not registered with a watcher",
13677 );
13678 let matching_entries = update
13679 .into_iter()
13680 .filter(|event| globs.is_match(&event.path))
13681 .collect::<Vec<_>>();
13682 this.lsp_notify_abs_paths_changed(
13683 language_server_id,
13684 matching_entries,
13685 );
13686 ControlFlow::Continue(())
13687 })
13688 .ok()?;
13689
13690 if action.is_break() {
13691 break;
13692 }
13693 }
13694 Some(())
13695 })
13696 .await;
13697 }
13698 });
13699 (abs_path, (globset, task))
13700 })
13701 .collect();
13702 LanguageServerWatchedPaths {
13703 worktree_paths: self.worktree_paths,
13704 abs_paths,
13705 }
13706 }
13707}
13708
13709struct LspBufferSnapshot {
13710 version: i32,
13711 snapshot: TextBufferSnapshot,
13712}
13713
13714/// A prompt requested by LSP server.
13715#[derive(Clone, Debug)]
13716pub struct LanguageServerPromptRequest {
13717 pub id: usize,
13718 pub level: PromptLevel,
13719 pub message: String,
13720 pub actions: Vec<MessageActionItem>,
13721 pub lsp_name: String,
13722 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13723}
13724
13725impl LanguageServerPromptRequest {
13726 pub fn new(
13727 level: PromptLevel,
13728 message: String,
13729 actions: Vec<MessageActionItem>,
13730 lsp_name: String,
13731 response_channel: smol::channel::Sender<MessageActionItem>,
13732 ) -> Self {
13733 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13734 LanguageServerPromptRequest {
13735 id,
13736 level,
13737 message,
13738 actions,
13739 lsp_name,
13740 response_channel,
13741 }
13742 }
13743 pub async fn respond(self, index: usize) -> Option<()> {
13744 if let Some(response) = self.actions.into_iter().nth(index) {
13745 self.response_channel.send(response).await.ok()
13746 } else {
13747 None
13748 }
13749 }
13750
13751 #[cfg(any(test, feature = "test-support"))]
13752 pub fn test(
13753 level: PromptLevel,
13754 message: String,
13755 actions: Vec<MessageActionItem>,
13756 lsp_name: String,
13757 ) -> Self {
13758 let (tx, _rx) = smol::channel::unbounded();
13759 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13760 }
13761}
13762impl PartialEq for LanguageServerPromptRequest {
13763 fn eq(&self, other: &Self) -> bool {
13764 self.message == other.message && self.actions == other.actions
13765 }
13766}
13767
13768#[derive(Clone, Debug, PartialEq)]
13769pub enum LanguageServerLogType {
13770 Log(MessageType),
13771 Trace { verbose_info: Option<String> },
13772 Rpc { received: bool },
13773}
13774
13775impl LanguageServerLogType {
13776 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13777 match self {
13778 Self::Log(log_type) => {
13779 use proto::log_message::LogLevel;
13780 let level = match *log_type {
13781 MessageType::ERROR => LogLevel::Error,
13782 MessageType::WARNING => LogLevel::Warning,
13783 MessageType::INFO => LogLevel::Info,
13784 MessageType::LOG => LogLevel::Log,
13785 other => {
13786 log::warn!("Unknown lsp log message type: {other:?}");
13787 LogLevel::Log
13788 }
13789 };
13790 proto::language_server_log::LogType::Log(proto::LogMessage {
13791 level: level as i32,
13792 })
13793 }
13794 Self::Trace { verbose_info } => {
13795 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13796 verbose_info: verbose_info.to_owned(),
13797 })
13798 }
13799 Self::Rpc { received } => {
13800 let kind = if *received {
13801 proto::rpc_message::Kind::Received
13802 } else {
13803 proto::rpc_message::Kind::Sent
13804 };
13805 let kind = kind as i32;
13806 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13807 }
13808 }
13809 }
13810
13811 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13812 use proto::log_message::LogLevel;
13813 use proto::rpc_message;
13814 match log_type {
13815 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13816 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13817 LogLevel::Error => MessageType::ERROR,
13818 LogLevel::Warning => MessageType::WARNING,
13819 LogLevel::Info => MessageType::INFO,
13820 LogLevel::Log => MessageType::LOG,
13821 },
13822 ),
13823 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13824 verbose_info: trace_message.verbose_info,
13825 },
13826 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13827 received: match rpc_message::Kind::from_i32(message.kind)
13828 .unwrap_or(rpc_message::Kind::Received)
13829 {
13830 rpc_message::Kind::Received => true,
13831 rpc_message::Kind::Sent => false,
13832 },
13833 },
13834 }
13835 }
13836}
13837
13838pub struct WorkspaceRefreshTask {
13839 refresh_tx: mpsc::Sender<()>,
13840 progress_tx: mpsc::Sender<()>,
13841 #[allow(dead_code)]
13842 task: Task<()>,
13843}
13844
13845pub enum LanguageServerState {
13846 Starting {
13847 startup: Task<Option<Arc<LanguageServer>>>,
13848 /// List of language servers that will be added to the workspace once it's initialization completes.
13849 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13850 },
13851
13852 Running {
13853 adapter: Arc<CachedLspAdapter>,
13854 server: Arc<LanguageServer>,
13855 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13856 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13857 },
13858}
13859
13860impl LanguageServerState {
13861 fn add_workspace_folder(&self, uri: Uri) {
13862 match self {
13863 LanguageServerState::Starting {
13864 pending_workspace_folders,
13865 ..
13866 } => {
13867 pending_workspace_folders.lock().insert(uri);
13868 }
13869 LanguageServerState::Running { server, .. } => {
13870 server.add_workspace_folder(uri);
13871 }
13872 }
13873 }
13874 fn _remove_workspace_folder(&self, uri: Uri) {
13875 match self {
13876 LanguageServerState::Starting {
13877 pending_workspace_folders,
13878 ..
13879 } => {
13880 pending_workspace_folders.lock().remove(&uri);
13881 }
13882 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13883 }
13884 }
13885}
13886
13887impl std::fmt::Debug for LanguageServerState {
13888 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13889 match self {
13890 LanguageServerState::Starting { .. } => {
13891 f.debug_struct("LanguageServerState::Starting").finish()
13892 }
13893 LanguageServerState::Running { .. } => {
13894 f.debug_struct("LanguageServerState::Running").finish()
13895 }
13896 }
13897 }
13898}
13899
13900#[derive(Clone, Debug, Serialize)]
13901pub struct LanguageServerProgress {
13902 pub is_disk_based_diagnostics_progress: bool,
13903 pub is_cancellable: bool,
13904 pub title: Option<String>,
13905 pub message: Option<String>,
13906 pub percentage: Option<usize>,
13907 #[serde(skip_serializing)]
13908 pub last_update_at: Instant,
13909}
13910
13911#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13912pub struct DiagnosticSummary {
13913 pub error_count: usize,
13914 pub warning_count: usize,
13915}
13916
13917impl DiagnosticSummary {
13918 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13919 let mut this = Self {
13920 error_count: 0,
13921 warning_count: 0,
13922 };
13923
13924 for entry in diagnostics {
13925 if entry.diagnostic.is_primary {
13926 match entry.diagnostic.severity {
13927 DiagnosticSeverity::ERROR => this.error_count += 1,
13928 DiagnosticSeverity::WARNING => this.warning_count += 1,
13929 _ => {}
13930 }
13931 }
13932 }
13933
13934 this
13935 }
13936
13937 pub fn is_empty(&self) -> bool {
13938 self.error_count == 0 && self.warning_count == 0
13939 }
13940
13941 pub fn to_proto(
13942 self,
13943 language_server_id: LanguageServerId,
13944 path: &RelPath,
13945 ) -> proto::DiagnosticSummary {
13946 proto::DiagnosticSummary {
13947 path: path.to_proto(),
13948 language_server_id: language_server_id.0 as u64,
13949 error_count: self.error_count as u32,
13950 warning_count: self.warning_count as u32,
13951 }
13952 }
13953}
13954
13955#[derive(Clone, Debug)]
13956pub enum CompletionDocumentation {
13957 /// There is no documentation for this completion.
13958 Undocumented,
13959 /// A single line of documentation.
13960 SingleLine(SharedString),
13961 /// Multiple lines of plain text documentation.
13962 MultiLinePlainText(SharedString),
13963 /// Markdown documentation.
13964 MultiLineMarkdown(SharedString),
13965 /// Both single line and multiple lines of plain text documentation.
13966 SingleLineAndMultiLinePlainText {
13967 single_line: SharedString,
13968 plain_text: Option<SharedString>,
13969 },
13970}
13971
13972impl CompletionDocumentation {
13973 #[cfg(any(test, feature = "test-support"))]
13974 pub fn text(&self) -> SharedString {
13975 match self {
13976 CompletionDocumentation::Undocumented => "".into(),
13977 CompletionDocumentation::SingleLine(s) => s.clone(),
13978 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13979 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13980 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13981 single_line.clone()
13982 }
13983 }
13984 }
13985}
13986
13987impl From<lsp::Documentation> for CompletionDocumentation {
13988 fn from(docs: lsp::Documentation) -> Self {
13989 match docs {
13990 lsp::Documentation::String(text) => {
13991 if text.lines().count() <= 1 {
13992 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13993 } else {
13994 CompletionDocumentation::MultiLinePlainText(text.into())
13995 }
13996 }
13997
13998 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13999 lsp::MarkupKind::PlainText => {
14000 if value.lines().count() <= 1 {
14001 CompletionDocumentation::SingleLine(value.into())
14002 } else {
14003 CompletionDocumentation::MultiLinePlainText(value.into())
14004 }
14005 }
14006
14007 lsp::MarkupKind::Markdown => {
14008 CompletionDocumentation::MultiLineMarkdown(value.into())
14009 }
14010 },
14011 }
14012 }
14013}
14014
14015pub enum ResolvedHint {
14016 Resolved(InlayHint),
14017 Resolving(Shared<Task<()>>),
14018}
14019
14020pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14021 glob.components()
14022 .take_while(|component| match component {
14023 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14024 _ => true,
14025 })
14026 .collect()
14027}
14028
14029pub struct SshLspAdapter {
14030 name: LanguageServerName,
14031 binary: LanguageServerBinary,
14032 initialization_options: Option<String>,
14033 code_action_kinds: Option<Vec<CodeActionKind>>,
14034}
14035
14036impl SshLspAdapter {
14037 pub fn new(
14038 name: LanguageServerName,
14039 binary: LanguageServerBinary,
14040 initialization_options: Option<String>,
14041 code_action_kinds: Option<String>,
14042 ) -> Self {
14043 Self {
14044 name,
14045 binary,
14046 initialization_options,
14047 code_action_kinds: code_action_kinds
14048 .as_ref()
14049 .and_then(|c| serde_json::from_str(c).ok()),
14050 }
14051 }
14052}
14053
14054impl LspInstaller for SshLspAdapter {
14055 type BinaryVersion = ();
14056 async fn check_if_user_installed(
14057 &self,
14058 _: &dyn LspAdapterDelegate,
14059 _: Option<Toolchain>,
14060 _: &AsyncApp,
14061 ) -> Option<LanguageServerBinary> {
14062 Some(self.binary.clone())
14063 }
14064
14065 async fn cached_server_binary(
14066 &self,
14067 _: PathBuf,
14068 _: &dyn LspAdapterDelegate,
14069 ) -> Option<LanguageServerBinary> {
14070 None
14071 }
14072
14073 async fn fetch_latest_server_version(
14074 &self,
14075 _: &dyn LspAdapterDelegate,
14076 _: bool,
14077 _: &mut AsyncApp,
14078 ) -> Result<()> {
14079 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14080 }
14081
14082 async fn fetch_server_binary(
14083 &self,
14084 _: (),
14085 _: PathBuf,
14086 _: &dyn LspAdapterDelegate,
14087 ) -> Result<LanguageServerBinary> {
14088 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14089 }
14090}
14091
14092#[async_trait(?Send)]
14093impl LspAdapter for SshLspAdapter {
14094 fn name(&self) -> LanguageServerName {
14095 self.name.clone()
14096 }
14097
14098 async fn initialization_options(
14099 self: Arc<Self>,
14100 _: &Arc<dyn LspAdapterDelegate>,
14101 _: &mut AsyncApp,
14102 ) -> Result<Option<serde_json::Value>> {
14103 let Some(options) = &self.initialization_options else {
14104 return Ok(None);
14105 };
14106 let result = serde_json::from_str(options)?;
14107 Ok(result)
14108 }
14109
14110 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14111 self.code_action_kinds.clone()
14112 }
14113}
14114
14115pub fn language_server_settings<'a>(
14116 delegate: &'a dyn LspAdapterDelegate,
14117 language: &LanguageServerName,
14118 cx: &'a App,
14119) -> Option<&'a LspSettings> {
14120 language_server_settings_for(
14121 SettingsLocation {
14122 worktree_id: delegate.worktree_id(),
14123 path: RelPath::empty(),
14124 },
14125 language,
14126 cx,
14127 )
14128}
14129
14130pub fn language_server_settings_for<'a>(
14131 location: SettingsLocation<'a>,
14132 language: &LanguageServerName,
14133 cx: &'a App,
14134) -> Option<&'a LspSettings> {
14135 ProjectSettings::get(Some(location), cx).lsp.get(language)
14136}
14137
14138pub struct LocalLspAdapterDelegate {
14139 lsp_store: WeakEntity<LspStore>,
14140 worktree: worktree::Snapshot,
14141 fs: Arc<dyn Fs>,
14142 http_client: Arc<dyn HttpClient>,
14143 language_registry: Arc<LanguageRegistry>,
14144 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14145}
14146
14147impl LocalLspAdapterDelegate {
14148 pub fn new(
14149 language_registry: Arc<LanguageRegistry>,
14150 environment: &Entity<ProjectEnvironment>,
14151 lsp_store: WeakEntity<LspStore>,
14152 worktree: &Entity<Worktree>,
14153 http_client: Arc<dyn HttpClient>,
14154 fs: Arc<dyn Fs>,
14155 cx: &mut App,
14156 ) -> Arc<Self> {
14157 let load_shell_env_task =
14158 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14159
14160 Arc::new(Self {
14161 lsp_store,
14162 worktree: worktree.read(cx).snapshot(),
14163 fs,
14164 http_client,
14165 language_registry,
14166 load_shell_env_task,
14167 })
14168 }
14169
14170 pub fn from_local_lsp(
14171 local: &LocalLspStore,
14172 worktree: &Entity<Worktree>,
14173 cx: &mut App,
14174 ) -> Arc<Self> {
14175 Self::new(
14176 local.languages.clone(),
14177 &local.environment,
14178 local.weak.clone(),
14179 worktree,
14180 local.http_client.clone(),
14181 local.fs.clone(),
14182 cx,
14183 )
14184 }
14185}
14186
14187#[async_trait]
14188impl LspAdapterDelegate for LocalLspAdapterDelegate {
14189 fn show_notification(&self, message: &str, cx: &mut App) {
14190 self.lsp_store
14191 .update(cx, |_, cx| {
14192 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14193 })
14194 .ok();
14195 }
14196
14197 fn http_client(&self) -> Arc<dyn HttpClient> {
14198 self.http_client.clone()
14199 }
14200
14201 fn worktree_id(&self) -> WorktreeId {
14202 self.worktree.id()
14203 }
14204
14205 fn worktree_root_path(&self) -> &Path {
14206 self.worktree.abs_path().as_ref()
14207 }
14208
14209 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14210 self.worktree.resolve_relative_path(path)
14211 }
14212
14213 async fn shell_env(&self) -> HashMap<String, String> {
14214 let task = self.load_shell_env_task.clone();
14215 task.await.unwrap_or_default()
14216 }
14217
14218 async fn npm_package_installed_version(
14219 &self,
14220 package_name: &str,
14221 ) -> Result<Option<(PathBuf, Version)>> {
14222 let local_package_directory = self.worktree_root_path();
14223 let node_modules_directory = local_package_directory.join("node_modules");
14224
14225 if let Some(version) =
14226 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14227 {
14228 return Ok(Some((node_modules_directory, version)));
14229 }
14230 let Some(npm) = self.which("npm".as_ref()).await else {
14231 log::warn!(
14232 "Failed to find npm executable for {:?}",
14233 local_package_directory
14234 );
14235 return Ok(None);
14236 };
14237
14238 let env = self.shell_env().await;
14239 let output = util::command::new_command(&npm)
14240 .args(["root", "-g"])
14241 .envs(env)
14242 .current_dir(local_package_directory)
14243 .output()
14244 .await?;
14245 let global_node_modules =
14246 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14247
14248 if let Some(version) =
14249 read_package_installed_version(global_node_modules.clone(), package_name).await?
14250 {
14251 return Ok(Some((global_node_modules, version)));
14252 }
14253 return Ok(None);
14254 }
14255
14256 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14257 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14258 if self.fs.is_file(&worktree_abs_path).await {
14259 worktree_abs_path.pop();
14260 }
14261
14262 let env = self.shell_env().await;
14263
14264 let shell_path = env.get("PATH").cloned();
14265
14266 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14267 }
14268
14269 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14270 let mut working_dir = self.worktree_root_path().to_path_buf();
14271 if self.fs.is_file(&working_dir).await {
14272 working_dir.pop();
14273 }
14274 let output = util::command::new_command(&command.path)
14275 .args(command.arguments)
14276 .envs(command.env.clone().unwrap_or_default())
14277 .current_dir(working_dir)
14278 .output()
14279 .await?;
14280
14281 anyhow::ensure!(
14282 output.status.success(),
14283 "{}, stdout: {:?}, stderr: {:?}",
14284 output.status,
14285 String::from_utf8_lossy(&output.stdout),
14286 String::from_utf8_lossy(&output.stderr)
14287 );
14288 Ok(())
14289 }
14290
14291 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14292 self.language_registry
14293 .update_lsp_binary_status(server_name, status);
14294 }
14295
14296 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14297 self.language_registry
14298 .all_lsp_adapters()
14299 .into_iter()
14300 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14301 .collect()
14302 }
14303
14304 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14305 let dir = self.language_registry.language_server_download_dir(name)?;
14306
14307 if !dir.exists() {
14308 smol::fs::create_dir_all(&dir)
14309 .await
14310 .context("failed to create container directory")
14311 .log_err()?;
14312 }
14313
14314 Some(dir)
14315 }
14316
14317 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14318 let entry = self
14319 .worktree
14320 .entry_for_path(path)
14321 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14322 let abs_path = self.worktree.absolutize(&entry.path);
14323 self.fs.load(&abs_path).await
14324 }
14325}
14326
14327async fn populate_labels_for_symbols(
14328 symbols: Vec<CoreSymbol>,
14329 language_registry: &Arc<LanguageRegistry>,
14330 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14331 output: &mut Vec<Symbol>,
14332) {
14333 #[allow(clippy::mutable_key_type)]
14334 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14335
14336 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14337 for symbol in symbols {
14338 let Some(file_name) = symbol.path.file_name() else {
14339 continue;
14340 };
14341 let language = language_registry
14342 .load_language_for_file_path(Path::new(file_name))
14343 .await
14344 .ok()
14345 .or_else(|| {
14346 unknown_paths.insert(file_name.into());
14347 None
14348 });
14349 symbols_by_language
14350 .entry(language)
14351 .or_default()
14352 .push(symbol);
14353 }
14354
14355 for unknown_path in unknown_paths {
14356 log::info!("no language found for symbol in file {unknown_path:?}");
14357 }
14358
14359 let mut label_params = Vec::new();
14360 for (language, mut symbols) in symbols_by_language {
14361 label_params.clear();
14362 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14363 name: mem::take(&mut symbol.name),
14364 kind: symbol.kind,
14365 container_name: symbol.container_name.take(),
14366 }));
14367
14368 let mut labels = Vec::new();
14369 if let Some(language) = language {
14370 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14371 language_registry
14372 .lsp_adapters(&language.name())
14373 .first()
14374 .cloned()
14375 });
14376 if let Some(lsp_adapter) = lsp_adapter {
14377 labels = lsp_adapter
14378 .labels_for_symbols(&label_params, &language)
14379 .await
14380 .log_err()
14381 .unwrap_or_default();
14382 }
14383 }
14384
14385 for (
14386 (
14387 symbol,
14388 language::Symbol {
14389 name,
14390 container_name,
14391 ..
14392 },
14393 ),
14394 label,
14395 ) in symbols
14396 .into_iter()
14397 .zip(label_params.drain(..))
14398 .zip(labels.into_iter().chain(iter::repeat(None)))
14399 {
14400 output.push(Symbol {
14401 language_server_name: symbol.language_server_name,
14402 source_worktree_id: symbol.source_worktree_id,
14403 source_language_server_id: symbol.source_language_server_id,
14404 path: symbol.path,
14405 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14406 name,
14407 kind: symbol.kind,
14408 range: symbol.range,
14409 container_name,
14410 });
14411 }
14412 }
14413}
14414
14415pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14416 text.lines()
14417 .map(|line| line.trim())
14418 .filter(|line| !line.is_empty())
14419 .join(separator)
14420}
14421
14422fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14423 match server.capabilities().text_document_sync.as_ref()? {
14424 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14425 // Server wants didSave but didn't specify includeText.
14426 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14427 // Server doesn't want didSave at all.
14428 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14429 // Server provided SaveOptions.
14430 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14431 Some(save_options.include_text.unwrap_or(false))
14432 }
14433 },
14434 // We do not have any save info. Kind affects didChange only.
14435 lsp::TextDocumentSyncCapability::Kind(_) => None,
14436 }
14437}
14438
14439/// Completion items are displayed in a `UniformList`.
14440/// Usually, those items are single-line strings, but in LSP responses,
14441/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14442/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14443/// 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,
14444/// breaking the completions menu presentation.
14445///
14446/// 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.
14447pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14448 let mut new_text = String::with_capacity(label.text.len());
14449 let mut offset_map = vec![0; label.text.len() + 1];
14450 let mut last_char_was_space = false;
14451 let mut new_idx = 0;
14452 let chars = label.text.char_indices().fuse();
14453 let mut newlines_removed = false;
14454
14455 for (idx, c) in chars {
14456 offset_map[idx] = new_idx;
14457
14458 match c {
14459 '\n' if last_char_was_space => {
14460 newlines_removed = true;
14461 }
14462 '\t' | ' ' if last_char_was_space => {}
14463 '\n' if !last_char_was_space => {
14464 new_text.push(' ');
14465 new_idx += 1;
14466 last_char_was_space = true;
14467 newlines_removed = true;
14468 }
14469 ' ' | '\t' => {
14470 new_text.push(' ');
14471 new_idx += 1;
14472 last_char_was_space = true;
14473 }
14474 _ => {
14475 new_text.push(c);
14476 new_idx += c.len_utf8();
14477 last_char_was_space = false;
14478 }
14479 }
14480 }
14481 offset_map[label.text.len()] = new_idx;
14482
14483 // Only modify the label if newlines were removed.
14484 if !newlines_removed {
14485 return;
14486 }
14487
14488 let last_index = new_idx;
14489 let mut run_ranges_errors = Vec::new();
14490 label.runs.retain_mut(|(range, _)| {
14491 match offset_map.get(range.start) {
14492 Some(&start) => range.start = start,
14493 None => {
14494 run_ranges_errors.push(range.clone());
14495 return false;
14496 }
14497 }
14498
14499 match offset_map.get(range.end) {
14500 Some(&end) => range.end = end,
14501 None => {
14502 run_ranges_errors.push(range.clone());
14503 range.end = last_index;
14504 }
14505 }
14506 true
14507 });
14508 if !run_ranges_errors.is_empty() {
14509 log::error!(
14510 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14511 label.text
14512 );
14513 }
14514
14515 let mut wrong_filter_range = None;
14516 if label.filter_range == (0..label.text.len()) {
14517 label.filter_range = 0..new_text.len();
14518 } else {
14519 let mut original_filter_range = Some(label.filter_range.clone());
14520 match offset_map.get(label.filter_range.start) {
14521 Some(&start) => label.filter_range.start = start,
14522 None => {
14523 wrong_filter_range = original_filter_range.take();
14524 label.filter_range.start = last_index;
14525 }
14526 }
14527
14528 match offset_map.get(label.filter_range.end) {
14529 Some(&end) => label.filter_range.end = end,
14530 None => {
14531 wrong_filter_range = original_filter_range.take();
14532 label.filter_range.end = last_index;
14533 }
14534 }
14535 }
14536 if let Some(wrong_filter_range) = wrong_filter_range {
14537 log::error!(
14538 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14539 label.text
14540 );
14541 }
14542
14543 label.text = new_text;
14544}