1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 CodeLabelExt, Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff,
75 File as _, Language, LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate,
76 LspInstaller, ManifestDelegate, ManifestName, ModelineSettings, Patch, PointUtf16,
77 TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 },
81 modeline, point_to_lsp,
82 proto::{
83 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
84 serialize_anchor_range, serialize_version,
85 },
86 range_from_lsp, range_to_lsp,
87 row_chunk::RowChunk,
88};
89use lsp::{
90 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
91 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
92 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
93 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
94 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
95 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
96 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
97 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
98};
99use node_runtime::read_package_installed_version;
100use parking_lot::Mutex;
101use postage::{mpsc, sink::Sink, stream::Stream, watch};
102use rand::prelude::*;
103use rpc::{
104 AnyProtoClient, ErrorCode, ErrorExt as _,
105 proto::{LspRequestId, LspRequestMessage as _},
106};
107use semver::Version;
108use serde::Serialize;
109use serde_json::Value;
110use settings::{Settings, SettingsLocation, SettingsStore};
111use sha2::{Digest, Sha256};
112use snippet::Snippet;
113use std::{
114 any::TypeId,
115 borrow::Cow,
116 cell::RefCell,
117 cmp::{Ordering, Reverse},
118 collections::{VecDeque, hash_map},
119 convert::TryInto,
120 ffi::OsStr,
121 future::ready,
122 iter, mem,
123 ops::{ControlFlow, Range},
124 path::{self, Path, PathBuf},
125 pin::pin,
126 rc::Rc,
127 sync::{
128 Arc,
129 atomic::{self, AtomicUsize},
130 },
131 time::{Duration, Instant},
132 vec,
133};
134use sum_tree::Dimensions;
135use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
136
137use util::{
138 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
139 paths::{PathStyle, SanitizedPath, UrlExt},
140 post_inc,
141 redact::redact_command,
142 rel_path::RelPath,
143};
144
145pub use document_colors::DocumentColors;
146pub use folding_ranges::LspFoldingRange;
147pub use fs::*;
148pub use language::Location;
149pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
150#[cfg(any(test, feature = "test-support"))]
151pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
152pub use semantic_tokens::{
153 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
154};
155
156pub use worktree::{
157 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
158 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
159};
160
161const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
162pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
163const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
164const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
165static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
166
167#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
168pub enum ProgressToken {
169 Number(i32),
170 String(SharedString),
171}
172
173impl std::fmt::Display for ProgressToken {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 match self {
176 Self::Number(number) => write!(f, "{number}"),
177 Self::String(string) => write!(f, "{string}"),
178 }
179 }
180}
181
182impl ProgressToken {
183 fn from_lsp(value: lsp::NumberOrString) -> Self {
184 match value {
185 lsp::NumberOrString::Number(number) => Self::Number(number),
186 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
187 }
188 }
189
190 fn to_lsp(&self) -> lsp::NumberOrString {
191 match self {
192 Self::Number(number) => lsp::NumberOrString::Number(*number),
193 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
194 }
195 }
196
197 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
198 Some(match value.value? {
199 proto::progress_token::Value::Number(number) => Self::Number(number),
200 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
201 })
202 }
203
204 fn to_proto(&self) -> proto::ProgressToken {
205 proto::ProgressToken {
206 value: Some(match self {
207 Self::Number(number) => proto::progress_token::Value::Number(*number),
208 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
209 }),
210 }
211 }
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215pub enum FormatTrigger {
216 Save,
217 Manual,
218}
219
220pub enum LspFormatTarget {
221 Buffers,
222 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Hash)]
226pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
227
228struct OpenLspBuffer(Entity<Buffer>);
229
230impl FormatTrigger {
231 fn from_proto(value: i32) -> FormatTrigger {
232 match value {
233 0 => FormatTrigger::Save,
234 1 => FormatTrigger::Manual,
235 _ => FormatTrigger::Save,
236 }
237 }
238}
239
240#[derive(Clone)]
241struct UnifiedLanguageServer {
242 id: LanguageServerId,
243 project_roots: HashSet<Arc<RelPath>>,
244}
245
246/// Settings that affect language server identity.
247///
248/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
249/// updated via `workspace/didChangeConfiguration` without restarting the server.
250#[derive(Clone, Debug, Hash, PartialEq, Eq)]
251struct LanguageServerSeedSettings {
252 binary: Option<BinarySettings>,
253 initialization_options: Option<serde_json::Value>,
254}
255
256#[derive(Clone, Debug, Hash, PartialEq, Eq)]
257struct LanguageServerSeed {
258 worktree_id: WorktreeId,
259 name: LanguageServerName,
260 toolchain: Option<Toolchain>,
261 settings: LanguageServerSeedSettings,
262}
263
264#[derive(Debug)]
265pub struct DocumentDiagnosticsUpdate<'a, D> {
266 pub diagnostics: D,
267 pub result_id: Option<SharedString>,
268 pub registration_id: Option<SharedString>,
269 pub server_id: LanguageServerId,
270 pub disk_based_sources: Cow<'a, [String]>,
271}
272
273pub struct DocumentDiagnostics {
274 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
275 document_abs_path: PathBuf,
276 version: Option<i32>,
277}
278
279#[derive(Default, Debug)]
280struct DynamicRegistrations {
281 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
282 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
283}
284
285pub struct LocalLspStore {
286 weak: WeakEntity<LspStore>,
287 pub worktree_store: Entity<WorktreeStore>,
288 toolchain_store: Entity<LocalToolchainStore>,
289 http_client: Arc<dyn HttpClient>,
290 environment: Entity<ProjectEnvironment>,
291 fs: Arc<dyn Fs>,
292 languages: Arc<LanguageRegistry>,
293 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
294 yarn: Entity<YarnPathStore>,
295 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
296 buffers_being_formatted: HashSet<BufferId>,
297 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
298 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
299 watched_manifest_filenames: HashSet<ManifestName>,
300 language_server_paths_watched_for_rename:
301 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
302 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
303 supplementary_language_servers:
304 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
305 prettier_store: Entity<PrettierStore>,
306 next_diagnostic_group_id: usize,
307 diagnostics: HashMap<
308 WorktreeId,
309 HashMap<
310 Arc<RelPath>,
311 Vec<(
312 LanguageServerId,
313 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
314 )>,
315 >,
316 >,
317 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
318 _subscription: gpui::Subscription,
319 lsp_tree: LanguageServerTree,
320 registered_buffers: HashMap<BufferId, usize>,
321 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
322 buffer_pull_diagnostics_result_ids: HashMap<
323 LanguageServerId,
324 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
325 >,
326 workspace_pull_diagnostics_result_ids: HashMap<
327 LanguageServerId,
328 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
329 >,
330 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
331
332 buffers_to_refresh_hash_set: HashSet<BufferId>,
333 buffers_to_refresh_queue: VecDeque<BufferId>,
334 _background_diagnostics_worker: Shared<Task<()>>,
335}
336
337impl LocalLspStore {
338 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
339 pub fn running_language_server_for_id(
340 &self,
341 id: LanguageServerId,
342 ) -> Option<&Arc<LanguageServer>> {
343 let language_server_state = self.language_servers.get(&id)?;
344
345 match language_server_state {
346 LanguageServerState::Running { server, .. } => Some(server),
347 LanguageServerState::Starting { .. } => None,
348 }
349 }
350
351 fn get_or_insert_language_server(
352 &mut self,
353 worktree_handle: &Entity<Worktree>,
354 delegate: Arc<LocalLspAdapterDelegate>,
355 disposition: &Arc<LaunchDisposition>,
356 language_name: &LanguageName,
357 cx: &mut App,
358 ) -> LanguageServerId {
359 let key = LanguageServerSeed {
360 worktree_id: worktree_handle.read(cx).id(),
361 name: disposition.server_name.clone(),
362 settings: LanguageServerSeedSettings {
363 binary: disposition.settings.binary.clone(),
364 initialization_options: disposition.settings.initialization_options.clone(),
365 },
366 toolchain: disposition.toolchain.clone(),
367 };
368 if let Some(state) = self.language_server_ids.get_mut(&key) {
369 state.project_roots.insert(disposition.path.path.clone());
370 state.id
371 } else {
372 let adapter = self
373 .languages
374 .lsp_adapters(language_name)
375 .into_iter()
376 .find(|adapter| adapter.name() == disposition.server_name)
377 .expect("To find LSP adapter");
378 let new_language_server_id = self.start_language_server(
379 worktree_handle,
380 delegate,
381 adapter,
382 disposition.settings.clone(),
383 key.clone(),
384 language_name.clone(),
385 cx,
386 );
387 if let Some(state) = self.language_server_ids.get_mut(&key) {
388 state.project_roots.insert(disposition.path.path.clone());
389 } else {
390 debug_assert!(
391 false,
392 "Expected `start_language_server` to ensure that `key` exists in a map"
393 );
394 }
395 new_language_server_id
396 }
397 }
398
399 fn start_language_server(
400 &mut self,
401 worktree_handle: &Entity<Worktree>,
402 delegate: Arc<LocalLspAdapterDelegate>,
403 adapter: Arc<CachedLspAdapter>,
404 settings: Arc<LspSettings>,
405 key: LanguageServerSeed,
406 language_name: LanguageName,
407 cx: &mut App,
408 ) -> LanguageServerId {
409 let worktree = worktree_handle.read(cx);
410
411 let worktree_id = worktree.id();
412 let worktree_abs_path = worktree.abs_path();
413 let toolchain = key.toolchain.clone();
414 let override_options = settings.initialization_options.clone();
415
416 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
417
418 let server_id = self.languages.next_language_server_id();
419 log::trace!(
420 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
421 adapter.name.0
422 );
423
424 let wait_until_worktree_trust =
425 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
426 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
427 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
428 });
429 if can_trust {
430 self.restricted_worktrees_tasks.remove(&worktree_id);
431 None
432 } else {
433 match self.restricted_worktrees_tasks.entry(worktree_id) {
434 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
435 hash_map::Entry::Vacant(v) => {
436 let (mut tx, rx) = watch::channel::<bool>();
437 let lsp_store = self.weak.clone();
438 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
439 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
440 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
441 tx.blocking_send(true).ok();
442 lsp_store
443 .update(cx, |lsp_store, _| {
444 if let Some(local_lsp_store) =
445 lsp_store.as_local_mut()
446 {
447 local_lsp_store
448 .restricted_worktrees_tasks
449 .remove(&worktree_id);
450 }
451 })
452 .ok();
453 }
454 }
455 });
456 v.insert((subscription, rx.clone()));
457 Some(rx)
458 }
459 }
460 }
461 });
462 let update_binary_status = wait_until_worktree_trust.is_none();
463
464 let binary = self.get_language_server_binary(
465 worktree_abs_path.clone(),
466 adapter.clone(),
467 settings,
468 toolchain.clone(),
469 delegate.clone(),
470 true,
471 wait_until_worktree_trust,
472 cx,
473 );
474 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
475
476 let pending_server = cx.spawn({
477 let adapter = adapter.clone();
478 let server_name = adapter.name.clone();
479 let stderr_capture = stderr_capture.clone();
480 #[cfg(any(test, feature = "test-support"))]
481 let lsp_store = self.weak.clone();
482 let pending_workspace_folders = pending_workspace_folders.clone();
483 async move |cx| {
484 let binary = binary.await?;
485 #[cfg(any(test, feature = "test-support"))]
486 if let Some(server) = lsp_store
487 .update(&mut cx.clone(), |this, cx| {
488 this.languages.create_fake_language_server(
489 server_id,
490 &server_name,
491 binary.clone(),
492 &mut cx.to_async(),
493 )
494 })
495 .ok()
496 .flatten()
497 {
498 return Ok(server);
499 }
500
501 let code_action_kinds = adapter.code_action_kinds();
502 lsp::LanguageServer::new(
503 stderr_capture,
504 server_id,
505 server_name,
506 binary,
507 &worktree_abs_path,
508 code_action_kinds,
509 Some(pending_workspace_folders),
510 cx,
511 )
512 }
513 });
514
515 let startup = {
516 let server_name = adapter.name.0.clone();
517 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
518 let key = key.clone();
519 let adapter = adapter.clone();
520 let lsp_store = self.weak.clone();
521 let pending_workspace_folders = pending_workspace_folders.clone();
522 let pull_diagnostics = ProjectSettings::get_global(cx)
523 .diagnostics
524 .lsp_pull_diagnostics
525 .enabled;
526 let settings_location = SettingsLocation {
527 worktree_id,
528 path: RelPath::empty(),
529 };
530 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
531 .language(Some(settings_location), Some(&language_name), cx)
532 .semantic_tokens
533 .use_tree_sitter();
534 cx.spawn(async move |cx| {
535 let result = async {
536 let language_server = pending_server.await?;
537
538 let workspace_config = Self::workspace_configuration_for_adapter(
539 adapter.adapter.clone(),
540 &delegate,
541 toolchain,
542 None,
543 cx,
544 )
545 .await?;
546
547 let mut initialization_options = Self::initialization_options_for_adapter(
548 adapter.adapter.clone(),
549 &delegate,
550 cx,
551 )
552 .await?;
553
554 match (&mut initialization_options, override_options) {
555 (Some(initialization_options), Some(override_options)) => {
556 merge_json_value_into(override_options, initialization_options);
557 }
558 (None, override_options) => initialization_options = override_options,
559 _ => {}
560 }
561
562 let initialization_params = cx.update(|cx| {
563 let mut params = language_server.default_initialize_params(
564 pull_diagnostics,
565 augments_syntax_tokens,
566 cx,
567 );
568 params.initialization_options = initialization_options;
569 adapter.adapter.prepare_initialize_params(params, cx)
570 })?;
571
572 Self::setup_lsp_messages(
573 lsp_store.clone(),
574 &language_server,
575 delegate.clone(),
576 adapter.clone(),
577 );
578
579 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
580 settings: workspace_config,
581 };
582 let language_server = cx
583 .update(|cx| {
584 let request_timeout = ProjectSettings::get_global(cx)
585 .global_lsp_settings
586 .get_request_timeout();
587
588 language_server.initialize(
589 initialization_params,
590 Arc::new(did_change_configuration_params.clone()),
591 request_timeout,
592 cx,
593 )
594 })
595 .await
596 .inspect_err(|_| {
597 if let Some(lsp_store) = lsp_store.upgrade() {
598 lsp_store.update(cx, |lsp_store, cx| {
599 lsp_store.cleanup_lsp_data(server_id);
600 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
601 });
602 }
603 })?;
604
605 language_server.notify::<lsp::notification::DidChangeConfiguration>(
606 did_change_configuration_params,
607 )?;
608
609 anyhow::Ok(language_server)
610 }
611 .await;
612
613 match result {
614 Ok(server) => {
615 lsp_store
616 .update(cx, |lsp_store, cx| {
617 lsp_store.insert_newly_running_language_server(
618 adapter,
619 server.clone(),
620 server_id,
621 key,
622 pending_workspace_folders,
623 cx,
624 );
625 })
626 .ok();
627 stderr_capture.lock().take();
628 Some(server)
629 }
630
631 Err(err) => {
632 let log = stderr_capture.lock().take().unwrap_or_default();
633 delegate.update_status(
634 adapter.name(),
635 BinaryStatus::Failed {
636 error: if log.is_empty() {
637 format!("{err:#}")
638 } else {
639 format!("{err:#}\n-- stderr --\n{log}")
640 },
641 },
642 );
643 log::error!(
644 "Failed to start language server {server_name:?}: {}",
645 redact_command(&format!("{err:?}"))
646 );
647 if !log.is_empty() {
648 log::error!("server stderr: {}", redact_command(&log));
649 }
650 None
651 }
652 }
653 })
654 };
655 let state = LanguageServerState::Starting {
656 startup,
657 pending_workspace_folders,
658 };
659
660 if update_binary_status {
661 self.languages
662 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
663 }
664
665 self.language_servers.insert(server_id, state);
666 self.language_server_ids
667 .entry(key)
668 .or_insert(UnifiedLanguageServer {
669 id: server_id,
670 project_roots: Default::default(),
671 });
672 server_id
673 }
674
675 fn get_language_server_binary(
676 &self,
677 worktree_abs_path: Arc<Path>,
678 adapter: Arc<CachedLspAdapter>,
679 settings: Arc<LspSettings>,
680 toolchain: Option<Toolchain>,
681 delegate: Arc<dyn LspAdapterDelegate>,
682 allow_binary_download: bool,
683 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
684 cx: &mut App,
685 ) -> Task<Result<LanguageServerBinary>> {
686 if let Some(settings) = &settings.binary
687 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
688 {
689 let settings = settings.clone();
690 let languages = self.languages.clone();
691 return cx.background_spawn(async move {
692 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
693 let already_trusted = *wait_until_worktree_trust.borrow();
694 if !already_trusted {
695 log::info!(
696 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
697 adapter.name(),
698 );
699 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
700 if worktree_trusted {
701 break;
702 }
703 }
704 log::info!(
705 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
706 adapter.name(),
707 );
708 }
709 languages
710 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
711 }
712 let mut env = delegate.shell_env().await;
713 env.extend(settings.env.unwrap_or_default());
714
715 Ok(LanguageServerBinary {
716 path: delegate.resolve_relative_path(path),
717 env: Some(env),
718 arguments: settings
719 .arguments
720 .unwrap_or_default()
721 .iter()
722 .map(Into::into)
723 .collect(),
724 })
725 });
726 }
727 let lsp_binary_options = LanguageServerBinaryOptions {
728 allow_path_lookup: !settings
729 .binary
730 .as_ref()
731 .and_then(|b| b.ignore_system_version)
732 .unwrap_or_default(),
733 allow_binary_download,
734 pre_release: settings
735 .fetch
736 .as_ref()
737 .and_then(|f| f.pre_release)
738 .unwrap_or(false),
739 };
740
741 cx.spawn(async move |cx| {
742 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
743 let already_trusted = *wait_until_worktree_trust.borrow();
744 if !already_trusted {
745 log::info!(
746 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
747 adapter.name(),
748 );
749 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
750 if worktree_trusted {
751 break;
752 }
753 }
754 log::info!(
755 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
756 adapter.name(),
757 );
758 }
759 }
760
761 let (existing_binary, maybe_download_binary) = adapter
762 .clone()
763 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
764 .await
765 .await;
766
767 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
768
769 let mut binary = match (existing_binary, maybe_download_binary) {
770 (binary, None) => binary?,
771 (Err(_), Some(downloader)) => downloader.await?,
772 (Ok(existing_binary), Some(downloader)) => {
773 let mut download_timeout = cx
774 .background_executor()
775 .timer(SERVER_DOWNLOAD_TIMEOUT)
776 .fuse();
777 let mut downloader = downloader.fuse();
778 futures::select! {
779 _ = download_timeout => {
780 // Return existing binary and kick the existing work to the background.
781 cx.spawn(async move |_| downloader.await).detach();
782 Ok(existing_binary)
783 },
784 downloaded_or_existing_binary = downloader => {
785 // If download fails, this results in the existing binary.
786 downloaded_or_existing_binary
787 }
788 }?
789 }
790 };
791 let mut shell_env = delegate.shell_env().await;
792
793 shell_env.extend(binary.env.unwrap_or_default());
794
795 if let Some(settings) = settings.binary.as_ref() {
796 if let Some(arguments) = &settings.arguments {
797 binary.arguments = arguments.iter().map(Into::into).collect();
798 }
799 if let Some(env) = &settings.env {
800 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
801 }
802 }
803
804 binary.env = Some(shell_env);
805 Ok(binary)
806 })
807 }
808
809 fn setup_lsp_messages(
810 lsp_store: WeakEntity<LspStore>,
811 language_server: &LanguageServer,
812 delegate: Arc<dyn LspAdapterDelegate>,
813 adapter: Arc<CachedLspAdapter>,
814 ) {
815 let name = language_server.name();
816 let server_id = language_server.server_id();
817 language_server
818 .on_notification::<lsp::notification::PublishDiagnostics, _>({
819 let adapter = adapter.clone();
820 let this = lsp_store.clone();
821 move |mut params, cx| {
822 let adapter = adapter.clone();
823 if let Some(this) = this.upgrade() {
824 this.update(cx, |this, cx| {
825 adapter.process_diagnostics(&mut params, server_id);
826
827 this.merge_lsp_diagnostics(
828 DiagnosticSourceKind::Pushed,
829 vec![DocumentDiagnosticsUpdate {
830 server_id,
831 diagnostics: params,
832 result_id: None,
833 disk_based_sources: Cow::Borrowed(
834 &adapter.disk_based_diagnostic_sources,
835 ),
836 registration_id: None,
837 }],
838 |_, diagnostic, _cx| match diagnostic.source_kind {
839 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
840 adapter.retain_old_diagnostic(diagnostic)
841 }
842 DiagnosticSourceKind::Pulled => true,
843 },
844 cx,
845 )
846 .log_err();
847 });
848 }
849 }
850 })
851 .detach();
852 language_server
853 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
854 let adapter = adapter.adapter.clone();
855 let delegate = delegate.clone();
856 let this = lsp_store.clone();
857 move |params, cx| {
858 let adapter = adapter.clone();
859 let delegate = delegate.clone();
860 let this = this.clone();
861 let mut cx = cx.clone();
862 async move {
863 let toolchain_for_id = this
864 .update(&mut cx, |this, _| {
865 this.as_local()?.language_server_ids.iter().find_map(
866 |(seed, value)| {
867 (value.id == server_id).then(|| seed.toolchain.clone())
868 },
869 )
870 })?
871 .context("Expected the LSP store to be in a local mode")?;
872
873 let mut scope_uri_to_workspace_config = BTreeMap::new();
874 for item in ¶ms.items {
875 let scope_uri = item.scope_uri.clone();
876 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
877 scope_uri_to_workspace_config.entry(scope_uri.clone())
878 else {
879 // We've already queried workspace configuration of this URI.
880 continue;
881 };
882 let workspace_config = Self::workspace_configuration_for_adapter(
883 adapter.clone(),
884 &delegate,
885 toolchain_for_id.clone(),
886 scope_uri,
887 &mut cx,
888 )
889 .await?;
890 new_scope_uri.insert(workspace_config);
891 }
892
893 Ok(params
894 .items
895 .into_iter()
896 .filter_map(|item| {
897 let workspace_config =
898 scope_uri_to_workspace_config.get(&item.scope_uri)?;
899 if let Some(section) = &item.section {
900 Some(
901 workspace_config
902 .get(section)
903 .cloned()
904 .unwrap_or(serde_json::Value::Null),
905 )
906 } else {
907 Some(workspace_config.clone())
908 }
909 })
910 .collect())
911 }
912 }
913 })
914 .detach();
915
916 language_server
917 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
918 let this = lsp_store.clone();
919 move |_, cx| {
920 let this = this.clone();
921 let cx = cx.clone();
922 async move {
923 let Some(server) =
924 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
925 else {
926 return Ok(None);
927 };
928 let root = server.workspace_folders();
929 Ok(Some(
930 root.into_iter()
931 .map(|uri| WorkspaceFolder {
932 uri,
933 name: Default::default(),
934 })
935 .collect(),
936 ))
937 }
938 }
939 })
940 .detach();
941 // Even though we don't have handling for these requests, respond to them to
942 // avoid stalling any language server like `gopls` which waits for a response
943 // to these requests when initializing.
944 language_server
945 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
946 let this = lsp_store.clone();
947 move |params, cx| {
948 let this = this.clone();
949 let mut cx = cx.clone();
950 async move {
951 this.update(&mut cx, |this, _| {
952 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
953 {
954 status
955 .progress_tokens
956 .insert(ProgressToken::from_lsp(params.token));
957 }
958 })?;
959
960 Ok(())
961 }
962 }
963 })
964 .detach();
965
966 language_server
967 .on_request::<lsp::request::RegisterCapability, _, _>({
968 let lsp_store = lsp_store.clone();
969 move |params, cx| {
970 let lsp_store = lsp_store.clone();
971 let mut cx = cx.clone();
972 async move {
973 lsp_store
974 .update(&mut cx, |lsp_store, cx| {
975 if lsp_store.as_local().is_some() {
976 match lsp_store
977 .register_server_capabilities(server_id, params, cx)
978 {
979 Ok(()) => {}
980 Err(e) => {
981 log::error!(
982 "Failed to register server capabilities: {e:#}"
983 );
984 }
985 };
986 }
987 })
988 .ok();
989 Ok(())
990 }
991 }
992 })
993 .detach();
994
995 language_server
996 .on_request::<lsp::request::UnregisterCapability, _, _>({
997 let lsp_store = lsp_store.clone();
998 move |params, cx| {
999 let lsp_store = lsp_store.clone();
1000 let mut cx = cx.clone();
1001 async move {
1002 lsp_store
1003 .update(&mut cx, |lsp_store, cx| {
1004 if lsp_store.as_local().is_some() {
1005 match lsp_store
1006 .unregister_server_capabilities(server_id, params, cx)
1007 {
1008 Ok(()) => {}
1009 Err(e) => {
1010 log::error!(
1011 "Failed to unregister server capabilities: {e:#}"
1012 );
1013 }
1014 }
1015 }
1016 })
1017 .ok();
1018 Ok(())
1019 }
1020 }
1021 })
1022 .detach();
1023
1024 language_server
1025 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1026 let this = lsp_store.clone();
1027 move |params, cx| {
1028 let mut cx = cx.clone();
1029 let this = this.clone();
1030 async move {
1031 LocalLspStore::on_lsp_workspace_edit(
1032 this.clone(),
1033 params,
1034 server_id,
1035 &mut cx,
1036 )
1037 .await
1038 }
1039 }
1040 })
1041 .detach();
1042
1043 language_server
1044 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1045 let lsp_store = lsp_store.clone();
1046 let request_id = Arc::new(AtomicUsize::new(0));
1047 move |(), cx| {
1048 let lsp_store = lsp_store.clone();
1049 let request_id = request_id.clone();
1050 let mut cx = cx.clone();
1051 async move {
1052 lsp_store
1053 .update(&mut cx, |lsp_store, cx| {
1054 let request_id =
1055 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1056 cx.emit(LspStoreEvent::RefreshInlayHints {
1057 server_id,
1058 request_id,
1059 });
1060 lsp_store
1061 .downstream_client
1062 .as_ref()
1063 .map(|(client, project_id)| {
1064 client.send(proto::RefreshInlayHints {
1065 project_id: *project_id,
1066 server_id: server_id.to_proto(),
1067 request_id: request_id.map(|id| id as u64),
1068 })
1069 })
1070 })?
1071 .transpose()?;
1072 Ok(())
1073 }
1074 }
1075 })
1076 .detach();
1077
1078 language_server
1079 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1080 let this = lsp_store.clone();
1081 move |(), cx| {
1082 let this = this.clone();
1083 let mut cx = cx.clone();
1084 async move {
1085 this.update(&mut cx, |this, cx| {
1086 cx.emit(LspStoreEvent::RefreshCodeLens);
1087 this.downstream_client.as_ref().map(|(client, project_id)| {
1088 client.send(proto::RefreshCodeLens {
1089 project_id: *project_id,
1090 })
1091 })
1092 })?
1093 .transpose()?;
1094 Ok(())
1095 }
1096 }
1097 })
1098 .detach();
1099
1100 language_server
1101 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1102 let lsp_store = lsp_store.clone();
1103 let request_id = Arc::new(AtomicUsize::new(0));
1104 move |(), cx| {
1105 let lsp_store = lsp_store.clone();
1106 let request_id = request_id.clone();
1107 let mut cx = cx.clone();
1108 async move {
1109 lsp_store
1110 .update(&mut cx, |lsp_store, cx| {
1111 let request_id =
1112 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1113 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1114 server_id,
1115 request_id,
1116 });
1117 lsp_store
1118 .downstream_client
1119 .as_ref()
1120 .map(|(client, project_id)| {
1121 client.send(proto::RefreshSemanticTokens {
1122 project_id: *project_id,
1123 server_id: server_id.to_proto(),
1124 request_id: request_id.map(|id| id as u64),
1125 })
1126 })
1127 })?
1128 .transpose()?;
1129 Ok(())
1130 }
1131 }
1132 })
1133 .detach();
1134
1135 language_server
1136 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1137 let this = lsp_store.clone();
1138 move |(), cx| {
1139 let this = this.clone();
1140 let mut cx = cx.clone();
1141 async move {
1142 this.update(&mut cx, |lsp_store, cx| {
1143 lsp_store.pull_workspace_diagnostics(server_id);
1144 lsp_store
1145 .downstream_client
1146 .as_ref()
1147 .map(|(client, project_id)| {
1148 client.send(proto::PullWorkspaceDiagnostics {
1149 project_id: *project_id,
1150 server_id: server_id.to_proto(),
1151 })
1152 })
1153 .transpose()?;
1154 anyhow::Ok(
1155 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1156 )
1157 })??
1158 .await;
1159 Ok(())
1160 }
1161 }
1162 })
1163 .detach();
1164
1165 language_server
1166 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1167 let this = lsp_store.clone();
1168 let name = name.to_string();
1169 let adapter = adapter.clone();
1170 move |params, cx| {
1171 let this = this.clone();
1172 let name = name.to_string();
1173 let adapter = adapter.clone();
1174 let mut cx = cx.clone();
1175 async move {
1176 let actions = params.actions.unwrap_or_default();
1177 let message = params.message.clone();
1178 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1179 let level = match params.typ {
1180 lsp::MessageType::ERROR => PromptLevel::Critical,
1181 lsp::MessageType::WARNING => PromptLevel::Warning,
1182 _ => PromptLevel::Info,
1183 };
1184 let request = LanguageServerPromptRequest::new(
1185 level,
1186 params.message,
1187 actions,
1188 name.clone(),
1189 tx,
1190 );
1191
1192 let did_update = this
1193 .update(&mut cx, |_, cx| {
1194 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1195 })
1196 .is_ok();
1197 if did_update {
1198 let response = rx.recv().await.ok();
1199 if let Some(ref selected_action) = response {
1200 let context = language::PromptResponseContext {
1201 message,
1202 selected_action: selected_action.clone(),
1203 };
1204 adapter.process_prompt_response(&context, &mut cx)
1205 }
1206
1207 Ok(response)
1208 } else {
1209 Ok(None)
1210 }
1211 }
1212 }
1213 })
1214 .detach();
1215 language_server
1216 .on_notification::<lsp::notification::ShowMessage, _>({
1217 let this = lsp_store.clone();
1218 let name = name.to_string();
1219 move |params, cx| {
1220 let this = this.clone();
1221 let name = name.to_string();
1222 let mut cx = cx.clone();
1223
1224 let (tx, _) = smol::channel::bounded(1);
1225 let level = match params.typ {
1226 lsp::MessageType::ERROR => PromptLevel::Critical,
1227 lsp::MessageType::WARNING => PromptLevel::Warning,
1228 _ => PromptLevel::Info,
1229 };
1230 let request =
1231 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1232
1233 let _ = this.update(&mut cx, |_, cx| {
1234 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1235 });
1236 }
1237 })
1238 .detach();
1239
1240 let disk_based_diagnostics_progress_token =
1241 adapter.disk_based_diagnostics_progress_token.clone();
1242
1243 language_server
1244 .on_notification::<lsp::notification::Progress, _>({
1245 let this = lsp_store.clone();
1246 move |params, cx| {
1247 if let Some(this) = this.upgrade() {
1248 this.update(cx, |this, cx| {
1249 this.on_lsp_progress(
1250 params,
1251 server_id,
1252 disk_based_diagnostics_progress_token.clone(),
1253 cx,
1254 );
1255 });
1256 }
1257 }
1258 })
1259 .detach();
1260
1261 language_server
1262 .on_notification::<lsp::notification::LogMessage, _>({
1263 let this = lsp_store.clone();
1264 move |params, cx| {
1265 if let Some(this) = this.upgrade() {
1266 this.update(cx, |_, cx| {
1267 cx.emit(LspStoreEvent::LanguageServerLog(
1268 server_id,
1269 LanguageServerLogType::Log(params.typ),
1270 params.message,
1271 ));
1272 });
1273 }
1274 }
1275 })
1276 .detach();
1277
1278 language_server
1279 .on_notification::<lsp::notification::LogTrace, _>({
1280 let this = lsp_store.clone();
1281 move |params, cx| {
1282 let mut cx = cx.clone();
1283 if let Some(this) = this.upgrade() {
1284 this.update(&mut cx, |_, cx| {
1285 cx.emit(LspStoreEvent::LanguageServerLog(
1286 server_id,
1287 LanguageServerLogType::Trace {
1288 verbose_info: params.verbose,
1289 },
1290 params.message,
1291 ));
1292 });
1293 }
1294 }
1295 })
1296 .detach();
1297
1298 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1299 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1300 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1301 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1302 }
1303
1304 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1305 let shutdown_futures = self
1306 .language_servers
1307 .drain()
1308 .map(|(_, server_state)| Self::shutdown_server(server_state))
1309 .collect::<Vec<_>>();
1310
1311 async move {
1312 join_all(shutdown_futures).await;
1313 }
1314 }
1315
1316 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1317 match server_state {
1318 LanguageServerState::Running { server, .. } => {
1319 if let Some(shutdown) = server.shutdown() {
1320 shutdown.await;
1321 }
1322 }
1323 LanguageServerState::Starting { startup, .. } => {
1324 if let Some(server) = startup.await
1325 && let Some(shutdown) = server.shutdown()
1326 {
1327 shutdown.await;
1328 }
1329 }
1330 }
1331 Ok(())
1332 }
1333
1334 fn language_servers_for_worktree(
1335 &self,
1336 worktree_id: WorktreeId,
1337 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1338 self.language_server_ids
1339 .iter()
1340 .filter_map(move |(seed, state)| {
1341 if seed.worktree_id != worktree_id {
1342 return None;
1343 }
1344
1345 if let Some(LanguageServerState::Running { server, .. }) =
1346 self.language_servers.get(&state.id)
1347 {
1348 Some(server)
1349 } else {
1350 None
1351 }
1352 })
1353 }
1354
1355 fn language_server_ids_for_project_path(
1356 &self,
1357 project_path: ProjectPath,
1358 language: &Language,
1359 cx: &mut App,
1360 ) -> Vec<LanguageServerId> {
1361 let Some(worktree) = self
1362 .worktree_store
1363 .read(cx)
1364 .worktree_for_id(project_path.worktree_id, cx)
1365 else {
1366 return Vec::new();
1367 };
1368 let delegate: Arc<dyn ManifestDelegate> =
1369 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1370
1371 self.lsp_tree
1372 .get(
1373 project_path,
1374 language.name(),
1375 language.manifest(),
1376 &delegate,
1377 cx,
1378 )
1379 .collect::<Vec<_>>()
1380 }
1381
1382 fn language_server_ids_for_buffer(
1383 &self,
1384 buffer: &Buffer,
1385 cx: &mut App,
1386 ) -> Vec<LanguageServerId> {
1387 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1388 let worktree_id = file.worktree_id(cx);
1389
1390 let path: Arc<RelPath> = file
1391 .path()
1392 .parent()
1393 .map(Arc::from)
1394 .unwrap_or_else(|| file.path().clone());
1395 let worktree_path = ProjectPath { worktree_id, path };
1396 self.language_server_ids_for_project_path(worktree_path, language, cx)
1397 } else {
1398 Vec::new()
1399 }
1400 }
1401
1402 fn language_servers_for_buffer<'a>(
1403 &'a self,
1404 buffer: &'a Buffer,
1405 cx: &'a mut App,
1406 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1407 self.language_server_ids_for_buffer(buffer, cx)
1408 .into_iter()
1409 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1410 LanguageServerState::Running {
1411 adapter, server, ..
1412 } => Some((adapter, server)),
1413 _ => None,
1414 })
1415 }
1416
1417 async fn execute_code_action_kind_locally(
1418 lsp_store: WeakEntity<LspStore>,
1419 mut buffers: Vec<Entity<Buffer>>,
1420 kind: CodeActionKind,
1421 push_to_history: bool,
1422 cx: &mut AsyncApp,
1423 ) -> anyhow::Result<ProjectTransaction> {
1424 // Do not allow multiple concurrent code actions requests for the
1425 // same buffer.
1426 lsp_store.update(cx, |this, cx| {
1427 let this = this.as_local_mut().unwrap();
1428 buffers.retain(|buffer| {
1429 this.buffers_being_formatted
1430 .insert(buffer.read(cx).remote_id())
1431 });
1432 })?;
1433 let _cleanup = defer({
1434 let this = lsp_store.clone();
1435 let mut cx = cx.clone();
1436 let buffers = &buffers;
1437 move || {
1438 this.update(&mut cx, |this, cx| {
1439 let this = this.as_local_mut().unwrap();
1440 for buffer in buffers {
1441 this.buffers_being_formatted
1442 .remove(&buffer.read(cx).remote_id());
1443 }
1444 })
1445 .ok();
1446 }
1447 });
1448 let mut project_transaction = ProjectTransaction::default();
1449
1450 for buffer in &buffers {
1451 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1452 buffer.update(cx, |buffer, cx| {
1453 lsp_store
1454 .as_local()
1455 .unwrap()
1456 .language_servers_for_buffer(buffer, cx)
1457 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1458 .collect::<Vec<_>>()
1459 })
1460 })?;
1461 for (_, language_server) in adapters_and_servers.iter() {
1462 let actions = Self::get_server_code_actions_from_action_kinds(
1463 &lsp_store,
1464 language_server.server_id(),
1465 vec![kind.clone()],
1466 buffer,
1467 cx,
1468 )
1469 .await?;
1470 Self::execute_code_actions_on_server(
1471 &lsp_store,
1472 language_server,
1473 actions,
1474 push_to_history,
1475 &mut project_transaction,
1476 cx,
1477 )
1478 .await?;
1479 }
1480 }
1481 Ok(project_transaction)
1482 }
1483
1484 async fn format_locally(
1485 lsp_store: WeakEntity<LspStore>,
1486 mut buffers: Vec<FormattableBuffer>,
1487 push_to_history: bool,
1488 trigger: FormatTrigger,
1489 logger: zlog::Logger,
1490 cx: &mut AsyncApp,
1491 ) -> anyhow::Result<ProjectTransaction> {
1492 // Do not allow multiple concurrent formatting requests for the
1493 // same buffer.
1494 lsp_store.update(cx, |this, cx| {
1495 let this = this.as_local_mut().unwrap();
1496 buffers.retain(|buffer| {
1497 this.buffers_being_formatted
1498 .insert(buffer.handle.read(cx).remote_id())
1499 });
1500 })?;
1501
1502 let _cleanup = defer({
1503 let this = lsp_store.clone();
1504 let mut cx = cx.clone();
1505 let buffers = &buffers;
1506 move || {
1507 this.update(&mut cx, |this, cx| {
1508 let this = this.as_local_mut().unwrap();
1509 for buffer in buffers {
1510 this.buffers_being_formatted
1511 .remove(&buffer.handle.read(cx).remote_id());
1512 }
1513 })
1514 .ok();
1515 }
1516 });
1517
1518 let mut project_transaction = ProjectTransaction::default();
1519
1520 for buffer in &buffers {
1521 zlog::debug!(
1522 logger =>
1523 "formatting buffer '{:?}'",
1524 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1525 );
1526 // Create an empty transaction to hold all of the formatting edits.
1527 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1528 // ensure no transactions created while formatting are
1529 // grouped with the previous transaction in the history
1530 // based on the transaction group interval
1531 buffer.finalize_last_transaction();
1532 buffer
1533 .start_transaction()
1534 .context("transaction already open")?;
1535 buffer.end_transaction(cx);
1536 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1537 buffer.finalize_last_transaction();
1538 anyhow::Ok(transaction_id)
1539 })?;
1540
1541 let result = Self::format_buffer_locally(
1542 lsp_store.clone(),
1543 buffer,
1544 formatting_transaction_id,
1545 trigger,
1546 logger,
1547 cx,
1548 )
1549 .await;
1550
1551 buffer.handle.update(cx, |buffer, cx| {
1552 let Some(formatting_transaction) =
1553 buffer.get_transaction(formatting_transaction_id).cloned()
1554 else {
1555 zlog::warn!(logger => "no formatting transaction");
1556 return;
1557 };
1558 if formatting_transaction.edit_ids.is_empty() {
1559 zlog::debug!(logger => "no changes made while formatting");
1560 buffer.forget_transaction(formatting_transaction_id);
1561 return;
1562 }
1563 if !push_to_history {
1564 zlog::trace!(logger => "forgetting format transaction");
1565 buffer.forget_transaction(formatting_transaction.id);
1566 }
1567 project_transaction
1568 .0
1569 .insert(cx.entity(), formatting_transaction);
1570 });
1571
1572 result?;
1573 }
1574
1575 Ok(project_transaction)
1576 }
1577
1578 async fn format_buffer_locally(
1579 lsp_store: WeakEntity<LspStore>,
1580 buffer: &FormattableBuffer,
1581 formatting_transaction_id: clock::Lamport,
1582 trigger: FormatTrigger,
1583 logger: zlog::Logger,
1584 cx: &mut AsyncApp,
1585 ) -> Result<()> {
1586 let (adapters_and_servers, settings, request_timeout) =
1587 lsp_store.update(cx, |lsp_store, cx| {
1588 buffer.handle.update(cx, |buffer, cx| {
1589 let adapters_and_servers = lsp_store
1590 .as_local()
1591 .unwrap()
1592 .language_servers_for_buffer(buffer, cx)
1593 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1594 .collect::<Vec<_>>();
1595 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1596 let request_timeout = ProjectSettings::get_global(cx)
1597 .global_lsp_settings
1598 .get_request_timeout();
1599 (adapters_and_servers, settings, request_timeout)
1600 })
1601 })?;
1602
1603 // handle whitespace formatting
1604 if settings.remove_trailing_whitespace_on_save {
1605 zlog::trace!(logger => "removing trailing whitespace");
1606 let diff = buffer
1607 .handle
1608 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1609 .await;
1610 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1611 buffer.apply_diff(diff, cx);
1612 })?;
1613 }
1614
1615 if settings.ensure_final_newline_on_save {
1616 zlog::trace!(logger => "ensuring final newline");
1617 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1618 buffer.ensure_final_newline(cx);
1619 })?;
1620 }
1621
1622 // Formatter for `code_actions_on_format` that runs before
1623 // the rest of the formatters
1624 let mut code_actions_on_format_formatters = None;
1625 let should_run_code_actions_on_format = !matches!(
1626 (trigger, &settings.format_on_save),
1627 (FormatTrigger::Save, &FormatOnSave::Off)
1628 );
1629 if should_run_code_actions_on_format {
1630 let have_code_actions_to_run_on_format = settings
1631 .code_actions_on_format
1632 .values()
1633 .any(|enabled| *enabled);
1634 if have_code_actions_to_run_on_format {
1635 zlog::trace!(logger => "going to run code actions on format");
1636 code_actions_on_format_formatters = Some(
1637 settings
1638 .code_actions_on_format
1639 .iter()
1640 .filter_map(|(action, enabled)| enabled.then_some(action))
1641 .cloned()
1642 .map(Formatter::CodeAction)
1643 .collect::<Vec<_>>(),
1644 );
1645 }
1646 }
1647
1648 let formatters = match (trigger, &settings.format_on_save) {
1649 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1650 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1651 settings.formatter.as_ref()
1652 }
1653 };
1654
1655 let formatters = code_actions_on_format_formatters
1656 .iter()
1657 .flatten()
1658 .chain(formatters);
1659
1660 for formatter in formatters {
1661 let formatter = if formatter == &Formatter::Auto {
1662 if settings.prettier.allowed {
1663 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1664 &Formatter::Prettier
1665 } else {
1666 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1667 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1668 }
1669 } else {
1670 formatter
1671 };
1672 if let Err(err) = Self::apply_formatter(
1673 formatter,
1674 &lsp_store,
1675 buffer,
1676 formatting_transaction_id,
1677 &adapters_and_servers,
1678 &settings,
1679 request_timeout,
1680 logger,
1681 cx,
1682 )
1683 .await
1684 {
1685 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1686 }
1687 }
1688
1689 Ok(())
1690 }
1691
1692 async fn apply_formatter(
1693 formatter: &Formatter,
1694 lsp_store: &WeakEntity<LspStore>,
1695 buffer: &FormattableBuffer,
1696 formatting_transaction_id: clock::Lamport,
1697 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1698 settings: &LanguageSettings,
1699 request_timeout: Duration,
1700 logger: zlog::Logger,
1701 cx: &mut AsyncApp,
1702 ) -> anyhow::Result<()> {
1703 match formatter {
1704 Formatter::None => {
1705 zlog::trace!(logger => "skipping formatter 'none'");
1706 return Ok(());
1707 }
1708 Formatter::Auto => {
1709 debug_panic!("Auto resolved above");
1710 return Ok(());
1711 }
1712 Formatter::Prettier => {
1713 let logger = zlog::scoped!(logger => "prettier");
1714 zlog::trace!(logger => "formatting");
1715 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1716
1717 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1718 lsp_store.prettier_store().unwrap().downgrade()
1719 })?;
1720 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1721 .await
1722 .transpose()?;
1723 let Some(diff) = diff else {
1724 zlog::trace!(logger => "No changes");
1725 return Ok(());
1726 };
1727
1728 extend_formatting_transaction(
1729 buffer,
1730 formatting_transaction_id,
1731 cx,
1732 |buffer, cx| {
1733 buffer.apply_diff(diff, cx);
1734 },
1735 )?;
1736 }
1737 Formatter::External { command, arguments } => {
1738 let logger = zlog::scoped!(logger => "command");
1739 zlog::trace!(logger => "formatting");
1740 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1741
1742 let diff =
1743 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1744 .await
1745 .with_context(|| {
1746 format!("Failed to format buffer via external command: {}", command)
1747 })?;
1748 let Some(diff) = diff else {
1749 zlog::trace!(logger => "No changes");
1750 return Ok(());
1751 };
1752
1753 extend_formatting_transaction(
1754 buffer,
1755 formatting_transaction_id,
1756 cx,
1757 |buffer, cx| {
1758 buffer.apply_diff(diff, cx);
1759 },
1760 )?;
1761 }
1762 Formatter::LanguageServer(specifier) => {
1763 let logger = zlog::scoped!(logger => "language-server");
1764 zlog::trace!(logger => "formatting");
1765 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1766
1767 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1768 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1769 return Ok(());
1770 };
1771
1772 let language_server = match specifier {
1773 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1774 adapters_and_servers.iter().find_map(|(adapter, server)| {
1775 if adapter.name.0.as_ref() == name {
1776 Some(server.clone())
1777 } else {
1778 None
1779 }
1780 })
1781 }
1782 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1783 .iter()
1784 .find(|(_, server)| Self::server_supports_formatting(server))
1785 .map(|(_, server)| server.clone()),
1786 };
1787
1788 let Some(language_server) = language_server else {
1789 log::debug!(
1790 "No language server found to format buffer '{:?}'. Skipping",
1791 buffer_path_abs.as_path().to_string_lossy()
1792 );
1793 return Ok(());
1794 };
1795
1796 zlog::trace!(
1797 logger =>
1798 "Formatting buffer '{:?}' using language server '{:?}'",
1799 buffer_path_abs.as_path().to_string_lossy(),
1800 language_server.name()
1801 );
1802
1803 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1804 zlog::trace!(logger => "formatting ranges");
1805 Self::format_ranges_via_lsp(
1806 &lsp_store,
1807 &buffer.handle,
1808 ranges,
1809 buffer_path_abs,
1810 &language_server,
1811 &settings,
1812 cx,
1813 )
1814 .await
1815 .context("Failed to format ranges via language server")?
1816 } else {
1817 zlog::trace!(logger => "formatting full");
1818 Self::format_via_lsp(
1819 &lsp_store,
1820 &buffer.handle,
1821 buffer_path_abs,
1822 &language_server,
1823 &settings,
1824 cx,
1825 )
1826 .await
1827 .context("failed to format via language server")?
1828 };
1829
1830 if edits.is_empty() {
1831 zlog::trace!(logger => "No changes");
1832 return Ok(());
1833 }
1834 extend_formatting_transaction(
1835 buffer,
1836 formatting_transaction_id,
1837 cx,
1838 |buffer, cx| {
1839 buffer.edit(edits, None, cx);
1840 },
1841 )?;
1842 }
1843 Formatter::CodeAction(code_action_name) => {
1844 let logger = zlog::scoped!(logger => "code-actions");
1845 zlog::trace!(logger => "formatting");
1846 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1847
1848 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1849 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1850 return Ok(());
1851 };
1852
1853 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1854 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1855
1856 let mut actions_and_servers = Vec::new();
1857
1858 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1859 let actions_result = Self::get_server_code_actions_from_action_kinds(
1860 &lsp_store,
1861 language_server.server_id(),
1862 vec![code_action_kind.clone()],
1863 &buffer.handle,
1864 cx,
1865 )
1866 .await
1867 .with_context(|| {
1868 format!(
1869 "Failed to resolve code action {:?} with language server {}",
1870 code_action_kind,
1871 language_server.name()
1872 )
1873 });
1874 let Ok(actions) = actions_result else {
1875 // note: it may be better to set result to the error and break formatters here
1876 // but for now we try to execute the actions that we can resolve and skip the rest
1877 zlog::error!(
1878 logger =>
1879 "Failed to resolve code action {:?} with language server {}",
1880 code_action_kind,
1881 language_server.name()
1882 );
1883 continue;
1884 };
1885 for action in actions {
1886 actions_and_servers.push((action, index));
1887 }
1888 }
1889
1890 if actions_and_servers.is_empty() {
1891 zlog::warn!(logger => "No code actions were resolved, continuing");
1892 return Ok(());
1893 }
1894
1895 'actions: for (mut action, server_index) in actions_and_servers {
1896 let server = &adapters_and_servers[server_index].1;
1897
1898 let describe_code_action = |action: &CodeAction| {
1899 format!(
1900 "code action '{}' with title \"{}\" on server {}",
1901 action
1902 .lsp_action
1903 .action_kind()
1904 .unwrap_or("unknown".into())
1905 .as_str(),
1906 action.lsp_action.title(),
1907 server.name(),
1908 )
1909 };
1910
1911 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1912
1913 if let Err(err) =
1914 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1915 {
1916 zlog::error!(
1917 logger =>
1918 "Failed to resolve {}. Error: {}",
1919 describe_code_action(&action),
1920 err
1921 );
1922 continue;
1923 }
1924
1925 if let Some(edit) = action.lsp_action.edit().cloned() {
1926 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1927 // but filters out and logs warnings for code actions that require unreasonably
1928 // difficult handling on our part, such as:
1929 // - applying edits that call commands
1930 // which can result in arbitrary workspace edits being sent from the server that
1931 // have no way of being tied back to the command that initiated them (i.e. we
1932 // can't know which edits are part of the format request, or if the server is done sending
1933 // actions in response to the command)
1934 // - actions that create/delete/modify/rename files other than the one we are formatting
1935 // as we then would need to handle such changes correctly in the local history as well
1936 // as the remote history through the ProjectTransaction
1937 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1938 // Supporting these actions is not impossible, but not supported as of yet.
1939 if edit.changes.is_none() && edit.document_changes.is_none() {
1940 zlog::trace!(
1941 logger =>
1942 "No changes for code action. Skipping {}",
1943 describe_code_action(&action),
1944 );
1945 continue;
1946 }
1947
1948 let mut operations = Vec::new();
1949 if let Some(document_changes) = edit.document_changes {
1950 match document_changes {
1951 lsp::DocumentChanges::Edits(edits) => operations.extend(
1952 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1953 ),
1954 lsp::DocumentChanges::Operations(ops) => operations = ops,
1955 }
1956 } else if let Some(changes) = edit.changes {
1957 operations.extend(changes.into_iter().map(|(uri, edits)| {
1958 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1959 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
1960 uri,
1961 version: None,
1962 },
1963 edits: edits.into_iter().map(Edit::Plain).collect(),
1964 })
1965 }));
1966 }
1967
1968 let mut edits = Vec::with_capacity(operations.len());
1969
1970 if operations.is_empty() {
1971 zlog::trace!(
1972 logger =>
1973 "No changes for code action. Skipping {}",
1974 describe_code_action(&action),
1975 );
1976 continue;
1977 }
1978 for operation in operations {
1979 let op = match operation {
1980 lsp::DocumentChangeOperation::Edit(op) => op,
1981 lsp::DocumentChangeOperation::Op(_) => {
1982 zlog::warn!(
1983 logger =>
1984 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1985 describe_code_action(&action),
1986 );
1987 continue 'actions;
1988 }
1989 };
1990 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1991 zlog::warn!(
1992 logger =>
1993 "Failed to convert URI '{:?}' to file path. Skipping {}",
1994 &op.text_document.uri,
1995 describe_code_action(&action),
1996 );
1997 continue 'actions;
1998 };
1999 if &file_path != buffer_path_abs {
2000 zlog::warn!(
2001 logger =>
2002 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2003 file_path,
2004 buffer_path_abs,
2005 describe_code_action(&action),
2006 );
2007 continue 'actions;
2008 }
2009
2010 let mut lsp_edits = Vec::new();
2011 for edit in op.edits {
2012 match edit {
2013 Edit::Plain(edit) => {
2014 if !lsp_edits.contains(&edit) {
2015 lsp_edits.push(edit);
2016 }
2017 }
2018 Edit::Annotated(edit) => {
2019 if !lsp_edits.contains(&edit.text_edit) {
2020 lsp_edits.push(edit.text_edit);
2021 }
2022 }
2023 Edit::Snippet(_) => {
2024 zlog::warn!(
2025 logger =>
2026 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2027 describe_code_action(&action),
2028 );
2029 continue 'actions;
2030 }
2031 }
2032 }
2033 let edits_result = lsp_store
2034 .update(cx, |lsp_store, cx| {
2035 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2036 &buffer.handle,
2037 lsp_edits,
2038 server.server_id(),
2039 op.text_document.version,
2040 cx,
2041 )
2042 })?
2043 .await;
2044 let Ok(resolved_edits) = edits_result else {
2045 zlog::warn!(
2046 logger =>
2047 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2048 buffer_path_abs.as_path(),
2049 describe_code_action(&action),
2050 );
2051 continue 'actions;
2052 };
2053 edits.extend(resolved_edits);
2054 }
2055
2056 if edits.is_empty() {
2057 zlog::warn!(logger => "No edits resolved from LSP");
2058 continue;
2059 }
2060
2061 extend_formatting_transaction(
2062 buffer,
2063 formatting_transaction_id,
2064 cx,
2065 |buffer, cx| {
2066 zlog::info!(
2067 "Applying edits {edits:?}. Content: {:?}",
2068 buffer.text()
2069 );
2070 buffer.edit(edits, None, cx);
2071 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2072 },
2073 )?;
2074 }
2075
2076 let Some(command) = action.lsp_action.command() else {
2077 continue;
2078 };
2079
2080 zlog::warn!(
2081 logger =>
2082 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2083 &command.command,
2084 );
2085
2086 let server_capabilities = server.capabilities();
2087 let available_commands = server_capabilities
2088 .execute_command_provider
2089 .as_ref()
2090 .map(|options| options.commands.as_slice())
2091 .unwrap_or_default();
2092 if !available_commands.contains(&command.command) {
2093 zlog::warn!(
2094 logger =>
2095 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2096 command.command,
2097 server.name(),
2098 );
2099 continue;
2100 }
2101
2102 extend_formatting_transaction(
2103 buffer,
2104 formatting_transaction_id,
2105 cx,
2106 |_, _| {},
2107 )?;
2108 zlog::info!(logger => "Executing command {}", &command.command);
2109
2110 lsp_store.update(cx, |this, _| {
2111 this.as_local_mut()
2112 .unwrap()
2113 .last_workspace_edits_by_language_server
2114 .remove(&server.server_id());
2115 })?;
2116
2117 let execute_command_result = server
2118 .request::<lsp::request::ExecuteCommand>(
2119 lsp::ExecuteCommandParams {
2120 command: command.command.clone(),
2121 arguments: command.arguments.clone().unwrap_or_default(),
2122 ..Default::default()
2123 },
2124 request_timeout,
2125 )
2126 .await
2127 .into_response();
2128
2129 if execute_command_result.is_err() {
2130 zlog::error!(
2131 logger =>
2132 "Failed to execute command '{}' as part of {}",
2133 &command.command,
2134 describe_code_action(&action),
2135 );
2136 continue 'actions;
2137 }
2138
2139 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2140 this.as_local_mut()
2141 .unwrap()
2142 .last_workspace_edits_by_language_server
2143 .remove(&server.server_id())
2144 .unwrap_or_default()
2145 })?;
2146
2147 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2148 {
2149 zlog::trace!(
2150 logger =>
2151 "Successfully captured {} edits that resulted from command {}",
2152 transaction.edit_ids.len(),
2153 &command.command,
2154 );
2155 let transaction_id_project_transaction = transaction.id;
2156 buffer.handle.update(cx, |buffer, _| {
2157 // it may have been removed from history if push_to_history was
2158 // false in deserialize_workspace_edit. If so push it so we
2159 // can merge it with the format transaction
2160 // and pop the combined transaction off the history stack
2161 // later if push_to_history is false
2162 if buffer.get_transaction(transaction.id).is_none() {
2163 buffer.push_transaction(transaction, Instant::now());
2164 }
2165 buffer.merge_transactions(
2166 transaction_id_project_transaction,
2167 formatting_transaction_id,
2168 );
2169 });
2170 }
2171
2172 if project_transaction_command.0.is_empty() {
2173 continue;
2174 }
2175
2176 let mut extra_buffers = String::new();
2177 for buffer in project_transaction_command.0.keys() {
2178 buffer.read_with(cx, |b, cx| {
2179 let Some(path) = b.project_path(cx) else {
2180 return;
2181 };
2182
2183 if !extra_buffers.is_empty() {
2184 extra_buffers.push_str(", ");
2185 }
2186 extra_buffers.push_str(path.path.as_unix_str());
2187 });
2188 }
2189 zlog::warn!(
2190 logger =>
2191 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2192 &command.command,
2193 extra_buffers,
2194 );
2195 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2196 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2197 // add it so it's included, and merge it into the format transaction when its created later
2198 }
2199 }
2200 }
2201
2202 Ok(())
2203 }
2204
2205 pub async fn format_ranges_via_lsp(
2206 this: &WeakEntity<LspStore>,
2207 buffer_handle: &Entity<Buffer>,
2208 ranges: &[Range<Anchor>],
2209 abs_path: &Path,
2210 language_server: &Arc<LanguageServer>,
2211 settings: &LanguageSettings,
2212 cx: &mut AsyncApp,
2213 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2214 let capabilities = &language_server.capabilities();
2215 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2216 if range_formatting_provider == Some(&OneOf::Left(false)) {
2217 anyhow::bail!(
2218 "{} language server does not support range formatting",
2219 language_server.name()
2220 );
2221 }
2222
2223 let uri = file_path_to_lsp_url(abs_path)?;
2224 let text_document = lsp::TextDocumentIdentifier::new(uri);
2225
2226 let request_timeout = cx.update(|app| {
2227 ProjectSettings::get_global(app)
2228 .global_lsp_settings
2229 .get_request_timeout()
2230 });
2231 let lsp_edits = {
2232 let mut lsp_ranges = Vec::new();
2233 this.update(cx, |_this, cx| {
2234 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2235 // not have been sent to the language server. This seems like a fairly systemic
2236 // issue, though, the resolution probably is not specific to formatting.
2237 //
2238 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2239 // LSP.
2240 let snapshot = buffer_handle.read(cx).snapshot();
2241 for range in ranges {
2242 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2243 }
2244 anyhow::Ok(())
2245 })??;
2246
2247 let mut edits = None;
2248 for range in lsp_ranges {
2249 if let Some(mut edit) = language_server
2250 .request::<lsp::request::RangeFormatting>(
2251 lsp::DocumentRangeFormattingParams {
2252 text_document: text_document.clone(),
2253 range,
2254 options: lsp_command::lsp_formatting_options(settings),
2255 work_done_progress_params: Default::default(),
2256 },
2257 request_timeout,
2258 )
2259 .await
2260 .into_response()?
2261 {
2262 edits.get_or_insert_with(Vec::new).append(&mut edit);
2263 }
2264 }
2265 edits
2266 };
2267
2268 if let Some(lsp_edits) = lsp_edits {
2269 this.update(cx, |this, cx| {
2270 this.as_local_mut().unwrap().edits_from_lsp(
2271 buffer_handle,
2272 lsp_edits,
2273 language_server.server_id(),
2274 None,
2275 cx,
2276 )
2277 })?
2278 .await
2279 } else {
2280 Ok(Vec::with_capacity(0))
2281 }
2282 }
2283
2284 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2285 let capabilities = server.capabilities();
2286 let formatting = capabilities.document_formatting_provider.as_ref();
2287 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2288 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2289 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2290 }
2291
2292 async fn format_via_lsp(
2293 this: &WeakEntity<LspStore>,
2294 buffer: &Entity<Buffer>,
2295 abs_path: &Path,
2296 language_server: &Arc<LanguageServer>,
2297 settings: &LanguageSettings,
2298 cx: &mut AsyncApp,
2299 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2300 let logger = zlog::scoped!("lsp_format");
2301 zlog::debug!(logger => "Formatting via LSP");
2302
2303 let uri = file_path_to_lsp_url(abs_path)?;
2304 let text_document = lsp::TextDocumentIdentifier::new(uri);
2305 let capabilities = &language_server.capabilities();
2306
2307 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2308 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2309
2310 let request_timeout = cx.update(|app| {
2311 ProjectSettings::get_global(app)
2312 .global_lsp_settings
2313 .get_request_timeout()
2314 });
2315
2316 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2317 let _timer = zlog::time!(logger => "format-full");
2318 language_server
2319 .request::<lsp::request::Formatting>(
2320 lsp::DocumentFormattingParams {
2321 text_document,
2322 options: lsp_command::lsp_formatting_options(settings),
2323 work_done_progress_params: Default::default(),
2324 },
2325 request_timeout,
2326 )
2327 .await
2328 .into_response()?
2329 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2330 let _timer = zlog::time!(logger => "format-range");
2331 let buffer_start = lsp::Position::new(0, 0);
2332 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2333 language_server
2334 .request::<lsp::request::RangeFormatting>(
2335 lsp::DocumentRangeFormattingParams {
2336 text_document: text_document.clone(),
2337 range: lsp::Range::new(buffer_start, buffer_end),
2338 options: lsp_command::lsp_formatting_options(settings),
2339 work_done_progress_params: Default::default(),
2340 },
2341 request_timeout,
2342 )
2343 .await
2344 .into_response()?
2345 } else {
2346 None
2347 };
2348
2349 if let Some(lsp_edits) = lsp_edits {
2350 this.update(cx, |this, cx| {
2351 this.as_local_mut().unwrap().edits_from_lsp(
2352 buffer,
2353 lsp_edits,
2354 language_server.server_id(),
2355 None,
2356 cx,
2357 )
2358 })?
2359 .await
2360 } else {
2361 Ok(Vec::with_capacity(0))
2362 }
2363 }
2364
2365 async fn format_via_external_command(
2366 buffer: &FormattableBuffer,
2367 command: &str,
2368 arguments: Option<&[String]>,
2369 cx: &mut AsyncApp,
2370 ) -> Result<Option<Diff>> {
2371 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2372 let file = File::from_dyn(buffer.file())?;
2373 let worktree = file.worktree.read(cx);
2374 let mut worktree_path = worktree.abs_path().to_path_buf();
2375 if worktree.root_entry()?.is_file() {
2376 worktree_path.pop();
2377 }
2378 Some(worktree_path)
2379 });
2380
2381 use util::command::Stdio;
2382 let mut child = util::command::new_command(command);
2383
2384 if let Some(buffer_env) = buffer.env.as_ref() {
2385 child.envs(buffer_env);
2386 }
2387
2388 if let Some(working_dir_path) = working_dir_path {
2389 child.current_dir(working_dir_path);
2390 }
2391
2392 if let Some(arguments) = arguments {
2393 child.args(arguments.iter().map(|arg| {
2394 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2395 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2396 } else {
2397 arg.replace("{buffer_path}", "Untitled")
2398 }
2399 }));
2400 }
2401
2402 let mut child = child
2403 .stdin(Stdio::piped())
2404 .stdout(Stdio::piped())
2405 .stderr(Stdio::piped())
2406 .spawn()?;
2407
2408 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2409 let text = buffer
2410 .handle
2411 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2412 for chunk in text.chunks() {
2413 stdin.write_all(chunk.as_bytes()).await?;
2414 }
2415 stdin.flush().await?;
2416
2417 let output = child.output().await?;
2418 anyhow::ensure!(
2419 output.status.success(),
2420 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2421 output.status.code(),
2422 String::from_utf8_lossy(&output.stdout),
2423 String::from_utf8_lossy(&output.stderr),
2424 );
2425
2426 let stdout = String::from_utf8(output.stdout)?;
2427 Ok(Some(
2428 buffer
2429 .handle
2430 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2431 .await,
2432 ))
2433 }
2434
2435 async fn try_resolve_code_action(
2436 lang_server: &LanguageServer,
2437 action: &mut CodeAction,
2438 request_timeout: Duration,
2439 ) -> anyhow::Result<()> {
2440 match &mut action.lsp_action {
2441 LspAction::Action(lsp_action) => {
2442 if !action.resolved
2443 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2444 && lsp_action.data.is_some()
2445 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2446 {
2447 **lsp_action = lang_server
2448 .request::<lsp::request::CodeActionResolveRequest>(
2449 *lsp_action.clone(),
2450 request_timeout,
2451 )
2452 .await
2453 .into_response()?;
2454 }
2455 }
2456 LspAction::CodeLens(lens) => {
2457 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2458 *lens = lang_server
2459 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2460 .await
2461 .into_response()?;
2462 }
2463 }
2464 LspAction::Command(_) => {}
2465 }
2466
2467 action.resolved = true;
2468 anyhow::Ok(())
2469 }
2470
2471 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2472 let buffer = buffer_handle.read(cx);
2473
2474 let file = buffer.file().cloned();
2475
2476 let Some(file) = File::from_dyn(file.as_ref()) else {
2477 return;
2478 };
2479 if !file.is_local() {
2480 return;
2481 }
2482 let path = ProjectPath::from_file(file, cx);
2483 let worktree_id = file.worktree_id(cx);
2484 let language = buffer.language().cloned();
2485
2486 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2487 for (server_id, diagnostics) in
2488 diagnostics.get(file.path()).cloned().unwrap_or_default()
2489 {
2490 self.update_buffer_diagnostics(
2491 buffer_handle,
2492 server_id,
2493 None,
2494 None,
2495 None,
2496 Vec::new(),
2497 diagnostics,
2498 cx,
2499 )
2500 .log_err();
2501 }
2502 }
2503 let Some(language) = language else {
2504 return;
2505 };
2506 let Some(snapshot) = self
2507 .worktree_store
2508 .read(cx)
2509 .worktree_for_id(worktree_id, cx)
2510 .map(|worktree| worktree.read(cx).snapshot())
2511 else {
2512 return;
2513 };
2514 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2515
2516 for server_id in
2517 self.lsp_tree
2518 .get(path, language.name(), language.manifest(), &delegate, cx)
2519 {
2520 let server = self
2521 .language_servers
2522 .get(&server_id)
2523 .and_then(|server_state| {
2524 if let LanguageServerState::Running { server, .. } = server_state {
2525 Some(server.clone())
2526 } else {
2527 None
2528 }
2529 });
2530 let server = match server {
2531 Some(server) => server,
2532 None => continue,
2533 };
2534
2535 buffer_handle.update(cx, |buffer, cx| {
2536 buffer.set_completion_triggers(
2537 server.server_id(),
2538 server
2539 .capabilities()
2540 .completion_provider
2541 .as_ref()
2542 .and_then(|provider| {
2543 provider
2544 .trigger_characters
2545 .as_ref()
2546 .map(|characters| characters.iter().cloned().collect())
2547 })
2548 .unwrap_or_default(),
2549 cx,
2550 );
2551 });
2552 }
2553 }
2554
2555 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2556 buffer.update(cx, |buffer, cx| {
2557 let Some(language) = buffer.language() else {
2558 return;
2559 };
2560 let path = ProjectPath {
2561 worktree_id: old_file.worktree_id(cx),
2562 path: old_file.path.clone(),
2563 };
2564 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2565 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2566 buffer.set_completion_triggers(server_id, Default::default(), cx);
2567 }
2568 });
2569 }
2570
2571 fn update_buffer_diagnostics(
2572 &mut self,
2573 buffer: &Entity<Buffer>,
2574 server_id: LanguageServerId,
2575 registration_id: Option<Option<SharedString>>,
2576 result_id: Option<SharedString>,
2577 version: Option<i32>,
2578 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2579 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2580 cx: &mut Context<LspStore>,
2581 ) -> Result<()> {
2582 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2583 Ordering::Equal
2584 .then_with(|| b.is_primary.cmp(&a.is_primary))
2585 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2586 .then_with(|| a.severity.cmp(&b.severity))
2587 .then_with(|| a.message.cmp(&b.message))
2588 }
2589
2590 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2591 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2592 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2593
2594 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2595 Ordering::Equal
2596 .then_with(|| a.range.start.cmp(&b.range.start))
2597 .then_with(|| b.range.end.cmp(&a.range.end))
2598 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2599 });
2600
2601 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2602
2603 let edits_since_save = std::cell::LazyCell::new(|| {
2604 let saved_version = buffer.read(cx).saved_version();
2605 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2606 });
2607
2608 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2609
2610 for (new_diagnostic, entry) in diagnostics {
2611 let start;
2612 let end;
2613 if new_diagnostic && entry.diagnostic.is_disk_based {
2614 // Some diagnostics are based on files on disk instead of buffers'
2615 // current contents. Adjust these diagnostics' ranges to reflect
2616 // any unsaved edits.
2617 // Do not alter the reused ones though, as their coordinates were stored as anchors
2618 // and were properly adjusted on reuse.
2619 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2620 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2621 } else {
2622 start = entry.range.start;
2623 end = entry.range.end;
2624 }
2625
2626 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2627 ..snapshot.clip_point_utf16(end, Bias::Right);
2628
2629 // Expand empty ranges by one codepoint
2630 if range.start == range.end {
2631 // This will be go to the next boundary when being clipped
2632 range.end.column += 1;
2633 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2634 if range.start == range.end && range.end.column > 0 {
2635 range.start.column -= 1;
2636 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2637 }
2638 }
2639
2640 sanitized_diagnostics.push(DiagnosticEntry {
2641 range,
2642 diagnostic: entry.diagnostic,
2643 });
2644 }
2645 drop(edits_since_save);
2646
2647 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2648 buffer.update(cx, |buffer, cx| {
2649 if let Some(registration_id) = registration_id {
2650 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2651 self.buffer_pull_diagnostics_result_ids
2652 .entry(server_id)
2653 .or_default()
2654 .entry(registration_id)
2655 .or_default()
2656 .insert(abs_path, result_id);
2657 }
2658 }
2659
2660 buffer.update_diagnostics(server_id, set, cx)
2661 });
2662
2663 Ok(())
2664 }
2665
2666 fn register_language_server_for_invisible_worktree(
2667 &mut self,
2668 worktree: &Entity<Worktree>,
2669 language_server_id: LanguageServerId,
2670 cx: &mut App,
2671 ) {
2672 let worktree = worktree.read(cx);
2673 let worktree_id = worktree.id();
2674 debug_assert!(!worktree.is_visible());
2675 let Some(mut origin_seed) = self
2676 .language_server_ids
2677 .iter()
2678 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2679 else {
2680 return;
2681 };
2682 origin_seed.worktree_id = worktree_id;
2683 self.language_server_ids
2684 .entry(origin_seed)
2685 .or_insert_with(|| UnifiedLanguageServer {
2686 id: language_server_id,
2687 project_roots: Default::default(),
2688 });
2689 }
2690
2691 fn register_buffer_with_language_servers(
2692 &mut self,
2693 buffer_handle: &Entity<Buffer>,
2694 only_register_servers: HashSet<LanguageServerSelector>,
2695 cx: &mut Context<LspStore>,
2696 ) {
2697 let buffer = buffer_handle.read(cx);
2698 let buffer_id = buffer.remote_id();
2699
2700 let Some(file) = File::from_dyn(buffer.file()) else {
2701 return;
2702 };
2703 if !file.is_local() {
2704 return;
2705 }
2706
2707 let abs_path = file.abs_path(cx);
2708 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2709 return;
2710 };
2711 let initial_snapshot = buffer.text_snapshot();
2712 let worktree_id = file.worktree_id(cx);
2713
2714 let Some(language) = buffer.language().cloned() else {
2715 return;
2716 };
2717 let path: Arc<RelPath> = file
2718 .path()
2719 .parent()
2720 .map(Arc::from)
2721 .unwrap_or_else(|| file.path().clone());
2722 let Some(worktree) = self
2723 .worktree_store
2724 .read(cx)
2725 .worktree_for_id(worktree_id, cx)
2726 else {
2727 return;
2728 };
2729 let language_name = language.name();
2730 let (reused, delegate, servers) = self
2731 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2732 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2733 .unwrap_or_else(|| {
2734 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2735 let delegate: Arc<dyn ManifestDelegate> =
2736 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2737
2738 let servers = self
2739 .lsp_tree
2740 .walk(
2741 ProjectPath { worktree_id, path },
2742 language.name(),
2743 language.manifest(),
2744 &delegate,
2745 cx,
2746 )
2747 .collect::<Vec<_>>();
2748 (false, lsp_delegate, servers)
2749 });
2750 let servers_and_adapters = servers
2751 .into_iter()
2752 .filter_map(|server_node| {
2753 if reused && server_node.server_id().is_none() {
2754 return None;
2755 }
2756 if !only_register_servers.is_empty() {
2757 if let Some(server_id) = server_node.server_id()
2758 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2759 {
2760 return None;
2761 }
2762 if let Some(name) = server_node.name()
2763 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2764 {
2765 return None;
2766 }
2767 }
2768
2769 let server_id = server_node.server_id_or_init(|disposition| {
2770 let path = &disposition.path;
2771
2772 {
2773 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2774
2775 let server_id = self.get_or_insert_language_server(
2776 &worktree,
2777 delegate.clone(),
2778 disposition,
2779 &language_name,
2780 cx,
2781 );
2782
2783 if let Some(state) = self.language_servers.get(&server_id)
2784 && let Ok(uri) = uri
2785 {
2786 state.add_workspace_folder(uri);
2787 };
2788 server_id
2789 }
2790 })?;
2791 let server_state = self.language_servers.get(&server_id)?;
2792 if let LanguageServerState::Running {
2793 server, adapter, ..
2794 } = server_state
2795 {
2796 Some((server.clone(), adapter.clone()))
2797 } else {
2798 None
2799 }
2800 })
2801 .collect::<Vec<_>>();
2802 for (server, adapter) in servers_and_adapters {
2803 buffer_handle.update(cx, |buffer, cx| {
2804 buffer.set_completion_triggers(
2805 server.server_id(),
2806 server
2807 .capabilities()
2808 .completion_provider
2809 .as_ref()
2810 .and_then(|provider| {
2811 provider
2812 .trigger_characters
2813 .as_ref()
2814 .map(|characters| characters.iter().cloned().collect())
2815 })
2816 .unwrap_or_default(),
2817 cx,
2818 );
2819 });
2820
2821 let snapshot = LspBufferSnapshot {
2822 version: 0,
2823 snapshot: initial_snapshot.clone(),
2824 };
2825
2826 let mut registered = false;
2827 self.buffer_snapshots
2828 .entry(buffer_id)
2829 .or_default()
2830 .entry(server.server_id())
2831 .or_insert_with(|| {
2832 registered = true;
2833 server.register_buffer(
2834 uri.clone(),
2835 adapter.language_id(&language.name()),
2836 0,
2837 initial_snapshot.text(),
2838 );
2839
2840 vec![snapshot]
2841 });
2842
2843 self.buffers_opened_in_servers
2844 .entry(buffer_id)
2845 .or_default()
2846 .insert(server.server_id());
2847 if registered {
2848 cx.emit(LspStoreEvent::LanguageServerUpdate {
2849 language_server_id: server.server_id(),
2850 name: None,
2851 message: proto::update_language_server::Variant::RegisteredForBuffer(
2852 proto::RegisteredForBuffer {
2853 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2854 buffer_id: buffer_id.to_proto(),
2855 },
2856 ),
2857 });
2858 }
2859 }
2860 }
2861
2862 fn reuse_existing_language_server<'lang_name>(
2863 &self,
2864 server_tree: &LanguageServerTree,
2865 worktree: &Entity<Worktree>,
2866 language_name: &'lang_name LanguageName,
2867 cx: &mut App,
2868 ) -> Option<(
2869 Arc<LocalLspAdapterDelegate>,
2870 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2871 )> {
2872 if worktree.read(cx).is_visible() {
2873 return None;
2874 }
2875
2876 let worktree_store = self.worktree_store.read(cx);
2877 let servers = server_tree
2878 .instances
2879 .iter()
2880 .filter(|(worktree_id, _)| {
2881 worktree_store
2882 .worktree_for_id(**worktree_id, cx)
2883 .is_some_and(|worktree| worktree.read(cx).is_visible())
2884 })
2885 .flat_map(|(worktree_id, servers)| {
2886 servers
2887 .roots
2888 .iter()
2889 .flat_map(|(_, language_servers)| language_servers)
2890 .map(move |(_, (server_node, server_languages))| {
2891 (worktree_id, server_node, server_languages)
2892 })
2893 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2894 .map(|(worktree_id, server_node, _)| {
2895 (
2896 *worktree_id,
2897 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2898 )
2899 })
2900 })
2901 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2902 acc.entry(worktree_id)
2903 .or_insert_with(Vec::new)
2904 .push(server_node);
2905 acc
2906 })
2907 .into_values()
2908 .max_by_key(|servers| servers.len())?;
2909
2910 let worktree_id = worktree.read(cx).id();
2911 let apply = move |tree: &mut LanguageServerTree| {
2912 for server_node in &servers {
2913 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2914 }
2915 servers
2916 };
2917
2918 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2919 Some((delegate, apply))
2920 }
2921
2922 pub(crate) fn unregister_old_buffer_from_language_servers(
2923 &mut self,
2924 buffer: &Entity<Buffer>,
2925 old_file: &File,
2926 cx: &mut App,
2927 ) {
2928 let old_path = match old_file.as_local() {
2929 Some(local) => local.abs_path(cx),
2930 None => return,
2931 };
2932
2933 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2934 debug_panic!("{old_path:?} is not parseable as an URI");
2935 return;
2936 };
2937 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2938 }
2939
2940 pub(crate) fn unregister_buffer_from_language_servers(
2941 &mut self,
2942 buffer: &Entity<Buffer>,
2943 file_url: &lsp::Uri,
2944 cx: &mut App,
2945 ) {
2946 buffer.update(cx, |buffer, cx| {
2947 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2948
2949 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2950 if snapshots
2951 .as_mut()
2952 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2953 {
2954 language_server.unregister_buffer(file_url.clone());
2955 }
2956 }
2957 });
2958 }
2959
2960 fn buffer_snapshot_for_lsp_version(
2961 &mut self,
2962 buffer: &Entity<Buffer>,
2963 server_id: LanguageServerId,
2964 version: Option<i32>,
2965 cx: &App,
2966 ) -> Result<TextBufferSnapshot> {
2967 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2968
2969 if let Some(version) = version {
2970 let buffer_id = buffer.read(cx).remote_id();
2971 let snapshots = if let Some(snapshots) = self
2972 .buffer_snapshots
2973 .get_mut(&buffer_id)
2974 .and_then(|m| m.get_mut(&server_id))
2975 {
2976 snapshots
2977 } else if version == 0 {
2978 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2979 // We detect this case and treat it as if the version was `None`.
2980 return Ok(buffer.read(cx).text_snapshot());
2981 } else {
2982 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2983 };
2984
2985 let found_snapshot = snapshots
2986 .binary_search_by_key(&version, |e| e.version)
2987 .map(|ix| snapshots[ix].snapshot.clone())
2988 .map_err(|_| {
2989 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2990 })?;
2991
2992 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2993 Ok(found_snapshot)
2994 } else {
2995 Ok((buffer.read(cx)).text_snapshot())
2996 }
2997 }
2998
2999 async fn get_server_code_actions_from_action_kinds(
3000 lsp_store: &WeakEntity<LspStore>,
3001 language_server_id: LanguageServerId,
3002 code_action_kinds: Vec<lsp::CodeActionKind>,
3003 buffer: &Entity<Buffer>,
3004 cx: &mut AsyncApp,
3005 ) -> Result<Vec<CodeAction>> {
3006 let actions = lsp_store
3007 .update(cx, move |this, cx| {
3008 let request = GetCodeActions {
3009 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3010 kinds: Some(code_action_kinds),
3011 };
3012 let server = LanguageServerToQuery::Other(language_server_id);
3013 this.request_lsp(buffer.clone(), server, request, cx)
3014 })?
3015 .await?;
3016 Ok(actions)
3017 }
3018
3019 pub async fn execute_code_actions_on_server(
3020 lsp_store: &WeakEntity<LspStore>,
3021 language_server: &Arc<LanguageServer>,
3022 actions: Vec<CodeAction>,
3023 push_to_history: bool,
3024 project_transaction: &mut ProjectTransaction,
3025 cx: &mut AsyncApp,
3026 ) -> anyhow::Result<()> {
3027 let request_timeout = cx.update(|app| {
3028 ProjectSettings::get_global(app)
3029 .global_lsp_settings
3030 .get_request_timeout()
3031 });
3032
3033 for mut action in actions {
3034 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3035 .await
3036 .context("resolving a formatting code action")?;
3037
3038 if let Some(edit) = action.lsp_action.edit() {
3039 if edit.changes.is_none() && edit.document_changes.is_none() {
3040 continue;
3041 }
3042
3043 let new = Self::deserialize_workspace_edit(
3044 lsp_store.upgrade().context("project dropped")?,
3045 edit.clone(),
3046 push_to_history,
3047 language_server.clone(),
3048 cx,
3049 )
3050 .await?;
3051 project_transaction.0.extend(new.0);
3052 }
3053
3054 let Some(command) = action.lsp_action.command() else {
3055 continue;
3056 };
3057
3058 let server_capabilities = language_server.capabilities();
3059 let available_commands = server_capabilities
3060 .execute_command_provider
3061 .as_ref()
3062 .map(|options| options.commands.as_slice())
3063 .unwrap_or_default();
3064 if !available_commands.contains(&command.command) {
3065 log::warn!(
3066 "Cannot execute a command {} not listed in the language server capabilities",
3067 command.command
3068 );
3069 continue;
3070 }
3071
3072 lsp_store.update(cx, |lsp_store, _| {
3073 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3074 mode.last_workspace_edits_by_language_server
3075 .remove(&language_server.server_id());
3076 }
3077 })?;
3078
3079 language_server
3080 .request::<lsp::request::ExecuteCommand>(
3081 lsp::ExecuteCommandParams {
3082 command: command.command.clone(),
3083 arguments: command.arguments.clone().unwrap_or_default(),
3084 ..Default::default()
3085 },
3086 request_timeout,
3087 )
3088 .await
3089 .into_response()
3090 .context("execute command")?;
3091
3092 lsp_store.update(cx, |this, _| {
3093 if let LspStoreMode::Local(mode) = &mut this.mode {
3094 project_transaction.0.extend(
3095 mode.last_workspace_edits_by_language_server
3096 .remove(&language_server.server_id())
3097 .unwrap_or_default()
3098 .0,
3099 )
3100 }
3101 })?;
3102 }
3103 Ok(())
3104 }
3105
3106 pub async fn deserialize_text_edits(
3107 this: Entity<LspStore>,
3108 buffer_to_edit: Entity<Buffer>,
3109 edits: Vec<lsp::TextEdit>,
3110 push_to_history: bool,
3111 _: Arc<CachedLspAdapter>,
3112 language_server: Arc<LanguageServer>,
3113 cx: &mut AsyncApp,
3114 ) -> Result<Option<Transaction>> {
3115 let edits = this
3116 .update(cx, |this, cx| {
3117 this.as_local_mut().unwrap().edits_from_lsp(
3118 &buffer_to_edit,
3119 edits,
3120 language_server.server_id(),
3121 None,
3122 cx,
3123 )
3124 })
3125 .await?;
3126
3127 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3128 buffer.finalize_last_transaction();
3129 buffer.start_transaction();
3130 for (range, text) in edits {
3131 buffer.edit([(range, text)], None, cx);
3132 }
3133
3134 if buffer.end_transaction(cx).is_some() {
3135 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3136 if !push_to_history {
3137 buffer.forget_transaction(transaction.id);
3138 }
3139 Some(transaction)
3140 } else {
3141 None
3142 }
3143 });
3144
3145 Ok(transaction)
3146 }
3147
3148 #[allow(clippy::type_complexity)]
3149 pub fn edits_from_lsp(
3150 &mut self,
3151 buffer: &Entity<Buffer>,
3152 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3153 server_id: LanguageServerId,
3154 version: Option<i32>,
3155 cx: &mut Context<LspStore>,
3156 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3157 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3158 cx.background_spawn(async move {
3159 let snapshot = snapshot?;
3160 let mut lsp_edits = lsp_edits
3161 .into_iter()
3162 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3163 .collect::<Vec<_>>();
3164
3165 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3166
3167 let mut lsp_edits = lsp_edits.into_iter().peekable();
3168 let mut edits = Vec::new();
3169 while let Some((range, mut new_text)) = lsp_edits.next() {
3170 // Clip invalid ranges provided by the language server.
3171 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3172 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3173
3174 // Combine any LSP edits that are adjacent.
3175 //
3176 // Also, combine LSP edits that are separated from each other by only
3177 // a newline. This is important because for some code actions,
3178 // Rust-analyzer rewrites the entire buffer via a series of edits that
3179 // are separated by unchanged newline characters.
3180 //
3181 // In order for the diffing logic below to work properly, any edits that
3182 // cancel each other out must be combined into one.
3183 while let Some((next_range, next_text)) = lsp_edits.peek() {
3184 if next_range.start.0 > range.end {
3185 if next_range.start.0.row > range.end.row + 1
3186 || next_range.start.0.column > 0
3187 || snapshot.clip_point_utf16(
3188 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3189 Bias::Left,
3190 ) > range.end
3191 {
3192 break;
3193 }
3194 new_text.push('\n');
3195 }
3196 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3197 new_text.push_str(next_text);
3198 lsp_edits.next();
3199 }
3200
3201 // For multiline edits, perform a diff of the old and new text so that
3202 // we can identify the changes more precisely, preserving the locations
3203 // of any anchors positioned in the unchanged regions.
3204 if range.end.row > range.start.row {
3205 let offset = range.start.to_offset(&snapshot);
3206 let old_text = snapshot.text_for_range(range).collect::<String>();
3207 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3208 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3209 (
3210 snapshot.anchor_after(offset + range.start)
3211 ..snapshot.anchor_before(offset + range.end),
3212 replacement,
3213 )
3214 }));
3215 } else if range.end == range.start {
3216 let anchor = snapshot.anchor_after(range.start);
3217 edits.push((anchor..anchor, new_text.into()));
3218 } else {
3219 let edit_start = snapshot.anchor_after(range.start);
3220 let edit_end = snapshot.anchor_before(range.end);
3221 edits.push((edit_start..edit_end, new_text.into()));
3222 }
3223 }
3224
3225 Ok(edits)
3226 })
3227 }
3228
3229 pub(crate) async fn deserialize_workspace_edit(
3230 this: Entity<LspStore>,
3231 edit: lsp::WorkspaceEdit,
3232 push_to_history: bool,
3233 language_server: Arc<LanguageServer>,
3234 cx: &mut AsyncApp,
3235 ) -> Result<ProjectTransaction> {
3236 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3237
3238 let mut operations = Vec::new();
3239 if let Some(document_changes) = edit.document_changes {
3240 match document_changes {
3241 lsp::DocumentChanges::Edits(edits) => {
3242 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3243 }
3244 lsp::DocumentChanges::Operations(ops) => operations = ops,
3245 }
3246 } else if let Some(changes) = edit.changes {
3247 operations.extend(changes.into_iter().map(|(uri, edits)| {
3248 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3249 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3250 uri,
3251 version: None,
3252 },
3253 edits: edits.into_iter().map(Edit::Plain).collect(),
3254 })
3255 }));
3256 }
3257
3258 let mut project_transaction = ProjectTransaction::default();
3259 for operation in operations {
3260 match operation {
3261 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3262 let abs_path = op
3263 .uri
3264 .to_file_path()
3265 .map_err(|()| anyhow!("can't convert URI to path"))?;
3266
3267 if let Some(parent_path) = abs_path.parent() {
3268 fs.create_dir(parent_path).await?;
3269 }
3270 if abs_path.ends_with("/") {
3271 fs.create_dir(&abs_path).await?;
3272 } else {
3273 fs.create_file(
3274 &abs_path,
3275 op.options
3276 .map(|options| fs::CreateOptions {
3277 overwrite: options.overwrite.unwrap_or(false),
3278 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3279 })
3280 .unwrap_or_default(),
3281 )
3282 .await?;
3283 }
3284 }
3285
3286 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3287 let source_abs_path = op
3288 .old_uri
3289 .to_file_path()
3290 .map_err(|()| anyhow!("can't convert URI to path"))?;
3291 let target_abs_path = op
3292 .new_uri
3293 .to_file_path()
3294 .map_err(|()| anyhow!("can't convert URI to path"))?;
3295
3296 let options = fs::RenameOptions {
3297 overwrite: op
3298 .options
3299 .as_ref()
3300 .and_then(|options| options.overwrite)
3301 .unwrap_or(false),
3302 ignore_if_exists: op
3303 .options
3304 .as_ref()
3305 .and_then(|options| options.ignore_if_exists)
3306 .unwrap_or(false),
3307 create_parents: true,
3308 };
3309
3310 fs.rename(&source_abs_path, &target_abs_path, options)
3311 .await?;
3312 }
3313
3314 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3315 let abs_path = op
3316 .uri
3317 .to_file_path()
3318 .map_err(|()| anyhow!("can't convert URI to path"))?;
3319 let options = op
3320 .options
3321 .map(|options| fs::RemoveOptions {
3322 recursive: options.recursive.unwrap_or(false),
3323 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3324 })
3325 .unwrap_or_default();
3326 if abs_path.ends_with("/") {
3327 fs.remove_dir(&abs_path, options).await?;
3328 } else {
3329 fs.remove_file(&abs_path, options).await?;
3330 }
3331 }
3332
3333 lsp::DocumentChangeOperation::Edit(op) => {
3334 let buffer_to_edit = this
3335 .update(cx, |this, cx| {
3336 this.open_local_buffer_via_lsp(
3337 op.text_document.uri.clone(),
3338 language_server.server_id(),
3339 cx,
3340 )
3341 })
3342 .await?;
3343
3344 let edits = this
3345 .update(cx, |this, cx| {
3346 let path = buffer_to_edit.read(cx).project_path(cx);
3347 let active_entry = this.active_entry;
3348 let is_active_entry = path.is_some_and(|project_path| {
3349 this.worktree_store
3350 .read(cx)
3351 .entry_for_path(&project_path, cx)
3352 .is_some_and(|entry| Some(entry.id) == active_entry)
3353 });
3354 let local = this.as_local_mut().unwrap();
3355
3356 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3357 for edit in op.edits {
3358 match edit {
3359 Edit::Plain(edit) => {
3360 if !edits.contains(&edit) {
3361 edits.push(edit)
3362 }
3363 }
3364 Edit::Annotated(edit) => {
3365 if !edits.contains(&edit.text_edit) {
3366 edits.push(edit.text_edit)
3367 }
3368 }
3369 Edit::Snippet(edit) => {
3370 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3371 else {
3372 continue;
3373 };
3374
3375 if is_active_entry {
3376 snippet_edits.push((edit.range, snippet));
3377 } else {
3378 // Since this buffer is not focused, apply a normal edit.
3379 let new_edit = TextEdit {
3380 range: edit.range,
3381 new_text: snippet.text,
3382 };
3383 if !edits.contains(&new_edit) {
3384 edits.push(new_edit);
3385 }
3386 }
3387 }
3388 }
3389 }
3390 if !snippet_edits.is_empty() {
3391 let buffer_id = buffer_to_edit.read(cx).remote_id();
3392 let version = if let Some(buffer_version) = op.text_document.version
3393 {
3394 local
3395 .buffer_snapshot_for_lsp_version(
3396 &buffer_to_edit,
3397 language_server.server_id(),
3398 Some(buffer_version),
3399 cx,
3400 )
3401 .ok()
3402 .map(|snapshot| snapshot.version)
3403 } else {
3404 Some(buffer_to_edit.read(cx).saved_version().clone())
3405 };
3406
3407 let most_recent_edit =
3408 version.and_then(|version| version.most_recent());
3409 // Check if the edit that triggered that edit has been made by this participant.
3410
3411 if let Some(most_recent_edit) = most_recent_edit {
3412 cx.emit(LspStoreEvent::SnippetEdit {
3413 buffer_id,
3414 edits: snippet_edits,
3415 most_recent_edit,
3416 });
3417 }
3418 }
3419
3420 local.edits_from_lsp(
3421 &buffer_to_edit,
3422 edits,
3423 language_server.server_id(),
3424 op.text_document.version,
3425 cx,
3426 )
3427 })
3428 .await?;
3429
3430 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3431 buffer.finalize_last_transaction();
3432 buffer.start_transaction();
3433 for (range, text) in edits {
3434 buffer.edit([(range, text)], None, cx);
3435 }
3436
3437 buffer.end_transaction(cx).and_then(|transaction_id| {
3438 if push_to_history {
3439 buffer.finalize_last_transaction();
3440 buffer.get_transaction(transaction_id).cloned()
3441 } else {
3442 buffer.forget_transaction(transaction_id)
3443 }
3444 })
3445 });
3446 if let Some(transaction) = transaction {
3447 project_transaction.0.insert(buffer_to_edit, transaction);
3448 }
3449 }
3450 }
3451 }
3452
3453 Ok(project_transaction)
3454 }
3455
3456 async fn on_lsp_workspace_edit(
3457 this: WeakEntity<LspStore>,
3458 params: lsp::ApplyWorkspaceEditParams,
3459 server_id: LanguageServerId,
3460 cx: &mut AsyncApp,
3461 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3462 let this = this.upgrade().context("project project closed")?;
3463 let language_server = this
3464 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3465 .context("language server not found")?;
3466 let transaction = Self::deserialize_workspace_edit(
3467 this.clone(),
3468 params.edit,
3469 true,
3470 language_server.clone(),
3471 cx,
3472 )
3473 .await
3474 .log_err();
3475 this.update(cx, |this, cx| {
3476 if let Some(transaction) = transaction {
3477 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3478
3479 this.as_local_mut()
3480 .unwrap()
3481 .last_workspace_edits_by_language_server
3482 .insert(server_id, transaction);
3483 }
3484 });
3485 Ok(lsp::ApplyWorkspaceEditResponse {
3486 applied: true,
3487 failed_change: None,
3488 failure_reason: None,
3489 })
3490 }
3491
3492 fn remove_worktree(
3493 &mut self,
3494 id_to_remove: WorktreeId,
3495 cx: &mut Context<LspStore>,
3496 ) -> Vec<LanguageServerId> {
3497 self.restricted_worktrees_tasks.remove(&id_to_remove);
3498 self.diagnostics.remove(&id_to_remove);
3499 self.prettier_store.update(cx, |prettier_store, cx| {
3500 prettier_store.remove_worktree(id_to_remove, cx);
3501 });
3502
3503 let mut servers_to_remove = BTreeSet::default();
3504 let mut servers_to_preserve = HashSet::default();
3505 for (seed, state) in &self.language_server_ids {
3506 if seed.worktree_id == id_to_remove {
3507 servers_to_remove.insert(state.id);
3508 } else {
3509 servers_to_preserve.insert(state.id);
3510 }
3511 }
3512 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3513 self.language_server_ids
3514 .retain(|_, state| !servers_to_remove.contains(&state.id));
3515 for server_id_to_remove in &servers_to_remove {
3516 self.language_server_watched_paths
3517 .remove(server_id_to_remove);
3518 self.language_server_paths_watched_for_rename
3519 .remove(server_id_to_remove);
3520 self.last_workspace_edits_by_language_server
3521 .remove(server_id_to_remove);
3522 self.language_servers.remove(server_id_to_remove);
3523 self.buffer_pull_diagnostics_result_ids
3524 .remove(server_id_to_remove);
3525 self.workspace_pull_diagnostics_result_ids
3526 .remove(server_id_to_remove);
3527 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3528 buffer_servers.remove(server_id_to_remove);
3529 }
3530 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3531 }
3532 servers_to_remove.into_iter().collect()
3533 }
3534
3535 fn rebuild_watched_paths_inner<'a>(
3536 &'a self,
3537 language_server_id: LanguageServerId,
3538 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3539 cx: &mut Context<LspStore>,
3540 ) -> LanguageServerWatchedPathsBuilder {
3541 let worktrees = self
3542 .worktree_store
3543 .read(cx)
3544 .worktrees()
3545 .filter_map(|worktree| {
3546 self.language_servers_for_worktree(worktree.read(cx).id())
3547 .find(|server| server.server_id() == language_server_id)
3548 .map(|_| worktree)
3549 })
3550 .collect::<Vec<_>>();
3551
3552 let mut worktree_globs = HashMap::default();
3553 let mut abs_globs = HashMap::default();
3554 log::trace!(
3555 "Processing new watcher paths for language server with id {}",
3556 language_server_id
3557 );
3558
3559 for watcher in watchers {
3560 if let Some((worktree, literal_prefix, pattern)) =
3561 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3562 {
3563 worktree.update(cx, |worktree, _| {
3564 if let Some((tree, glob)) =
3565 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3566 {
3567 tree.add_path_prefix_to_scan(literal_prefix);
3568 worktree_globs
3569 .entry(tree.id())
3570 .or_insert_with(GlobSetBuilder::new)
3571 .add(glob);
3572 }
3573 });
3574 } else {
3575 let (path, pattern) = match &watcher.glob_pattern {
3576 lsp::GlobPattern::String(s) => {
3577 let watcher_path = SanitizedPath::new(s);
3578 let path = glob_literal_prefix(watcher_path.as_path());
3579 let pattern = watcher_path
3580 .as_path()
3581 .strip_prefix(&path)
3582 .map(|p| p.to_string_lossy().into_owned())
3583 .unwrap_or_else(|e| {
3584 debug_panic!(
3585 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3586 s,
3587 path.display(),
3588 e
3589 );
3590 watcher_path.as_path().to_string_lossy().into_owned()
3591 });
3592 (path, pattern)
3593 }
3594 lsp::GlobPattern::Relative(rp) => {
3595 let Ok(mut base_uri) = match &rp.base_uri {
3596 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3597 lsp::OneOf::Right(base_uri) => base_uri,
3598 }
3599 .to_file_path() else {
3600 continue;
3601 };
3602
3603 let path = glob_literal_prefix(Path::new(&rp.pattern));
3604 let pattern = Path::new(&rp.pattern)
3605 .strip_prefix(&path)
3606 .map(|p| p.to_string_lossy().into_owned())
3607 .unwrap_or_else(|e| {
3608 debug_panic!(
3609 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3610 rp.pattern,
3611 path.display(),
3612 e
3613 );
3614 rp.pattern.clone()
3615 });
3616 base_uri.push(path);
3617 (base_uri, pattern)
3618 }
3619 };
3620
3621 if let Some(glob) = Glob::new(&pattern).log_err() {
3622 if !path
3623 .components()
3624 .any(|c| matches!(c, path::Component::Normal(_)))
3625 {
3626 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3627 // rather than adding a new watcher for `/`.
3628 for worktree in &worktrees {
3629 worktree_globs
3630 .entry(worktree.read(cx).id())
3631 .or_insert_with(GlobSetBuilder::new)
3632 .add(glob.clone());
3633 }
3634 } else {
3635 abs_globs
3636 .entry(path.into())
3637 .or_insert_with(GlobSetBuilder::new)
3638 .add(glob);
3639 }
3640 }
3641 }
3642 }
3643
3644 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3645 for (worktree_id, builder) in worktree_globs {
3646 if let Ok(globset) = builder.build() {
3647 watch_builder.watch_worktree(worktree_id, globset);
3648 }
3649 }
3650 for (abs_path, builder) in abs_globs {
3651 if let Ok(globset) = builder.build() {
3652 watch_builder.watch_abs_path(abs_path, globset);
3653 }
3654 }
3655 watch_builder
3656 }
3657
3658 fn worktree_and_path_for_file_watcher(
3659 worktrees: &[Entity<Worktree>],
3660 watcher: &FileSystemWatcher,
3661 cx: &App,
3662 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3663 worktrees.iter().find_map(|worktree| {
3664 let tree = worktree.read(cx);
3665 let worktree_root_path = tree.abs_path();
3666 let path_style = tree.path_style();
3667 match &watcher.glob_pattern {
3668 lsp::GlobPattern::String(s) => {
3669 let watcher_path = SanitizedPath::new(s);
3670 let relative = watcher_path
3671 .as_path()
3672 .strip_prefix(&worktree_root_path)
3673 .ok()?;
3674 let literal_prefix = glob_literal_prefix(relative);
3675 Some((
3676 worktree.clone(),
3677 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3678 relative.to_string_lossy().into_owned(),
3679 ))
3680 }
3681 lsp::GlobPattern::Relative(rp) => {
3682 let base_uri = match &rp.base_uri {
3683 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3684 lsp::OneOf::Right(base_uri) => base_uri,
3685 }
3686 .to_file_path()
3687 .ok()?;
3688 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3689 let mut literal_prefix = relative.to_owned();
3690 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3691 Some((
3692 worktree.clone(),
3693 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3694 rp.pattern.clone(),
3695 ))
3696 }
3697 }
3698 })
3699 }
3700
3701 fn rebuild_watched_paths(
3702 &mut self,
3703 language_server_id: LanguageServerId,
3704 cx: &mut Context<LspStore>,
3705 ) {
3706 let Some(registrations) = self
3707 .language_server_dynamic_registrations
3708 .get(&language_server_id)
3709 else {
3710 return;
3711 };
3712
3713 let watch_builder = self.rebuild_watched_paths_inner(
3714 language_server_id,
3715 registrations.did_change_watched_files.values().flatten(),
3716 cx,
3717 );
3718 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3719 self.language_server_watched_paths
3720 .insert(language_server_id, watcher);
3721
3722 cx.notify();
3723 }
3724
3725 fn on_lsp_did_change_watched_files(
3726 &mut self,
3727 language_server_id: LanguageServerId,
3728 registration_id: &str,
3729 params: DidChangeWatchedFilesRegistrationOptions,
3730 cx: &mut Context<LspStore>,
3731 ) {
3732 let registrations = self
3733 .language_server_dynamic_registrations
3734 .entry(language_server_id)
3735 .or_default();
3736
3737 registrations
3738 .did_change_watched_files
3739 .insert(registration_id.to_string(), params.watchers);
3740
3741 self.rebuild_watched_paths(language_server_id, cx);
3742 }
3743
3744 fn on_lsp_unregister_did_change_watched_files(
3745 &mut self,
3746 language_server_id: LanguageServerId,
3747 registration_id: &str,
3748 cx: &mut Context<LspStore>,
3749 ) {
3750 let registrations = self
3751 .language_server_dynamic_registrations
3752 .entry(language_server_id)
3753 .or_default();
3754
3755 if registrations
3756 .did_change_watched_files
3757 .remove(registration_id)
3758 .is_some()
3759 {
3760 log::info!(
3761 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3762 language_server_id,
3763 registration_id
3764 );
3765 } else {
3766 log::warn!(
3767 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3768 language_server_id,
3769 registration_id
3770 );
3771 }
3772
3773 self.rebuild_watched_paths(language_server_id, cx);
3774 }
3775
3776 async fn initialization_options_for_adapter(
3777 adapter: Arc<dyn LspAdapter>,
3778 delegate: &Arc<dyn LspAdapterDelegate>,
3779 cx: &mut AsyncApp,
3780 ) -> Result<Option<serde_json::Value>> {
3781 let Some(mut initialization_config) =
3782 adapter.clone().initialization_options(delegate, cx).await?
3783 else {
3784 return Ok(None);
3785 };
3786
3787 for other_adapter in delegate.registered_lsp_adapters() {
3788 if other_adapter.name() == adapter.name() {
3789 continue;
3790 }
3791 if let Ok(Some(target_config)) = other_adapter
3792 .clone()
3793 .additional_initialization_options(adapter.name(), delegate)
3794 .await
3795 {
3796 merge_json_value_into(target_config.clone(), &mut initialization_config);
3797 }
3798 }
3799
3800 Ok(Some(initialization_config))
3801 }
3802
3803 async fn workspace_configuration_for_adapter(
3804 adapter: Arc<dyn LspAdapter>,
3805 delegate: &Arc<dyn LspAdapterDelegate>,
3806 toolchain: Option<Toolchain>,
3807 requested_uri: Option<Uri>,
3808 cx: &mut AsyncApp,
3809 ) -> Result<serde_json::Value> {
3810 let mut workspace_config = adapter
3811 .clone()
3812 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3813 .await?;
3814
3815 for other_adapter in delegate.registered_lsp_adapters() {
3816 if other_adapter.name() == adapter.name() {
3817 continue;
3818 }
3819 if let Ok(Some(target_config)) = other_adapter
3820 .clone()
3821 .additional_workspace_configuration(adapter.name(), delegate, cx)
3822 .await
3823 {
3824 merge_json_value_into(target_config.clone(), &mut workspace_config);
3825 }
3826 }
3827
3828 Ok(workspace_config)
3829 }
3830
3831 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3832 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3833 Some(server.clone())
3834 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3835 Some(Arc::clone(server))
3836 } else {
3837 None
3838 }
3839 }
3840}
3841
3842fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3843 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3844 cx.emit(LspStoreEvent::LanguageServerUpdate {
3845 language_server_id: server.server_id(),
3846 name: Some(server.name()),
3847 message: proto::update_language_server::Variant::MetadataUpdated(
3848 proto::ServerMetadataUpdated {
3849 capabilities: Some(capabilities),
3850 binary: Some(proto::LanguageServerBinaryInfo {
3851 path: server.binary().path.to_string_lossy().into_owned(),
3852 arguments: server
3853 .binary()
3854 .arguments
3855 .iter()
3856 .map(|arg| arg.to_string_lossy().into_owned())
3857 .collect(),
3858 }),
3859 configuration: serde_json::to_string(server.configuration()).ok(),
3860 workspace_folders: server
3861 .workspace_folders()
3862 .iter()
3863 .map(|uri| uri.to_string())
3864 .collect(),
3865 },
3866 ),
3867 });
3868 }
3869}
3870
3871#[derive(Debug)]
3872pub struct FormattableBuffer {
3873 handle: Entity<Buffer>,
3874 abs_path: Option<PathBuf>,
3875 env: Option<HashMap<String, String>>,
3876 ranges: Option<Vec<Range<Anchor>>>,
3877}
3878
3879pub struct RemoteLspStore {
3880 upstream_client: Option<AnyProtoClient>,
3881 upstream_project_id: u64,
3882}
3883
3884pub(crate) enum LspStoreMode {
3885 Local(LocalLspStore), // ssh host and collab host
3886 Remote(RemoteLspStore), // collab guest
3887}
3888
3889impl LspStoreMode {
3890 fn is_local(&self) -> bool {
3891 matches!(self, LspStoreMode::Local(_))
3892 }
3893}
3894
3895pub struct LspStore {
3896 mode: LspStoreMode,
3897 last_formatting_failure: Option<String>,
3898 downstream_client: Option<(AnyProtoClient, u64)>,
3899 nonce: u128,
3900 buffer_store: Entity<BufferStore>,
3901 worktree_store: Entity<WorktreeStore>,
3902 pub languages: Arc<LanguageRegistry>,
3903 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3904 active_entry: Option<ProjectEntryId>,
3905 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3906 _maintain_buffer_languages: Task<()>,
3907 diagnostic_summaries:
3908 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3909 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3910 semantic_token_config: SemanticTokenConfig,
3911 lsp_data: HashMap<BufferId, BufferLspData>,
3912 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3913 next_hint_id: Arc<AtomicUsize>,
3914}
3915
3916#[derive(Debug)]
3917pub struct BufferLspData {
3918 buffer_version: Global,
3919 document_colors: Option<DocumentColorData>,
3920 code_lens: Option<CodeLensData>,
3921 semantic_tokens: Option<SemanticTokensData>,
3922 folding_ranges: Option<FoldingRangeData>,
3923 document_symbols: Option<DocumentSymbolsData>,
3924 inlay_hints: BufferInlayHints,
3925 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3926 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3927}
3928
3929#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3930struct LspKey {
3931 request_type: TypeId,
3932 server_queried: Option<LanguageServerId>,
3933}
3934
3935impl BufferLspData {
3936 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3937 Self {
3938 buffer_version: buffer.read(cx).version(),
3939 document_colors: None,
3940 code_lens: None,
3941 semantic_tokens: None,
3942 folding_ranges: None,
3943 document_symbols: None,
3944 inlay_hints: BufferInlayHints::new(buffer, cx),
3945 lsp_requests: HashMap::default(),
3946 chunk_lsp_requests: HashMap::default(),
3947 }
3948 }
3949
3950 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3951 if let Some(document_colors) = &mut self.document_colors {
3952 document_colors.remove_server_data(for_server);
3953 }
3954
3955 if let Some(code_lens) = &mut self.code_lens {
3956 code_lens.remove_server_data(for_server);
3957 }
3958
3959 self.inlay_hints.remove_server_data(for_server);
3960
3961 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3962 semantic_tokens.remove_server_data(for_server);
3963 }
3964
3965 if let Some(folding_ranges) = &mut self.folding_ranges {
3966 folding_ranges.ranges.remove(&for_server);
3967 }
3968
3969 if let Some(document_symbols) = &mut self.document_symbols {
3970 document_symbols.remove_server_data(for_server);
3971 }
3972 }
3973
3974 #[cfg(any(test, feature = "test-support"))]
3975 pub fn inlay_hints(&self) -> &BufferInlayHints {
3976 &self.inlay_hints
3977 }
3978}
3979
3980#[derive(Debug)]
3981pub enum LspStoreEvent {
3982 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3983 LanguageServerRemoved(LanguageServerId),
3984 LanguageServerUpdate {
3985 language_server_id: LanguageServerId,
3986 name: Option<LanguageServerName>,
3987 message: proto::update_language_server::Variant,
3988 },
3989 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3990 LanguageServerPrompt(LanguageServerPromptRequest),
3991 LanguageDetected {
3992 buffer: Entity<Buffer>,
3993 new_language: Option<Arc<Language>>,
3994 },
3995 Notification(String),
3996 RefreshInlayHints {
3997 server_id: LanguageServerId,
3998 request_id: Option<usize>,
3999 },
4000 RefreshSemanticTokens {
4001 server_id: LanguageServerId,
4002 request_id: Option<usize>,
4003 },
4004 RefreshCodeLens,
4005 DiagnosticsUpdated {
4006 server_id: LanguageServerId,
4007 paths: Vec<ProjectPath>,
4008 },
4009 DiskBasedDiagnosticsStarted {
4010 language_server_id: LanguageServerId,
4011 },
4012 DiskBasedDiagnosticsFinished {
4013 language_server_id: LanguageServerId,
4014 },
4015 SnippetEdit {
4016 buffer_id: BufferId,
4017 edits: Vec<(lsp::Range, Snippet)>,
4018 most_recent_edit: clock::Lamport,
4019 },
4020 WorkspaceEditApplied(ProjectTransaction),
4021}
4022
4023#[derive(Clone, Debug, Serialize)]
4024pub struct LanguageServerStatus {
4025 pub name: LanguageServerName,
4026 pub server_version: Option<SharedString>,
4027 pub server_readable_version: Option<SharedString>,
4028 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4029 pub has_pending_diagnostic_updates: bool,
4030 pub progress_tokens: HashSet<ProgressToken>,
4031 pub worktree: Option<WorktreeId>,
4032 pub binary: Option<LanguageServerBinary>,
4033 pub configuration: Option<Value>,
4034 pub workspace_folders: BTreeSet<Uri>,
4035 pub process_id: Option<u32>,
4036}
4037
4038#[derive(Clone, Debug)]
4039struct CoreSymbol {
4040 pub language_server_name: LanguageServerName,
4041 pub source_worktree_id: WorktreeId,
4042 pub source_language_server_id: LanguageServerId,
4043 pub path: SymbolLocation,
4044 pub name: String,
4045 pub kind: lsp::SymbolKind,
4046 pub range: Range<Unclipped<PointUtf16>>,
4047 pub container_name: Option<String>,
4048}
4049
4050#[derive(Clone, Debug, PartialEq, Eq)]
4051pub enum SymbolLocation {
4052 InProject(ProjectPath),
4053 OutsideProject {
4054 abs_path: Arc<Path>,
4055 signature: [u8; 32],
4056 },
4057}
4058
4059impl SymbolLocation {
4060 fn file_name(&self) -> Option<&str> {
4061 match self {
4062 Self::InProject(path) => path.path.file_name(),
4063 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4064 }
4065 }
4066}
4067
4068impl LspStore {
4069 pub fn init(client: &AnyProtoClient) {
4070 client.add_entity_request_handler(Self::handle_lsp_query);
4071 client.add_entity_message_handler(Self::handle_lsp_query_response);
4072 client.add_entity_request_handler(Self::handle_restart_language_servers);
4073 client.add_entity_request_handler(Self::handle_stop_language_servers);
4074 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4075 client.add_entity_message_handler(Self::handle_start_language_server);
4076 client.add_entity_message_handler(Self::handle_update_language_server);
4077 client.add_entity_message_handler(Self::handle_language_server_log);
4078 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4079 client.add_entity_request_handler(Self::handle_format_buffers);
4080 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4081 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4082 client.add_entity_request_handler(Self::handle_apply_code_action);
4083 client.add_entity_request_handler(Self::handle_get_project_symbols);
4084 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4085 client.add_entity_request_handler(Self::handle_get_color_presentation);
4086 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4087 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4088 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4089 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4090 client.add_entity_request_handler(Self::handle_on_type_formatting);
4091 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4092 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4093 client.add_entity_request_handler(Self::handle_rename_project_entry);
4094 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4095 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4096 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4097 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4098 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4099 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4100 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4101
4102 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4103 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4104 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4105 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4106 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4107 client.add_entity_request_handler(
4108 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4109 );
4110 client.add_entity_request_handler(
4111 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4112 );
4113 client.add_entity_request_handler(
4114 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4115 );
4116 }
4117
4118 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4119 match &self.mode {
4120 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4121 _ => None,
4122 }
4123 }
4124
4125 pub fn as_local(&self) -> Option<&LocalLspStore> {
4126 match &self.mode {
4127 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4128 _ => None,
4129 }
4130 }
4131
4132 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4133 match &mut self.mode {
4134 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4135 _ => None,
4136 }
4137 }
4138
4139 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4140 match &self.mode {
4141 LspStoreMode::Remote(RemoteLspStore {
4142 upstream_client: Some(upstream_client),
4143 upstream_project_id,
4144 ..
4145 }) => Some((upstream_client.clone(), *upstream_project_id)),
4146
4147 LspStoreMode::Remote(RemoteLspStore {
4148 upstream_client: None,
4149 ..
4150 }) => None,
4151 LspStoreMode::Local(_) => None,
4152 }
4153 }
4154
4155 pub fn new_local(
4156 buffer_store: Entity<BufferStore>,
4157 worktree_store: Entity<WorktreeStore>,
4158 prettier_store: Entity<PrettierStore>,
4159 toolchain_store: Entity<LocalToolchainStore>,
4160 environment: Entity<ProjectEnvironment>,
4161 manifest_tree: Entity<ManifestTree>,
4162 languages: Arc<LanguageRegistry>,
4163 http_client: Arc<dyn HttpClient>,
4164 fs: Arc<dyn Fs>,
4165 cx: &mut Context<Self>,
4166 ) -> Self {
4167 let yarn = YarnPathStore::new(fs.clone(), cx);
4168 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4169 .detach();
4170 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4171 .detach();
4172 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4173 .detach();
4174 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4175 .detach();
4176 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4177 .detach();
4178 subscribe_to_binary_statuses(&languages, cx).detach();
4179
4180 let _maintain_workspace_config = {
4181 let (sender, receiver) = watch::channel();
4182 (Self::maintain_workspace_config(receiver, cx), sender)
4183 };
4184
4185 Self {
4186 mode: LspStoreMode::Local(LocalLspStore {
4187 weak: cx.weak_entity(),
4188 worktree_store: worktree_store.clone(),
4189
4190 supplementary_language_servers: Default::default(),
4191 languages: languages.clone(),
4192 language_server_ids: Default::default(),
4193 language_servers: Default::default(),
4194 last_workspace_edits_by_language_server: Default::default(),
4195 language_server_watched_paths: Default::default(),
4196 language_server_paths_watched_for_rename: Default::default(),
4197 language_server_dynamic_registrations: Default::default(),
4198 buffers_being_formatted: Default::default(),
4199 buffers_to_refresh_hash_set: HashSet::default(),
4200 buffers_to_refresh_queue: VecDeque::new(),
4201 _background_diagnostics_worker: Task::ready(()).shared(),
4202 buffer_snapshots: Default::default(),
4203 prettier_store,
4204 environment,
4205 http_client,
4206 fs,
4207 yarn,
4208 next_diagnostic_group_id: Default::default(),
4209 diagnostics: Default::default(),
4210 _subscription: cx.on_app_quit(|this, _| {
4211 this.as_local_mut()
4212 .unwrap()
4213 .shutdown_language_servers_on_quit()
4214 }),
4215 lsp_tree: LanguageServerTree::new(
4216 manifest_tree,
4217 languages.clone(),
4218 toolchain_store.clone(),
4219 ),
4220 toolchain_store,
4221 registered_buffers: HashMap::default(),
4222 buffers_opened_in_servers: HashMap::default(),
4223 buffer_pull_diagnostics_result_ids: HashMap::default(),
4224 workspace_pull_diagnostics_result_ids: HashMap::default(),
4225 restricted_worktrees_tasks: HashMap::default(),
4226 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4227 .manifest_file_names(),
4228 }),
4229 last_formatting_failure: None,
4230 downstream_client: None,
4231 buffer_store,
4232 worktree_store,
4233 languages: languages.clone(),
4234 language_server_statuses: Default::default(),
4235 nonce: StdRng::from_os_rng().random(),
4236 diagnostic_summaries: HashMap::default(),
4237 lsp_server_capabilities: HashMap::default(),
4238 semantic_token_config: SemanticTokenConfig::new(cx),
4239 lsp_data: HashMap::default(),
4240 buffer_reload_tasks: HashMap::default(),
4241 next_hint_id: Arc::default(),
4242 active_entry: None,
4243 _maintain_workspace_config,
4244 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4245 }
4246 }
4247
4248 fn send_lsp_proto_request<R: LspCommand>(
4249 &self,
4250 buffer: Entity<Buffer>,
4251 client: AnyProtoClient,
4252 upstream_project_id: u64,
4253 request: R,
4254 cx: &mut Context<LspStore>,
4255 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4256 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4257 return Task::ready(Ok(R::Response::default()));
4258 }
4259 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4260 cx.spawn(async move |this, cx| {
4261 let response = client.request(message).await?;
4262 let this = this.upgrade().context("project dropped")?;
4263 request
4264 .response_from_proto(response, this, buffer, cx.clone())
4265 .await
4266 })
4267 }
4268
4269 pub(super) fn new_remote(
4270 buffer_store: Entity<BufferStore>,
4271 worktree_store: Entity<WorktreeStore>,
4272 languages: Arc<LanguageRegistry>,
4273 upstream_client: AnyProtoClient,
4274 project_id: u64,
4275 cx: &mut Context<Self>,
4276 ) -> Self {
4277 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4278 .detach();
4279 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4280 .detach();
4281 subscribe_to_binary_statuses(&languages, cx).detach();
4282 let _maintain_workspace_config = {
4283 let (sender, receiver) = watch::channel();
4284 (Self::maintain_workspace_config(receiver, cx), sender)
4285 };
4286 Self {
4287 mode: LspStoreMode::Remote(RemoteLspStore {
4288 upstream_client: Some(upstream_client),
4289 upstream_project_id: project_id,
4290 }),
4291 downstream_client: None,
4292 last_formatting_failure: None,
4293 buffer_store,
4294 worktree_store,
4295 languages: languages.clone(),
4296 language_server_statuses: Default::default(),
4297 nonce: StdRng::from_os_rng().random(),
4298 diagnostic_summaries: HashMap::default(),
4299 lsp_server_capabilities: HashMap::default(),
4300 semantic_token_config: SemanticTokenConfig::new(cx),
4301 next_hint_id: Arc::default(),
4302 lsp_data: HashMap::default(),
4303 buffer_reload_tasks: HashMap::default(),
4304 active_entry: None,
4305
4306 _maintain_workspace_config,
4307 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4308 }
4309 }
4310
4311 fn on_buffer_store_event(
4312 &mut self,
4313 _: Entity<BufferStore>,
4314 event: &BufferStoreEvent,
4315 cx: &mut Context<Self>,
4316 ) {
4317 match event {
4318 BufferStoreEvent::BufferAdded(buffer) => {
4319 self.on_buffer_added(buffer, cx).log_err();
4320 }
4321 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4322 let buffer_id = buffer.read(cx).remote_id();
4323 if let Some(local) = self.as_local_mut()
4324 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4325 {
4326 local.reset_buffer(buffer, old_file, cx);
4327
4328 if local.registered_buffers.contains_key(&buffer_id) {
4329 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4330 }
4331 }
4332
4333 self.detect_language_for_buffer(buffer, cx);
4334 if let Some(local) = self.as_local_mut() {
4335 local.initialize_buffer(buffer, cx);
4336 if local.registered_buffers.contains_key(&buffer_id) {
4337 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4338 }
4339 }
4340 }
4341 _ => {}
4342 }
4343 }
4344
4345 fn on_worktree_store_event(
4346 &mut self,
4347 _: Entity<WorktreeStore>,
4348 event: &WorktreeStoreEvent,
4349 cx: &mut Context<Self>,
4350 ) {
4351 match event {
4352 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4353 if !worktree.read(cx).is_local() {
4354 return;
4355 }
4356 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4357 worktree::Event::UpdatedEntries(changes) => {
4358 this.update_local_worktree_language_servers(&worktree, changes, cx);
4359 }
4360 worktree::Event::UpdatedGitRepositories(_)
4361 | worktree::Event::DeletedEntry(_) => {}
4362 })
4363 .detach()
4364 }
4365 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4366 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4367 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4368 }
4369 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4370 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4371 }
4372 WorktreeStoreEvent::WorktreeReleased(..)
4373 | WorktreeStoreEvent::WorktreeOrderChanged
4374 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4375 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4376 }
4377 }
4378
4379 fn on_prettier_store_event(
4380 &mut self,
4381 _: Entity<PrettierStore>,
4382 event: &PrettierStoreEvent,
4383 cx: &mut Context<Self>,
4384 ) {
4385 match event {
4386 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4387 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4388 }
4389 PrettierStoreEvent::LanguageServerAdded {
4390 new_server_id,
4391 name,
4392 prettier_server,
4393 } => {
4394 self.register_supplementary_language_server(
4395 *new_server_id,
4396 name.clone(),
4397 prettier_server.clone(),
4398 cx,
4399 );
4400 }
4401 }
4402 }
4403
4404 fn on_toolchain_store_event(
4405 &mut self,
4406 _: Entity<LocalToolchainStore>,
4407 event: &ToolchainStoreEvent,
4408 _: &mut Context<Self>,
4409 ) {
4410 if let ToolchainStoreEvent::ToolchainActivated = event {
4411 self.request_workspace_config_refresh()
4412 }
4413 }
4414
4415 fn request_workspace_config_refresh(&mut self) {
4416 *self._maintain_workspace_config.1.borrow_mut() = ();
4417 }
4418
4419 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4420 self.as_local().map(|local| local.prettier_store.clone())
4421 }
4422
4423 fn on_buffer_event(
4424 &mut self,
4425 buffer: Entity<Buffer>,
4426 event: &language::BufferEvent,
4427 cx: &mut Context<Self>,
4428 ) {
4429 match event {
4430 language::BufferEvent::Edited { .. } => {
4431 self.on_buffer_edited(buffer, cx);
4432 }
4433
4434 language::BufferEvent::Saved => {
4435 self.on_buffer_saved(buffer, cx);
4436 }
4437
4438 language::BufferEvent::Reloaded => {
4439 self.on_buffer_reloaded(buffer, cx);
4440 }
4441
4442 _ => {}
4443 }
4444 }
4445
4446 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4447 buffer
4448 .read(cx)
4449 .set_language_registry(self.languages.clone());
4450
4451 cx.subscribe(buffer, |this, buffer, event, cx| {
4452 this.on_buffer_event(buffer, event, cx);
4453 })
4454 .detach();
4455
4456 self.parse_modeline(buffer, cx);
4457 self.detect_language_for_buffer(buffer, cx);
4458 if let Some(local) = self.as_local_mut() {
4459 local.initialize_buffer(buffer, cx);
4460 }
4461
4462 Ok(())
4463 }
4464
4465 pub fn refresh_background_diagnostics_for_buffers(
4466 &mut self,
4467 buffers: HashSet<BufferId>,
4468 cx: &mut Context<Self>,
4469 ) -> Shared<Task<()>> {
4470 let Some(local) = self.as_local_mut() else {
4471 return Task::ready(()).shared();
4472 };
4473 for buffer in buffers {
4474 if local.buffers_to_refresh_hash_set.insert(buffer) {
4475 local.buffers_to_refresh_queue.push_back(buffer);
4476 if local.buffers_to_refresh_queue.len() == 1 {
4477 local._background_diagnostics_worker =
4478 Self::background_diagnostics_worker(cx).shared();
4479 }
4480 }
4481 }
4482
4483 local._background_diagnostics_worker.clone()
4484 }
4485
4486 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4487 let buffer_store = self.buffer_store.clone();
4488 let local = self.as_local_mut()?;
4489 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4490 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4491 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4492 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4493 }
4494 }
4495 None
4496 }
4497
4498 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4499 cx.spawn(async move |this, cx| {
4500 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4501 task.await.log_err();
4502 }
4503 })
4504 }
4505
4506 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4507 if self.parse_modeline(&buffer, cx) {
4508 self.detect_language_for_buffer(&buffer, cx);
4509 }
4510
4511 let buffer_id = buffer.read(cx).remote_id();
4512 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4513 self.buffer_reload_tasks.insert(buffer_id, task);
4514 }
4515
4516 pub(crate) fn register_buffer_with_language_servers(
4517 &mut self,
4518 buffer: &Entity<Buffer>,
4519 only_register_servers: HashSet<LanguageServerSelector>,
4520 ignore_refcounts: bool,
4521 cx: &mut Context<Self>,
4522 ) -> OpenLspBufferHandle {
4523 let buffer_id = buffer.read(cx).remote_id();
4524 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4525 if let Some(local) = self.as_local_mut() {
4526 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4527 if !ignore_refcounts {
4528 *refcount += 1;
4529 }
4530
4531 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4532 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4533 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4534 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4535 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4536 return handle;
4537 };
4538 if !file.is_local() {
4539 return handle;
4540 }
4541
4542 if ignore_refcounts || *refcount == 1 {
4543 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4544 }
4545 if !ignore_refcounts {
4546 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4547 let refcount = {
4548 let local = lsp_store.as_local_mut().unwrap();
4549 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4550 debug_panic!("bad refcounting");
4551 return;
4552 };
4553
4554 *refcount -= 1;
4555 *refcount
4556 };
4557 if refcount == 0 {
4558 lsp_store.lsp_data.remove(&buffer_id);
4559 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4560 let local = lsp_store.as_local_mut().unwrap();
4561 local.registered_buffers.remove(&buffer_id);
4562
4563 local.buffers_opened_in_servers.remove(&buffer_id);
4564 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4565 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4566
4567 let buffer_abs_path = file.abs_path(cx);
4568 for (_, buffer_pull_diagnostics_result_ids) in
4569 &mut local.buffer_pull_diagnostics_result_ids
4570 {
4571 buffer_pull_diagnostics_result_ids.retain(
4572 |_, buffer_result_ids| {
4573 buffer_result_ids.remove(&buffer_abs_path);
4574 !buffer_result_ids.is_empty()
4575 },
4576 );
4577 }
4578
4579 let diagnostic_updates = local
4580 .language_servers
4581 .keys()
4582 .cloned()
4583 .map(|server_id| DocumentDiagnosticsUpdate {
4584 diagnostics: DocumentDiagnostics {
4585 document_abs_path: buffer_abs_path.clone(),
4586 version: None,
4587 diagnostics: Vec::new(),
4588 },
4589 result_id: None,
4590 registration_id: None,
4591 server_id,
4592 disk_based_sources: Cow::Borrowed(&[]),
4593 })
4594 .collect::<Vec<_>>();
4595
4596 lsp_store
4597 .merge_diagnostic_entries(
4598 diagnostic_updates,
4599 |_, diagnostic, _| {
4600 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4601 },
4602 cx,
4603 )
4604 .context("Clearing diagnostics for the closed buffer")
4605 .log_err();
4606 }
4607 }
4608 })
4609 .detach();
4610 }
4611 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4612 let buffer_id = buffer.read(cx).remote_id().to_proto();
4613 cx.background_spawn(async move {
4614 upstream_client
4615 .request(proto::RegisterBufferWithLanguageServers {
4616 project_id: upstream_project_id,
4617 buffer_id,
4618 only_servers: only_register_servers
4619 .into_iter()
4620 .map(|selector| {
4621 let selector = match selector {
4622 LanguageServerSelector::Id(language_server_id) => {
4623 proto::language_server_selector::Selector::ServerId(
4624 language_server_id.to_proto(),
4625 )
4626 }
4627 LanguageServerSelector::Name(language_server_name) => {
4628 proto::language_server_selector::Selector::Name(
4629 language_server_name.to_string(),
4630 )
4631 }
4632 };
4633 proto::LanguageServerSelector {
4634 selector: Some(selector),
4635 }
4636 })
4637 .collect(),
4638 })
4639 .await
4640 })
4641 .detach();
4642 } else {
4643 // Our remote connection got closed
4644 }
4645 handle
4646 }
4647
4648 fn maintain_buffer_languages(
4649 languages: Arc<LanguageRegistry>,
4650 cx: &mut Context<Self>,
4651 ) -> Task<()> {
4652 let mut subscription = languages.subscribe();
4653 let mut prev_reload_count = languages.reload_count();
4654 cx.spawn(async move |this, cx| {
4655 while let Some(()) = subscription.next().await {
4656 if let Some(this) = this.upgrade() {
4657 // If the language registry has been reloaded, then remove and
4658 // re-assign the languages on all open buffers.
4659 let reload_count = languages.reload_count();
4660 if reload_count > prev_reload_count {
4661 prev_reload_count = reload_count;
4662 this.update(cx, |this, cx| {
4663 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4664 for buffer in buffer_store.buffers() {
4665 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4666 {
4667 buffer.update(cx, |buffer, cx| {
4668 buffer.set_language_async(None, cx)
4669 });
4670 if let Some(local) = this.as_local_mut() {
4671 local.reset_buffer(&buffer, &f, cx);
4672
4673 if local
4674 .registered_buffers
4675 .contains_key(&buffer.read(cx).remote_id())
4676 && let Some(file_url) =
4677 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4678 {
4679 local.unregister_buffer_from_language_servers(
4680 &buffer, &file_url, cx,
4681 );
4682 }
4683 }
4684 }
4685 }
4686 });
4687 });
4688 }
4689
4690 this.update(cx, |this, cx| {
4691 let mut plain_text_buffers = Vec::new();
4692 let mut buffers_with_unknown_injections = Vec::new();
4693 for handle in this.buffer_store.read(cx).buffers() {
4694 let buffer = handle.read(cx);
4695 if buffer.language().is_none()
4696 || buffer.language() == Some(&*language::PLAIN_TEXT)
4697 {
4698 plain_text_buffers.push(handle);
4699 } else if buffer.contains_unknown_injections() {
4700 buffers_with_unknown_injections.push(handle);
4701 }
4702 }
4703
4704 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4705 // and reused later in the invisible worktrees.
4706 plain_text_buffers.sort_by_key(|buffer| {
4707 Reverse(
4708 File::from_dyn(buffer.read(cx).file())
4709 .map(|file| file.worktree.read(cx).is_visible()),
4710 )
4711 });
4712
4713 for buffer in plain_text_buffers {
4714 this.detect_language_for_buffer(&buffer, cx);
4715 if let Some(local) = this.as_local_mut() {
4716 local.initialize_buffer(&buffer, cx);
4717 if local
4718 .registered_buffers
4719 .contains_key(&buffer.read(cx).remote_id())
4720 {
4721 local.register_buffer_with_language_servers(
4722 &buffer,
4723 HashSet::default(),
4724 cx,
4725 );
4726 }
4727 }
4728 }
4729
4730 for buffer in buffers_with_unknown_injections {
4731 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4732 }
4733 });
4734 }
4735 }
4736 })
4737 }
4738
4739 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4740 let buffer = buffer_handle.read(cx);
4741 let content = buffer.as_rope();
4742
4743 let modeline_settings = {
4744 let settings_store = cx.global::<SettingsStore>();
4745 let modeline_lines = settings_store
4746 .raw_user_settings()
4747 .and_then(|s| s.content.modeline_lines)
4748 .or(settings_store.raw_default_settings().modeline_lines)
4749 .unwrap_or(5);
4750
4751 const MAX_MODELINE_BYTES: usize = 1024;
4752
4753 let first_bytes =
4754 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4755 let mut first_lines = Vec::new();
4756 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4757 for _ in 0..modeline_lines {
4758 if let Some(line) = lines.next() {
4759 first_lines.push(line.to_string());
4760 } else {
4761 break;
4762 }
4763 }
4764 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4765
4766 let last_start =
4767 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4768 let mut last_lines = Vec::new();
4769 let mut lines = content
4770 .reversed_chunks_in_range(last_start..content.len())
4771 .lines();
4772 for _ in 0..modeline_lines {
4773 if let Some(line) = lines.next() {
4774 last_lines.push(line.to_string());
4775 } else {
4776 break;
4777 }
4778 }
4779 let last_lines_ref: Vec<_> =
4780 last_lines.iter().rev().map(|line| line.as_str()).collect();
4781 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4782 };
4783
4784 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4785
4786 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4787 }
4788
4789 fn detect_language_for_buffer(
4790 &mut self,
4791 buffer_handle: &Entity<Buffer>,
4792 cx: &mut Context<Self>,
4793 ) -> Option<language::AvailableLanguage> {
4794 // If the buffer has a language, set it and start the language server if we haven't already.
4795 let buffer = buffer_handle.read(cx);
4796 let file = buffer.file()?;
4797 let content = buffer.as_rope();
4798 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4799
4800 let available_language = if let Some(ModelineSettings {
4801 mode: Some(mode_name),
4802 ..
4803 }) = modeline_settings
4804 {
4805 self.languages
4806 .available_language_for_modeline_name(mode_name)
4807 } else {
4808 self.languages.language_for_file(file, Some(content), cx)
4809 };
4810 if let Some(available_language) = &available_language {
4811 if let Some(Ok(Ok(new_language))) = self
4812 .languages
4813 .load_language(available_language)
4814 .now_or_never()
4815 {
4816 self.set_language_for_buffer(buffer_handle, new_language, cx);
4817 }
4818 } else {
4819 cx.emit(LspStoreEvent::LanguageDetected {
4820 buffer: buffer_handle.clone(),
4821 new_language: None,
4822 });
4823 }
4824
4825 available_language
4826 }
4827
4828 pub(crate) fn set_language_for_buffer(
4829 &mut self,
4830 buffer_entity: &Entity<Buffer>,
4831 new_language: Arc<Language>,
4832 cx: &mut Context<Self>,
4833 ) {
4834 let buffer = buffer_entity.read(cx);
4835 let buffer_file = buffer.file().cloned();
4836 let buffer_id = buffer.remote_id();
4837 if let Some(local_store) = self.as_local_mut()
4838 && local_store.registered_buffers.contains_key(&buffer_id)
4839 && let Some(abs_path) =
4840 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4841 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4842 {
4843 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4844 }
4845 buffer_entity.update(cx, |buffer, cx| {
4846 if buffer
4847 .language()
4848 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4849 {
4850 buffer.set_language_async(Some(new_language.clone()), cx);
4851 }
4852 });
4853
4854 let settings = LanguageSettings::resolve(
4855 Some(&buffer_entity.read(cx)),
4856 Some(&new_language.name()),
4857 cx,
4858 )
4859 .into_owned();
4860 let buffer_file = File::from_dyn(buffer_file.as_ref());
4861
4862 let worktree_id = if let Some(file) = buffer_file {
4863 let worktree = file.worktree.clone();
4864
4865 if let Some(local) = self.as_local_mut()
4866 && local.registered_buffers.contains_key(&buffer_id)
4867 {
4868 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4869 }
4870 Some(worktree.read(cx).id())
4871 } else {
4872 None
4873 };
4874
4875 if settings.prettier.allowed
4876 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4877 {
4878 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4879 if let Some(prettier_store) = prettier_store {
4880 prettier_store.update(cx, |prettier_store, cx| {
4881 prettier_store.install_default_prettier(
4882 worktree_id,
4883 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4884 cx,
4885 )
4886 })
4887 }
4888 }
4889
4890 cx.emit(LspStoreEvent::LanguageDetected {
4891 buffer: buffer_entity.clone(),
4892 new_language: Some(new_language),
4893 })
4894 }
4895
4896 pub fn buffer_store(&self) -> Entity<BufferStore> {
4897 self.buffer_store.clone()
4898 }
4899
4900 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4901 self.active_entry = active_entry;
4902 }
4903
4904 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4905 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4906 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4907 {
4908 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4909 summaries
4910 .iter()
4911 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4912 });
4913 if let Some(summary) = summaries.next() {
4914 client
4915 .send(proto::UpdateDiagnosticSummary {
4916 project_id: downstream_project_id,
4917 worktree_id: worktree.id().to_proto(),
4918 summary: Some(summary),
4919 more_summaries: summaries.collect(),
4920 })
4921 .log_err();
4922 }
4923 }
4924 }
4925
4926 fn is_capable_for_proto_request<R>(
4927 &self,
4928 buffer: &Entity<Buffer>,
4929 request: &R,
4930 cx: &App,
4931 ) -> bool
4932 where
4933 R: LspCommand,
4934 {
4935 self.check_if_capable_for_proto_request(
4936 buffer,
4937 |capabilities| {
4938 request.check_capabilities(AdapterServerCapabilities {
4939 server_capabilities: capabilities.clone(),
4940 code_action_kinds: None,
4941 })
4942 },
4943 cx,
4944 )
4945 }
4946
4947 fn check_if_capable_for_proto_request<F>(
4948 &self,
4949 buffer: &Entity<Buffer>,
4950 check: F,
4951 cx: &App,
4952 ) -> bool
4953 where
4954 F: FnMut(&lsp::ServerCapabilities) -> bool,
4955 {
4956 let Some(language) = buffer.read(cx).language().cloned() else {
4957 return false;
4958 };
4959 let registered_language_servers = self
4960 .languages
4961 .lsp_adapters(&language.name())
4962 .into_iter()
4963 .map(|lsp_adapter| lsp_adapter.name())
4964 .collect::<HashSet<_>>();
4965 self.language_server_statuses
4966 .iter()
4967 .filter_map(|(server_id, server_status)| {
4968 // Include servers that are either registered for this language OR
4969 // available to be loaded (for SSH remote mode where adapters like
4970 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4971 // but only loaded on the server side)
4972 let is_relevant = registered_language_servers.contains(&server_status.name)
4973 || self.languages.is_lsp_adapter_available(&server_status.name);
4974 is_relevant.then_some(server_id)
4975 })
4976 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4977 .any(check)
4978 }
4979
4980 fn all_capable_for_proto_request<F>(
4981 &self,
4982 buffer: &Entity<Buffer>,
4983 mut check: F,
4984 cx: &App,
4985 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4986 where
4987 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4988 {
4989 let Some(language) = buffer.read(cx).language().cloned() else {
4990 return Vec::default();
4991 };
4992 let registered_language_servers = self
4993 .languages
4994 .lsp_adapters(&language.name())
4995 .into_iter()
4996 .map(|lsp_adapter| lsp_adapter.name())
4997 .collect::<HashSet<_>>();
4998 self.language_server_statuses
4999 .iter()
5000 .filter_map(|(server_id, server_status)| {
5001 // Include servers that are either registered for this language OR
5002 // available to be loaded (for SSH remote mode where adapters like
5003 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5004 // but only loaded on the server side)
5005 let is_relevant = registered_language_servers.contains(&server_status.name)
5006 || self.languages.is_lsp_adapter_available(&server_status.name);
5007 is_relevant.then_some((server_id, &server_status.name))
5008 })
5009 .filter_map(|(server_id, server_name)| {
5010 self.lsp_server_capabilities
5011 .get(server_id)
5012 .map(|c| (server_id, server_name, c))
5013 })
5014 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5015 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5016 .collect()
5017 }
5018
5019 pub fn request_lsp<R>(
5020 &mut self,
5021 buffer: Entity<Buffer>,
5022 server: LanguageServerToQuery,
5023 request: R,
5024 cx: &mut Context<Self>,
5025 ) -> Task<Result<R::Response>>
5026 where
5027 R: LspCommand,
5028 <R::LspRequest as lsp::request::Request>::Result: Send,
5029 <R::LspRequest as lsp::request::Request>::Params: Send,
5030 {
5031 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5032 return self.send_lsp_proto_request(
5033 buffer,
5034 upstream_client,
5035 upstream_project_id,
5036 request,
5037 cx,
5038 );
5039 }
5040
5041 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5042 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5043 local
5044 .language_servers_for_buffer(buffer, cx)
5045 .find(|(_, server)| {
5046 request.check_capabilities(server.adapter_server_capabilities())
5047 })
5048 .map(|(_, server)| server.clone())
5049 }),
5050 LanguageServerToQuery::Other(id) => self
5051 .language_server_for_local_buffer(buffer, id, cx)
5052 .and_then(|(_, server)| {
5053 request
5054 .check_capabilities(server.adapter_server_capabilities())
5055 .then(|| Arc::clone(server))
5056 }),
5057 }) else {
5058 return Task::ready(Ok(Default::default()));
5059 };
5060
5061 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5062
5063 let Some(file) = file else {
5064 return Task::ready(Ok(Default::default()));
5065 };
5066
5067 let lsp_params = match request.to_lsp_params_or_response(
5068 &file.abs_path(cx),
5069 buffer.read(cx),
5070 &language_server,
5071 cx,
5072 ) {
5073 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5074 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5075 Err(err) => {
5076 let message = format!(
5077 "{} via {} failed: {}",
5078 request.display_name(),
5079 language_server.name(),
5080 err
5081 );
5082 // rust-analyzer likes to error with this when its still loading up
5083 if !message.ends_with("content modified") {
5084 log::warn!("{message}");
5085 }
5086 return Task::ready(Err(anyhow!(message)));
5087 }
5088 };
5089
5090 let status = request.status();
5091 let request_timeout = ProjectSettings::get_global(cx)
5092 .global_lsp_settings
5093 .get_request_timeout();
5094
5095 cx.spawn(async move |this, cx| {
5096 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5097
5098 let id = lsp_request.id();
5099 let _cleanup = if status.is_some() {
5100 cx.update(|cx| {
5101 this.update(cx, |this, cx| {
5102 this.on_lsp_work_start(
5103 language_server.server_id(),
5104 ProgressToken::Number(id),
5105 LanguageServerProgress {
5106 is_disk_based_diagnostics_progress: false,
5107 is_cancellable: false,
5108 title: None,
5109 message: status.clone(),
5110 percentage: None,
5111 last_update_at: cx.background_executor().now(),
5112 },
5113 cx,
5114 );
5115 })
5116 })
5117 .log_err();
5118
5119 Some(defer(|| {
5120 cx.update(|cx| {
5121 this.update(cx, |this, cx| {
5122 this.on_lsp_work_end(
5123 language_server.server_id(),
5124 ProgressToken::Number(id),
5125 cx,
5126 );
5127 })
5128 })
5129 .log_err();
5130 }))
5131 } else {
5132 None
5133 };
5134
5135 let result = lsp_request.await.into_response();
5136
5137 let response = result.map_err(|err| {
5138 let message = format!(
5139 "{} via {} failed: {}",
5140 request.display_name(),
5141 language_server.name(),
5142 err
5143 );
5144 // rust-analyzer likes to error with this when its still loading up
5145 if !message.ends_with("content modified") {
5146 log::warn!("{message}");
5147 }
5148 anyhow::anyhow!(message)
5149 })?;
5150
5151 request
5152 .response_from_lsp(
5153 response,
5154 this.upgrade().context("no app context")?,
5155 buffer,
5156 language_server.server_id(),
5157 cx.clone(),
5158 )
5159 .await
5160 })
5161 }
5162
5163 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5164 let mut language_formatters_to_check = Vec::new();
5165 for buffer in self.buffer_store.read(cx).buffers() {
5166 let buffer = buffer.read(cx);
5167 let settings = LanguageSettings::for_buffer(buffer, cx);
5168 if buffer.language().is_some() {
5169 let buffer_file = File::from_dyn(buffer.file());
5170 language_formatters_to_check.push((
5171 buffer_file.map(|f| f.worktree_id(cx)),
5172 settings.into_owned(),
5173 ));
5174 }
5175 }
5176
5177 self.request_workspace_config_refresh();
5178
5179 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5180 prettier_store.update(cx, |prettier_store, cx| {
5181 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5182 })
5183 }
5184
5185 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5186 .global_lsp_settings
5187 .semantic_token_rules
5188 .clone();
5189 self.semantic_token_config
5190 .update_rules(new_semantic_token_rules);
5191 // Always clear cached stylizers so that changes to language-specific
5192 // semantic token rules (e.g. from extension install/uninstall) are
5193 // picked up. Stylizers are recreated lazily, so this is cheap.
5194 self.semantic_token_config.clear_stylizers();
5195
5196 let new_global_semantic_tokens_mode =
5197 all_language_settings(None, cx).defaults.semantic_tokens;
5198 if self
5199 .semantic_token_config
5200 .update_global_mode(new_global_semantic_tokens_mode)
5201 {
5202 self.restart_all_language_servers(cx);
5203 }
5204
5205 cx.notify();
5206 }
5207
5208 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5209 let buffer_store = self.buffer_store.clone();
5210 let Some(local) = self.as_local_mut() else {
5211 return;
5212 };
5213 let mut adapters = BTreeMap::default();
5214 let get_adapter = {
5215 let languages = local.languages.clone();
5216 let environment = local.environment.clone();
5217 let weak = local.weak.clone();
5218 let worktree_store = local.worktree_store.clone();
5219 let http_client = local.http_client.clone();
5220 let fs = local.fs.clone();
5221 move |worktree_id, cx: &mut App| {
5222 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5223 Some(LocalLspAdapterDelegate::new(
5224 languages.clone(),
5225 &environment,
5226 weak.clone(),
5227 &worktree,
5228 http_client.clone(),
5229 fs.clone(),
5230 cx,
5231 ))
5232 }
5233 };
5234
5235 let mut messages_to_report = Vec::new();
5236 let (new_tree, to_stop) = {
5237 let mut rebase = local.lsp_tree.rebase();
5238 let buffers = buffer_store
5239 .read(cx)
5240 .buffers()
5241 .filter_map(|buffer| {
5242 let raw_buffer = buffer.read(cx);
5243 if !local
5244 .registered_buffers
5245 .contains_key(&raw_buffer.remote_id())
5246 {
5247 return None;
5248 }
5249 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5250 let language = raw_buffer.language().cloned()?;
5251 Some((file, language, raw_buffer.remote_id()))
5252 })
5253 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5254 for (file, language, buffer_id) in buffers {
5255 let worktree_id = file.worktree_id(cx);
5256 let Some(worktree) = local
5257 .worktree_store
5258 .read(cx)
5259 .worktree_for_id(worktree_id, cx)
5260 else {
5261 continue;
5262 };
5263
5264 if let Some((_, apply)) = local.reuse_existing_language_server(
5265 rebase.server_tree(),
5266 &worktree,
5267 &language.name(),
5268 cx,
5269 ) {
5270 (apply)(rebase.server_tree());
5271 } else if let Some(lsp_delegate) = adapters
5272 .entry(worktree_id)
5273 .or_insert_with(|| get_adapter(worktree_id, cx))
5274 .clone()
5275 {
5276 let delegate =
5277 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5278 let path = file
5279 .path()
5280 .parent()
5281 .map(Arc::from)
5282 .unwrap_or_else(|| file.path().clone());
5283 let worktree_path = ProjectPath { worktree_id, path };
5284 let abs_path = file.abs_path(cx);
5285 let nodes = rebase
5286 .walk(
5287 worktree_path,
5288 language.name(),
5289 language.manifest(),
5290 delegate.clone(),
5291 cx,
5292 )
5293 .collect::<Vec<_>>();
5294 for node in nodes {
5295 let server_id = node.server_id_or_init(|disposition| {
5296 let path = &disposition.path;
5297 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5298 let key = LanguageServerSeed {
5299 worktree_id,
5300 name: disposition.server_name.clone(),
5301 settings: LanguageServerSeedSettings {
5302 binary: disposition.settings.binary.clone(),
5303 initialization_options: disposition
5304 .settings
5305 .initialization_options
5306 .clone(),
5307 },
5308 toolchain: local.toolchain_store.read(cx).active_toolchain(
5309 path.worktree_id,
5310 &path.path,
5311 language.name(),
5312 ),
5313 };
5314 local.language_server_ids.remove(&key);
5315
5316 let server_id = local.get_or_insert_language_server(
5317 &worktree,
5318 lsp_delegate.clone(),
5319 disposition,
5320 &language.name(),
5321 cx,
5322 );
5323 if let Some(state) = local.language_servers.get(&server_id)
5324 && let Ok(uri) = uri
5325 {
5326 state.add_workspace_folder(uri);
5327 };
5328 server_id
5329 });
5330
5331 if let Some(language_server_id) = server_id {
5332 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5333 language_server_id,
5334 name: node.name(),
5335 message:
5336 proto::update_language_server::Variant::RegisteredForBuffer(
5337 proto::RegisteredForBuffer {
5338 buffer_abs_path: abs_path
5339 .to_string_lossy()
5340 .into_owned(),
5341 buffer_id: buffer_id.to_proto(),
5342 },
5343 ),
5344 });
5345 }
5346 }
5347 } else {
5348 continue;
5349 }
5350 }
5351 rebase.finish()
5352 };
5353 for message in messages_to_report {
5354 cx.emit(message);
5355 }
5356 local.lsp_tree = new_tree;
5357 for (id, _) in to_stop {
5358 self.stop_local_language_server(id, cx).detach();
5359 }
5360 }
5361
5362 pub fn apply_code_action(
5363 &self,
5364 buffer_handle: Entity<Buffer>,
5365 mut action: CodeAction,
5366 push_to_history: bool,
5367 cx: &mut Context<Self>,
5368 ) -> Task<Result<ProjectTransaction>> {
5369 if let Some((upstream_client, project_id)) = self.upstream_client() {
5370 let request = proto::ApplyCodeAction {
5371 project_id,
5372 buffer_id: buffer_handle.read(cx).remote_id().into(),
5373 action: Some(Self::serialize_code_action(&action)),
5374 };
5375 let buffer_store = self.buffer_store();
5376 cx.spawn(async move |_, cx| {
5377 let response = upstream_client
5378 .request(request)
5379 .await?
5380 .transaction
5381 .context("missing transaction")?;
5382
5383 buffer_store
5384 .update(cx, |buffer_store, cx| {
5385 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5386 })
5387 .await
5388 })
5389 } else if self.mode.is_local() {
5390 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5391 let request_timeout = ProjectSettings::get_global(cx)
5392 .global_lsp_settings
5393 .get_request_timeout();
5394 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5395 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5396 }) else {
5397 return Task::ready(Ok(ProjectTransaction::default()));
5398 };
5399
5400 cx.spawn(async move |this, cx| {
5401 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5402 .await
5403 .context("resolving a code action")?;
5404 if let Some(edit) = action.lsp_action.edit()
5405 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5406 return LocalLspStore::deserialize_workspace_edit(
5407 this.upgrade().context("no app present")?,
5408 edit.clone(),
5409 push_to_history,
5410
5411 lang_server.clone(),
5412 cx,
5413 )
5414 .await;
5415 }
5416
5417 let Some(command) = action.lsp_action.command() else {
5418 return Ok(ProjectTransaction::default())
5419 };
5420
5421 let server_capabilities = lang_server.capabilities();
5422 let available_commands = server_capabilities
5423 .execute_command_provider
5424 .as_ref()
5425 .map(|options| options.commands.as_slice())
5426 .unwrap_or_default();
5427
5428 if !available_commands.contains(&command.command) {
5429 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5430 return Ok(ProjectTransaction::default())
5431 }
5432
5433 let request_timeout = cx.update(|app|
5434 ProjectSettings::get_global(app)
5435 .global_lsp_settings
5436 .get_request_timeout()
5437 );
5438
5439 this.update(cx, |this, _| {
5440 this.as_local_mut()
5441 .unwrap()
5442 .last_workspace_edits_by_language_server
5443 .remove(&lang_server.server_id());
5444 })?;
5445
5446 let _result = lang_server
5447 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5448 command: command.command.clone(),
5449 arguments: command.arguments.clone().unwrap_or_default(),
5450 ..lsp::ExecuteCommandParams::default()
5451 }, request_timeout)
5452 .await.into_response()
5453 .context("execute command")?;
5454
5455 return this.update(cx, |this, _| {
5456 this.as_local_mut()
5457 .unwrap()
5458 .last_workspace_edits_by_language_server
5459 .remove(&lang_server.server_id())
5460 .unwrap_or_default()
5461 });
5462 })
5463 } else {
5464 Task::ready(Err(anyhow!("no upstream client and not local")))
5465 }
5466 }
5467
5468 pub fn apply_code_action_kind(
5469 &mut self,
5470 buffers: HashSet<Entity<Buffer>>,
5471 kind: CodeActionKind,
5472 push_to_history: bool,
5473 cx: &mut Context<Self>,
5474 ) -> Task<anyhow::Result<ProjectTransaction>> {
5475 if self.as_local().is_some() {
5476 cx.spawn(async move |lsp_store, cx| {
5477 let buffers = buffers.into_iter().collect::<Vec<_>>();
5478 let result = LocalLspStore::execute_code_action_kind_locally(
5479 lsp_store.clone(),
5480 buffers,
5481 kind,
5482 push_to_history,
5483 cx,
5484 )
5485 .await;
5486 lsp_store.update(cx, |lsp_store, _| {
5487 lsp_store.update_last_formatting_failure(&result);
5488 })?;
5489 result
5490 })
5491 } else if let Some((client, project_id)) = self.upstream_client() {
5492 let buffer_store = self.buffer_store();
5493 cx.spawn(async move |lsp_store, cx| {
5494 let result = client
5495 .request(proto::ApplyCodeActionKind {
5496 project_id,
5497 kind: kind.as_str().to_owned(),
5498 buffer_ids: buffers
5499 .iter()
5500 .map(|buffer| {
5501 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5502 })
5503 .collect(),
5504 })
5505 .await
5506 .and_then(|result| result.transaction.context("missing transaction"));
5507 lsp_store.update(cx, |lsp_store, _| {
5508 lsp_store.update_last_formatting_failure(&result);
5509 })?;
5510
5511 let transaction_response = result?;
5512 buffer_store
5513 .update(cx, |buffer_store, cx| {
5514 buffer_store.deserialize_project_transaction(
5515 transaction_response,
5516 push_to_history,
5517 cx,
5518 )
5519 })
5520 .await
5521 })
5522 } else {
5523 Task::ready(Ok(ProjectTransaction::default()))
5524 }
5525 }
5526
5527 pub fn resolved_hint(
5528 &mut self,
5529 buffer_id: BufferId,
5530 id: InlayId,
5531 cx: &mut Context<Self>,
5532 ) -> Option<ResolvedHint> {
5533 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5534
5535 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5536 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5537 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5538 let (server_id, resolve_data) = match &hint.resolve_state {
5539 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5540 ResolveState::Resolving => {
5541 return Some(ResolvedHint::Resolving(
5542 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5543 ));
5544 }
5545 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5546 };
5547
5548 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5549 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5550 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5551 id,
5552 cx.spawn(async move |lsp_store, cx| {
5553 let resolved_hint = resolve_task.await;
5554 lsp_store
5555 .update(cx, |lsp_store, _| {
5556 if let Some(old_inlay_hint) = lsp_store
5557 .lsp_data
5558 .get_mut(&buffer_id)
5559 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5560 {
5561 match resolved_hint {
5562 Ok(resolved_hint) => {
5563 *old_inlay_hint = resolved_hint;
5564 }
5565 Err(e) => {
5566 old_inlay_hint.resolve_state =
5567 ResolveState::CanResolve(server_id, resolve_data);
5568 log::error!("Inlay hint resolve failed: {e:#}");
5569 }
5570 }
5571 }
5572 })
5573 .ok();
5574 })
5575 .shared(),
5576 );
5577 debug_assert!(
5578 previous_task.is_none(),
5579 "Did not change hint's resolve state after spawning its resolve"
5580 );
5581 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5582 None
5583 }
5584
5585 pub(crate) fn linked_edits(
5586 &mut self,
5587 buffer: &Entity<Buffer>,
5588 position: Anchor,
5589 cx: &mut Context<Self>,
5590 ) -> Task<Result<Vec<Range<Anchor>>>> {
5591 let snapshot = buffer.read(cx).snapshot();
5592 let scope = snapshot.language_scope_at(position);
5593 let Some(server_id) = self
5594 .as_local()
5595 .and_then(|local| {
5596 buffer.update(cx, |buffer, cx| {
5597 local
5598 .language_servers_for_buffer(buffer, cx)
5599 .filter(|(_, server)| {
5600 LinkedEditingRange::check_server_capabilities(server.capabilities())
5601 })
5602 .filter(|(adapter, _)| {
5603 scope
5604 .as_ref()
5605 .map(|scope| scope.language_allowed(&adapter.name))
5606 .unwrap_or(true)
5607 })
5608 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5609 .next()
5610 })
5611 })
5612 .or_else(|| {
5613 self.upstream_client()
5614 .is_some()
5615 .then_some(LanguageServerToQuery::FirstCapable)
5616 })
5617 .filter(|_| {
5618 maybe!({
5619 buffer.read(cx).language_at(position)?;
5620 Some(
5621 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5622 .linked_edits,
5623 )
5624 }) == Some(true)
5625 })
5626 else {
5627 return Task::ready(Ok(Vec::new()));
5628 };
5629
5630 self.request_lsp(
5631 buffer.clone(),
5632 server_id,
5633 LinkedEditingRange { position },
5634 cx,
5635 )
5636 }
5637
5638 fn apply_on_type_formatting(
5639 &mut self,
5640 buffer: Entity<Buffer>,
5641 position: Anchor,
5642 trigger: String,
5643 cx: &mut Context<Self>,
5644 ) -> Task<Result<Option<Transaction>>> {
5645 if let Some((client, project_id)) = self.upstream_client() {
5646 if !self.check_if_capable_for_proto_request(
5647 &buffer,
5648 |capabilities| {
5649 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5650 },
5651 cx,
5652 ) {
5653 return Task::ready(Ok(None));
5654 }
5655 let request = proto::OnTypeFormatting {
5656 project_id,
5657 buffer_id: buffer.read(cx).remote_id().into(),
5658 position: Some(serialize_anchor(&position)),
5659 trigger,
5660 version: serialize_version(&buffer.read(cx).version()),
5661 };
5662 cx.background_spawn(async move {
5663 client
5664 .request(request)
5665 .await?
5666 .transaction
5667 .map(language::proto::deserialize_transaction)
5668 .transpose()
5669 })
5670 } else if let Some(local) = self.as_local_mut() {
5671 let buffer_id = buffer.read(cx).remote_id();
5672 local.buffers_being_formatted.insert(buffer_id);
5673 cx.spawn(async move |this, cx| {
5674 let _cleanup = defer({
5675 let this = this.clone();
5676 let mut cx = cx.clone();
5677 move || {
5678 this.update(&mut cx, |this, _| {
5679 if let Some(local) = this.as_local_mut() {
5680 local.buffers_being_formatted.remove(&buffer_id);
5681 }
5682 })
5683 .ok();
5684 }
5685 });
5686
5687 buffer
5688 .update(cx, |buffer, _| {
5689 buffer.wait_for_edits(Some(position.timestamp()))
5690 })
5691 .await?;
5692 this.update(cx, |this, cx| {
5693 let position = position.to_point_utf16(buffer.read(cx));
5694 this.on_type_format(buffer, position, trigger, false, cx)
5695 })?
5696 .await
5697 })
5698 } else {
5699 Task::ready(Err(anyhow!("No upstream client or local language server")))
5700 }
5701 }
5702
5703 pub fn on_type_format<T: ToPointUtf16>(
5704 &mut self,
5705 buffer: Entity<Buffer>,
5706 position: T,
5707 trigger: String,
5708 push_to_history: bool,
5709 cx: &mut Context<Self>,
5710 ) -> Task<Result<Option<Transaction>>> {
5711 let position = position.to_point_utf16(buffer.read(cx));
5712 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5713 }
5714
5715 fn on_type_format_impl(
5716 &mut self,
5717 buffer: Entity<Buffer>,
5718 position: PointUtf16,
5719 trigger: String,
5720 push_to_history: bool,
5721 cx: &mut Context<Self>,
5722 ) -> Task<Result<Option<Transaction>>> {
5723 let options = buffer.update(cx, |buffer, cx| {
5724 lsp_command::lsp_formatting_options(
5725 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5726 )
5727 });
5728
5729 cx.spawn(async move |this, cx| {
5730 if let Some(waiter) =
5731 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5732 {
5733 waiter.await?;
5734 }
5735 cx.update(|cx| {
5736 this.update(cx, |this, cx| {
5737 this.request_lsp(
5738 buffer.clone(),
5739 LanguageServerToQuery::FirstCapable,
5740 OnTypeFormatting {
5741 position,
5742 trigger,
5743 options,
5744 push_to_history,
5745 },
5746 cx,
5747 )
5748 })
5749 })?
5750 .await
5751 })
5752 }
5753
5754 pub fn definitions(
5755 &mut self,
5756 buffer: &Entity<Buffer>,
5757 position: PointUtf16,
5758 cx: &mut Context<Self>,
5759 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5760 if let Some((upstream_client, project_id)) = self.upstream_client() {
5761 let request = GetDefinitions { position };
5762 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5763 return Task::ready(Ok(None));
5764 }
5765
5766 let request_timeout = ProjectSettings::get_global(cx)
5767 .global_lsp_settings
5768 .get_request_timeout();
5769
5770 let request_task = upstream_client.request_lsp(
5771 project_id,
5772 None,
5773 request_timeout,
5774 cx.background_executor().clone(),
5775 request.to_proto(project_id, buffer.read(cx)),
5776 );
5777 let buffer = buffer.clone();
5778 cx.spawn(async move |weak_lsp_store, cx| {
5779 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5780 return Ok(None);
5781 };
5782 let Some(responses) = request_task.await? else {
5783 return Ok(None);
5784 };
5785 let actions = join_all(responses.payload.into_iter().map(|response| {
5786 GetDefinitions { position }.response_from_proto(
5787 response.response,
5788 lsp_store.clone(),
5789 buffer.clone(),
5790 cx.clone(),
5791 )
5792 }))
5793 .await;
5794
5795 Ok(Some(
5796 actions
5797 .into_iter()
5798 .collect::<Result<Vec<Vec<_>>>>()?
5799 .into_iter()
5800 .flatten()
5801 .dedup()
5802 .collect(),
5803 ))
5804 })
5805 } else {
5806 let definitions_task = self.request_multiple_lsp_locally(
5807 buffer,
5808 Some(position),
5809 GetDefinitions { position },
5810 cx,
5811 );
5812 cx.background_spawn(async move {
5813 Ok(Some(
5814 definitions_task
5815 .await
5816 .into_iter()
5817 .flat_map(|(_, definitions)| definitions)
5818 .dedup()
5819 .collect(),
5820 ))
5821 })
5822 }
5823 }
5824
5825 pub fn declarations(
5826 &mut self,
5827 buffer: &Entity<Buffer>,
5828 position: PointUtf16,
5829 cx: &mut Context<Self>,
5830 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5831 if let Some((upstream_client, project_id)) = self.upstream_client() {
5832 let request = GetDeclarations { position };
5833 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5834 return Task::ready(Ok(None));
5835 }
5836 let request_timeout = ProjectSettings::get_global(cx)
5837 .global_lsp_settings
5838 .get_request_timeout();
5839 let request_task = upstream_client.request_lsp(
5840 project_id,
5841 None,
5842 request_timeout,
5843 cx.background_executor().clone(),
5844 request.to_proto(project_id, buffer.read(cx)),
5845 );
5846 let buffer = buffer.clone();
5847 cx.spawn(async move |weak_lsp_store, cx| {
5848 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5849 return Ok(None);
5850 };
5851 let Some(responses) = request_task.await? else {
5852 return Ok(None);
5853 };
5854 let actions = join_all(responses.payload.into_iter().map(|response| {
5855 GetDeclarations { position }.response_from_proto(
5856 response.response,
5857 lsp_store.clone(),
5858 buffer.clone(),
5859 cx.clone(),
5860 )
5861 }))
5862 .await;
5863
5864 Ok(Some(
5865 actions
5866 .into_iter()
5867 .collect::<Result<Vec<Vec<_>>>>()?
5868 .into_iter()
5869 .flatten()
5870 .dedup()
5871 .collect(),
5872 ))
5873 })
5874 } else {
5875 let declarations_task = self.request_multiple_lsp_locally(
5876 buffer,
5877 Some(position),
5878 GetDeclarations { position },
5879 cx,
5880 );
5881 cx.background_spawn(async move {
5882 Ok(Some(
5883 declarations_task
5884 .await
5885 .into_iter()
5886 .flat_map(|(_, declarations)| declarations)
5887 .dedup()
5888 .collect(),
5889 ))
5890 })
5891 }
5892 }
5893
5894 pub fn type_definitions(
5895 &mut self,
5896 buffer: &Entity<Buffer>,
5897 position: PointUtf16,
5898 cx: &mut Context<Self>,
5899 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5900 if let Some((upstream_client, project_id)) = self.upstream_client() {
5901 let request = GetTypeDefinitions { position };
5902 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5903 return Task::ready(Ok(None));
5904 }
5905 let request_timeout = ProjectSettings::get_global(cx)
5906 .global_lsp_settings
5907 .get_request_timeout();
5908 let request_task = upstream_client.request_lsp(
5909 project_id,
5910 None,
5911 request_timeout,
5912 cx.background_executor().clone(),
5913 request.to_proto(project_id, buffer.read(cx)),
5914 );
5915 let buffer = buffer.clone();
5916 cx.spawn(async move |weak_lsp_store, cx| {
5917 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5918 return Ok(None);
5919 };
5920 let Some(responses) = request_task.await? else {
5921 return Ok(None);
5922 };
5923 let actions = join_all(responses.payload.into_iter().map(|response| {
5924 GetTypeDefinitions { position }.response_from_proto(
5925 response.response,
5926 lsp_store.clone(),
5927 buffer.clone(),
5928 cx.clone(),
5929 )
5930 }))
5931 .await;
5932
5933 Ok(Some(
5934 actions
5935 .into_iter()
5936 .collect::<Result<Vec<Vec<_>>>>()?
5937 .into_iter()
5938 .flatten()
5939 .dedup()
5940 .collect(),
5941 ))
5942 })
5943 } else {
5944 let type_definitions_task = self.request_multiple_lsp_locally(
5945 buffer,
5946 Some(position),
5947 GetTypeDefinitions { position },
5948 cx,
5949 );
5950 cx.background_spawn(async move {
5951 Ok(Some(
5952 type_definitions_task
5953 .await
5954 .into_iter()
5955 .flat_map(|(_, type_definitions)| type_definitions)
5956 .dedup()
5957 .collect(),
5958 ))
5959 })
5960 }
5961 }
5962
5963 pub fn implementations(
5964 &mut self,
5965 buffer: &Entity<Buffer>,
5966 position: PointUtf16,
5967 cx: &mut Context<Self>,
5968 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5969 if let Some((upstream_client, project_id)) = self.upstream_client() {
5970 let request = GetImplementations { position };
5971 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5972 return Task::ready(Ok(None));
5973 }
5974
5975 let request_timeout = ProjectSettings::get_global(cx)
5976 .global_lsp_settings
5977 .get_request_timeout();
5978 let request_task = upstream_client.request_lsp(
5979 project_id,
5980 None,
5981 request_timeout,
5982 cx.background_executor().clone(),
5983 request.to_proto(project_id, buffer.read(cx)),
5984 );
5985 let buffer = buffer.clone();
5986 cx.spawn(async move |weak_lsp_store, cx| {
5987 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5988 return Ok(None);
5989 };
5990 let Some(responses) = request_task.await? else {
5991 return Ok(None);
5992 };
5993 let actions = join_all(responses.payload.into_iter().map(|response| {
5994 GetImplementations { position }.response_from_proto(
5995 response.response,
5996 lsp_store.clone(),
5997 buffer.clone(),
5998 cx.clone(),
5999 )
6000 }))
6001 .await;
6002
6003 Ok(Some(
6004 actions
6005 .into_iter()
6006 .collect::<Result<Vec<Vec<_>>>>()?
6007 .into_iter()
6008 .flatten()
6009 .dedup()
6010 .collect(),
6011 ))
6012 })
6013 } else {
6014 let implementations_task = self.request_multiple_lsp_locally(
6015 buffer,
6016 Some(position),
6017 GetImplementations { position },
6018 cx,
6019 );
6020 cx.background_spawn(async move {
6021 Ok(Some(
6022 implementations_task
6023 .await
6024 .into_iter()
6025 .flat_map(|(_, implementations)| implementations)
6026 .dedup()
6027 .collect(),
6028 ))
6029 })
6030 }
6031 }
6032
6033 pub fn references(
6034 &mut self,
6035 buffer: &Entity<Buffer>,
6036 position: PointUtf16,
6037 cx: &mut Context<Self>,
6038 ) -> Task<Result<Option<Vec<Location>>>> {
6039 if let Some((upstream_client, project_id)) = self.upstream_client() {
6040 let request = GetReferences { position };
6041 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6042 return Task::ready(Ok(None));
6043 }
6044
6045 let request_timeout = ProjectSettings::get_global(cx)
6046 .global_lsp_settings
6047 .get_request_timeout();
6048 let request_task = upstream_client.request_lsp(
6049 project_id,
6050 None,
6051 request_timeout,
6052 cx.background_executor().clone(),
6053 request.to_proto(project_id, buffer.read(cx)),
6054 );
6055 let buffer = buffer.clone();
6056 cx.spawn(async move |weak_lsp_store, cx| {
6057 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6058 return Ok(None);
6059 };
6060 let Some(responses) = request_task.await? else {
6061 return Ok(None);
6062 };
6063
6064 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6065 GetReferences { position }.response_from_proto(
6066 lsp_response.response,
6067 lsp_store.clone(),
6068 buffer.clone(),
6069 cx.clone(),
6070 )
6071 }))
6072 .await
6073 .into_iter()
6074 .collect::<Result<Vec<Vec<_>>>>()?
6075 .into_iter()
6076 .flatten()
6077 .dedup()
6078 .collect();
6079 Ok(Some(locations))
6080 })
6081 } else {
6082 let references_task = self.request_multiple_lsp_locally(
6083 buffer,
6084 Some(position),
6085 GetReferences { position },
6086 cx,
6087 );
6088 cx.background_spawn(async move {
6089 Ok(Some(
6090 references_task
6091 .await
6092 .into_iter()
6093 .flat_map(|(_, references)| references)
6094 .dedup()
6095 .collect(),
6096 ))
6097 })
6098 }
6099 }
6100
6101 pub fn code_actions(
6102 &mut self,
6103 buffer: &Entity<Buffer>,
6104 range: Range<Anchor>,
6105 kinds: Option<Vec<CodeActionKind>>,
6106 cx: &mut Context<Self>,
6107 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6108 if let Some((upstream_client, project_id)) = self.upstream_client() {
6109 let request = GetCodeActions {
6110 range: range.clone(),
6111 kinds: kinds.clone(),
6112 };
6113 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6114 return Task::ready(Ok(None));
6115 }
6116 let request_timeout = ProjectSettings::get_global(cx)
6117 .global_lsp_settings
6118 .get_request_timeout();
6119 let request_task = upstream_client.request_lsp(
6120 project_id,
6121 None,
6122 request_timeout,
6123 cx.background_executor().clone(),
6124 request.to_proto(project_id, buffer.read(cx)),
6125 );
6126 let buffer = buffer.clone();
6127 cx.spawn(async move |weak_lsp_store, cx| {
6128 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6129 return Ok(None);
6130 };
6131 let Some(responses) = request_task.await? else {
6132 return Ok(None);
6133 };
6134 let actions = join_all(responses.payload.into_iter().map(|response| {
6135 GetCodeActions {
6136 range: range.clone(),
6137 kinds: kinds.clone(),
6138 }
6139 .response_from_proto(
6140 response.response,
6141 lsp_store.clone(),
6142 buffer.clone(),
6143 cx.clone(),
6144 )
6145 }))
6146 .await;
6147
6148 Ok(Some(
6149 actions
6150 .into_iter()
6151 .collect::<Result<Vec<Vec<_>>>>()?
6152 .into_iter()
6153 .flatten()
6154 .collect(),
6155 ))
6156 })
6157 } else {
6158 let all_actions_task = self.request_multiple_lsp_locally(
6159 buffer,
6160 Some(range.start),
6161 GetCodeActions { range, kinds },
6162 cx,
6163 );
6164 cx.background_spawn(async move {
6165 Ok(Some(
6166 all_actions_task
6167 .await
6168 .into_iter()
6169 .flat_map(|(_, actions)| actions)
6170 .collect(),
6171 ))
6172 })
6173 }
6174 }
6175
6176 #[inline(never)]
6177 pub fn completions(
6178 &self,
6179 buffer: &Entity<Buffer>,
6180 position: PointUtf16,
6181 context: CompletionContext,
6182 cx: &mut Context<Self>,
6183 ) -> Task<Result<Vec<CompletionResponse>>> {
6184 let language_registry = self.languages.clone();
6185
6186 if let Some((upstream_client, project_id)) = self.upstream_client() {
6187 let snapshot = buffer.read(cx).snapshot();
6188 let offset = position.to_offset(&snapshot);
6189 let scope = snapshot.language_scope_at(offset);
6190 let capable_lsps = self.all_capable_for_proto_request(
6191 buffer,
6192 |server_name, capabilities| {
6193 capabilities.completion_provider.is_some()
6194 && scope
6195 .as_ref()
6196 .map(|scope| scope.language_allowed(server_name))
6197 .unwrap_or(true)
6198 },
6199 cx,
6200 );
6201 if capable_lsps.is_empty() {
6202 return Task::ready(Ok(Vec::new()));
6203 }
6204
6205 let language = buffer.read(cx).language().cloned();
6206
6207 let buffer = buffer.clone();
6208
6209 cx.spawn(async move |this, cx| {
6210 let requests = join_all(
6211 capable_lsps
6212 .into_iter()
6213 .map(|(id, server_name)| {
6214 let request = GetCompletions {
6215 position,
6216 context: context.clone(),
6217 server_id: Some(id),
6218 };
6219 let buffer = buffer.clone();
6220 let language = language.clone();
6221 let lsp_adapter = language.as_ref().and_then(|language| {
6222 let adapters = language_registry.lsp_adapters(&language.name());
6223 adapters
6224 .iter()
6225 .find(|adapter| adapter.name() == server_name)
6226 .or_else(|| adapters.first())
6227 .cloned()
6228 });
6229 let upstream_client = upstream_client.clone();
6230 let response = this
6231 .update(cx, |this, cx| {
6232 this.send_lsp_proto_request(
6233 buffer,
6234 upstream_client,
6235 project_id,
6236 request,
6237 cx,
6238 )
6239 })
6240 .log_err();
6241 async move {
6242 let response = response?.await.log_err()?;
6243
6244 let completions = populate_labels_for_completions(
6245 response.completions,
6246 language,
6247 lsp_adapter,
6248 )
6249 .await;
6250
6251 Some(CompletionResponse {
6252 completions,
6253 display_options: CompletionDisplayOptions::default(),
6254 is_incomplete: response.is_incomplete,
6255 })
6256 }
6257 })
6258 .collect::<Vec<_>>(),
6259 );
6260 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6261 })
6262 } else if let Some(local) = self.as_local() {
6263 let snapshot = buffer.read(cx).snapshot();
6264 let offset = position.to_offset(&snapshot);
6265 let scope = snapshot.language_scope_at(offset);
6266 let language = snapshot.language().cloned();
6267 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6268 .completions
6269 .clone();
6270 if !completion_settings.lsp {
6271 return Task::ready(Ok(Vec::new()));
6272 }
6273
6274 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6275 local
6276 .language_servers_for_buffer(buffer, cx)
6277 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6278 .filter(|(adapter, _)| {
6279 scope
6280 .as_ref()
6281 .map(|scope| scope.language_allowed(&adapter.name))
6282 .unwrap_or(true)
6283 })
6284 .map(|(_, server)| server.server_id())
6285 .collect()
6286 });
6287
6288 let buffer = buffer.clone();
6289 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6290 let lsp_timeout = if lsp_timeout > 0 {
6291 Some(Duration::from_millis(lsp_timeout))
6292 } else {
6293 None
6294 };
6295 cx.spawn(async move |this, cx| {
6296 let mut tasks = Vec::with_capacity(server_ids.len());
6297 this.update(cx, |lsp_store, cx| {
6298 for server_id in server_ids {
6299 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6300 let lsp_timeout = lsp_timeout
6301 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6302 let mut timeout = cx.background_spawn(async move {
6303 match lsp_timeout {
6304 Some(lsp_timeout) => {
6305 lsp_timeout.await;
6306 true
6307 },
6308 None => false,
6309 }
6310 }).fuse();
6311 let mut lsp_request = lsp_store.request_lsp(
6312 buffer.clone(),
6313 LanguageServerToQuery::Other(server_id),
6314 GetCompletions {
6315 position,
6316 context: context.clone(),
6317 server_id: Some(server_id),
6318 },
6319 cx,
6320 ).fuse();
6321 let new_task = cx.background_spawn(async move {
6322 select_biased! {
6323 response = lsp_request => anyhow::Ok(Some(response?)),
6324 timeout_happened = timeout => {
6325 if timeout_happened {
6326 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6327 Ok(None)
6328 } else {
6329 let completions = lsp_request.await?;
6330 Ok(Some(completions))
6331 }
6332 },
6333 }
6334 });
6335 tasks.push((lsp_adapter, new_task));
6336 }
6337 })?;
6338
6339 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6340 let completion_response = task.await.ok()??;
6341 let completions = populate_labels_for_completions(
6342 completion_response.completions,
6343 language.clone(),
6344 lsp_adapter,
6345 )
6346 .await;
6347 Some(CompletionResponse {
6348 completions,
6349 display_options: CompletionDisplayOptions::default(),
6350 is_incomplete: completion_response.is_incomplete,
6351 })
6352 });
6353
6354 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6355
6356 Ok(responses.into_iter().flatten().collect())
6357 })
6358 } else {
6359 Task::ready(Err(anyhow!("No upstream client or local language server")))
6360 }
6361 }
6362
6363 pub fn resolve_completions(
6364 &self,
6365 buffer: Entity<Buffer>,
6366 completion_indices: Vec<usize>,
6367 completions: Rc<RefCell<Box<[Completion]>>>,
6368 cx: &mut Context<Self>,
6369 ) -> Task<Result<bool>> {
6370 let client = self.upstream_client();
6371 let buffer_id = buffer.read(cx).remote_id();
6372 let buffer_snapshot = buffer.read(cx).snapshot();
6373
6374 if !self.check_if_capable_for_proto_request(
6375 &buffer,
6376 GetCompletions::can_resolve_completions,
6377 cx,
6378 ) {
6379 return Task::ready(Ok(false));
6380 }
6381 cx.spawn(async move |lsp_store, cx| {
6382 let request_timeout = cx.update(|app| {
6383 ProjectSettings::get_global(app)
6384 .global_lsp_settings
6385 .get_request_timeout()
6386 });
6387
6388 let mut did_resolve = false;
6389 if let Some((client, project_id)) = client {
6390 for completion_index in completion_indices {
6391 let server_id = {
6392 let completion = &completions.borrow()[completion_index];
6393 completion.source.server_id()
6394 };
6395 if let Some(server_id) = server_id {
6396 if Self::resolve_completion_remote(
6397 project_id,
6398 server_id,
6399 buffer_id,
6400 completions.clone(),
6401 completion_index,
6402 client.clone(),
6403 )
6404 .await
6405 .log_err()
6406 .is_some()
6407 {
6408 did_resolve = true;
6409 }
6410 } else {
6411 resolve_word_completion(
6412 &buffer_snapshot,
6413 &mut completions.borrow_mut()[completion_index],
6414 );
6415 }
6416 }
6417 } else {
6418 for completion_index in completion_indices {
6419 let server_id = {
6420 let completion = &completions.borrow()[completion_index];
6421 completion.source.server_id()
6422 };
6423 if let Some(server_id) = server_id {
6424 let server_and_adapter = lsp_store
6425 .read_with(cx, |lsp_store, _| {
6426 let server = lsp_store.language_server_for_id(server_id)?;
6427 let adapter =
6428 lsp_store.language_server_adapter_for_id(server.server_id())?;
6429 Some((server, adapter))
6430 })
6431 .ok()
6432 .flatten();
6433 let Some((server, adapter)) = server_and_adapter else {
6434 continue;
6435 };
6436
6437 let resolved = Self::resolve_completion_local(
6438 server,
6439 completions.clone(),
6440 completion_index,
6441 request_timeout,
6442 )
6443 .await
6444 .log_err()
6445 .is_some();
6446 if resolved {
6447 Self::regenerate_completion_labels(
6448 adapter,
6449 &buffer_snapshot,
6450 completions.clone(),
6451 completion_index,
6452 )
6453 .await
6454 .log_err();
6455 did_resolve = true;
6456 }
6457 } else {
6458 resolve_word_completion(
6459 &buffer_snapshot,
6460 &mut completions.borrow_mut()[completion_index],
6461 );
6462 }
6463 }
6464 }
6465
6466 Ok(did_resolve)
6467 })
6468 }
6469
6470 async fn resolve_completion_local(
6471 server: Arc<lsp::LanguageServer>,
6472 completions: Rc<RefCell<Box<[Completion]>>>,
6473 completion_index: usize,
6474 request_timeout: Duration,
6475 ) -> Result<()> {
6476 let server_id = server.server_id();
6477 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6478 return Ok(());
6479 }
6480
6481 let request = {
6482 let completion = &completions.borrow()[completion_index];
6483 match &completion.source {
6484 CompletionSource::Lsp {
6485 lsp_completion,
6486 resolved,
6487 server_id: completion_server_id,
6488 ..
6489 } => {
6490 if *resolved {
6491 return Ok(());
6492 }
6493 anyhow::ensure!(
6494 server_id == *completion_server_id,
6495 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6496 );
6497 server.request::<lsp::request::ResolveCompletionItem>(
6498 *lsp_completion.clone(),
6499 request_timeout,
6500 )
6501 }
6502 CompletionSource::BufferWord { .. }
6503 | CompletionSource::Dap { .. }
6504 | CompletionSource::Custom => {
6505 return Ok(());
6506 }
6507 }
6508 };
6509 let resolved_completion = request
6510 .await
6511 .into_response()
6512 .context("resolve completion")?;
6513
6514 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6515 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6516
6517 let mut completions = completions.borrow_mut();
6518 let completion = &mut completions[completion_index];
6519 if let CompletionSource::Lsp {
6520 lsp_completion,
6521 resolved,
6522 server_id: completion_server_id,
6523 ..
6524 } = &mut completion.source
6525 {
6526 if *resolved {
6527 return Ok(());
6528 }
6529 anyhow::ensure!(
6530 server_id == *completion_server_id,
6531 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6532 );
6533 **lsp_completion = resolved_completion;
6534 *resolved = true;
6535 }
6536 Ok(())
6537 }
6538
6539 async fn regenerate_completion_labels(
6540 adapter: Arc<CachedLspAdapter>,
6541 snapshot: &BufferSnapshot,
6542 completions: Rc<RefCell<Box<[Completion]>>>,
6543 completion_index: usize,
6544 ) -> Result<()> {
6545 let completion_item = completions.borrow()[completion_index]
6546 .source
6547 .lsp_completion(true)
6548 .map(Cow::into_owned);
6549 if let Some(lsp_documentation) = completion_item
6550 .as_ref()
6551 .and_then(|completion_item| completion_item.documentation.clone())
6552 {
6553 let mut completions = completions.borrow_mut();
6554 let completion = &mut completions[completion_index];
6555 completion.documentation = Some(lsp_documentation.into());
6556 } else {
6557 let mut completions = completions.borrow_mut();
6558 let completion = &mut completions[completion_index];
6559 completion.documentation = Some(CompletionDocumentation::Undocumented);
6560 }
6561
6562 let mut new_label = match completion_item {
6563 Some(completion_item) => {
6564 // Some language servers always return `detail` lazily via resolve, regardless of
6565 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6566 // See: https://github.com/yioneko/vtsls/issues/213
6567 let language = snapshot.language();
6568 match language {
6569 Some(language) => {
6570 adapter
6571 .labels_for_completions(
6572 std::slice::from_ref(&completion_item),
6573 language,
6574 )
6575 .await?
6576 }
6577 None => Vec::new(),
6578 }
6579 .pop()
6580 .flatten()
6581 .unwrap_or_else(|| {
6582 CodeLabel::fallback_for_completion(
6583 &completion_item,
6584 language.map(|language| language.as_ref()),
6585 )
6586 })
6587 }
6588 None => CodeLabel::plain(
6589 completions.borrow()[completion_index].new_text.clone(),
6590 None,
6591 ),
6592 };
6593 ensure_uniform_list_compatible_label(&mut new_label);
6594
6595 let mut completions = completions.borrow_mut();
6596 let completion = &mut completions[completion_index];
6597 if completion.label.filter_text() == new_label.filter_text() {
6598 completion.label = new_label;
6599 } else {
6600 log::error!(
6601 "Resolved completion changed display label from {} to {}. \
6602 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6603 completion.label.text(),
6604 new_label.text(),
6605 completion.label.filter_text(),
6606 new_label.filter_text()
6607 );
6608 }
6609
6610 Ok(())
6611 }
6612
6613 async fn resolve_completion_remote(
6614 project_id: u64,
6615 server_id: LanguageServerId,
6616 buffer_id: BufferId,
6617 completions: Rc<RefCell<Box<[Completion]>>>,
6618 completion_index: usize,
6619 client: AnyProtoClient,
6620 ) -> Result<()> {
6621 let lsp_completion = {
6622 let completion = &completions.borrow()[completion_index];
6623 match &completion.source {
6624 CompletionSource::Lsp {
6625 lsp_completion,
6626 resolved,
6627 server_id: completion_server_id,
6628 ..
6629 } => {
6630 anyhow::ensure!(
6631 server_id == *completion_server_id,
6632 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6633 );
6634 if *resolved {
6635 return Ok(());
6636 }
6637 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6638 }
6639 CompletionSource::Custom
6640 | CompletionSource::Dap { .. }
6641 | CompletionSource::BufferWord { .. } => {
6642 return Ok(());
6643 }
6644 }
6645 };
6646 let request = proto::ResolveCompletionDocumentation {
6647 project_id,
6648 language_server_id: server_id.0 as u64,
6649 lsp_completion,
6650 buffer_id: buffer_id.into(),
6651 };
6652
6653 let response = client
6654 .request(request)
6655 .await
6656 .context("completion documentation resolve proto request")?;
6657 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6658
6659 let documentation = if response.documentation.is_empty() {
6660 CompletionDocumentation::Undocumented
6661 } else if response.documentation_is_markdown {
6662 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6663 } else if response.documentation.lines().count() <= 1 {
6664 CompletionDocumentation::SingleLine(response.documentation.into())
6665 } else {
6666 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6667 };
6668
6669 let mut completions = completions.borrow_mut();
6670 let completion = &mut completions[completion_index];
6671 completion.documentation = Some(documentation);
6672 if let CompletionSource::Lsp {
6673 insert_range,
6674 lsp_completion,
6675 resolved,
6676 server_id: completion_server_id,
6677 lsp_defaults: _,
6678 } = &mut completion.source
6679 {
6680 let completion_insert_range = response
6681 .old_insert_start
6682 .and_then(deserialize_anchor)
6683 .zip(response.old_insert_end.and_then(deserialize_anchor));
6684 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6685
6686 if *resolved {
6687 return Ok(());
6688 }
6689 anyhow::ensure!(
6690 server_id == *completion_server_id,
6691 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6692 );
6693 **lsp_completion = resolved_lsp_completion;
6694 *resolved = true;
6695 }
6696
6697 let replace_range = response
6698 .old_replace_start
6699 .and_then(deserialize_anchor)
6700 .zip(response.old_replace_end.and_then(deserialize_anchor));
6701 if let Some((old_replace_start, old_replace_end)) = replace_range
6702 && !response.new_text.is_empty()
6703 {
6704 completion.new_text = response.new_text;
6705 completion.replace_range = old_replace_start..old_replace_end;
6706 }
6707
6708 Ok(())
6709 }
6710
6711 pub fn apply_additional_edits_for_completion(
6712 &self,
6713 buffer_handle: Entity<Buffer>,
6714 completions: Rc<RefCell<Box<[Completion]>>>,
6715 completion_index: usize,
6716 push_to_history: bool,
6717 all_commit_ranges: Vec<Range<language::Anchor>>,
6718 cx: &mut Context<Self>,
6719 ) -> Task<Result<Option<Transaction>>> {
6720 if let Some((client, project_id)) = self.upstream_client() {
6721 let buffer = buffer_handle.read(cx);
6722 let buffer_id = buffer.remote_id();
6723 cx.spawn(async move |_, cx| {
6724 let request = {
6725 let completion = completions.borrow()[completion_index].clone();
6726 proto::ApplyCompletionAdditionalEdits {
6727 project_id,
6728 buffer_id: buffer_id.into(),
6729 completion: Some(Self::serialize_completion(&CoreCompletion {
6730 replace_range: completion.replace_range,
6731 new_text: completion.new_text,
6732 source: completion.source,
6733 })),
6734 all_commit_ranges: all_commit_ranges
6735 .iter()
6736 .cloned()
6737 .map(language::proto::serialize_anchor_range)
6738 .collect(),
6739 }
6740 };
6741
6742 let Some(transaction) = client.request(request).await?.transaction else {
6743 return Ok(None);
6744 };
6745
6746 let transaction = language::proto::deserialize_transaction(transaction)?;
6747 buffer_handle
6748 .update(cx, |buffer, _| {
6749 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6750 })
6751 .await?;
6752 if push_to_history {
6753 buffer_handle.update(cx, |buffer, _| {
6754 buffer.push_transaction(transaction.clone(), Instant::now());
6755 buffer.finalize_last_transaction();
6756 });
6757 }
6758 Ok(Some(transaction))
6759 })
6760 } else {
6761 let request_timeout = ProjectSettings::get_global(cx)
6762 .global_lsp_settings
6763 .get_request_timeout();
6764
6765 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6766 let completion = &completions.borrow()[completion_index];
6767 let server_id = completion.source.server_id()?;
6768 Some(
6769 self.language_server_for_local_buffer(buffer, server_id, cx)?
6770 .1
6771 .clone(),
6772 )
6773 }) else {
6774 return Task::ready(Ok(None));
6775 };
6776
6777 cx.spawn(async move |this, cx| {
6778 Self::resolve_completion_local(
6779 server.clone(),
6780 completions.clone(),
6781 completion_index,
6782 request_timeout,
6783 )
6784 .await
6785 .context("resolving completion")?;
6786 let completion = completions.borrow()[completion_index].clone();
6787 let additional_text_edits = completion
6788 .source
6789 .lsp_completion(true)
6790 .as_ref()
6791 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6792 if let Some(edits) = additional_text_edits {
6793 let edits = this
6794 .update(cx, |this, cx| {
6795 this.as_local_mut().unwrap().edits_from_lsp(
6796 &buffer_handle,
6797 edits,
6798 server.server_id(),
6799 None,
6800 cx,
6801 )
6802 })?
6803 .await?;
6804
6805 buffer_handle.update(cx, |buffer, cx| {
6806 buffer.finalize_last_transaction();
6807 buffer.start_transaction();
6808
6809 for (range, text) in edits {
6810 let primary = &completion.replace_range;
6811
6812 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6813 // and the primary completion is just an insertion (empty range), then this is likely
6814 // an auto-import scenario and should not be considered overlapping
6815 // https://github.com/zed-industries/zed/issues/26136
6816 let is_file_start_auto_import = {
6817 let snapshot = buffer.snapshot();
6818 let primary_start_point = primary.start.to_point(&snapshot);
6819 let range_start_point = range.start.to_point(&snapshot);
6820
6821 let result = primary_start_point.row == 0
6822 && primary_start_point.column == 0
6823 && range_start_point.row == 0
6824 && range_start_point.column == 0;
6825
6826 result
6827 };
6828
6829 let has_overlap = if is_file_start_auto_import {
6830 false
6831 } else {
6832 all_commit_ranges.iter().any(|commit_range| {
6833 let start_within =
6834 commit_range.start.cmp(&range.start, buffer).is_le()
6835 && commit_range.end.cmp(&range.start, buffer).is_ge();
6836 let end_within =
6837 range.start.cmp(&commit_range.end, buffer).is_le()
6838 && range.end.cmp(&commit_range.end, buffer).is_ge();
6839 start_within || end_within
6840 })
6841 };
6842
6843 //Skip additional edits which overlap with the primary completion edit
6844 //https://github.com/zed-industries/zed/pull/1871
6845 if !has_overlap {
6846 buffer.edit([(range, text)], None, cx);
6847 }
6848 }
6849
6850 let transaction = if buffer.end_transaction(cx).is_some() {
6851 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6852 if !push_to_history {
6853 buffer.forget_transaction(transaction.id);
6854 }
6855 Some(transaction)
6856 } else {
6857 None
6858 };
6859 Ok(transaction)
6860 })
6861 } else {
6862 Ok(None)
6863 }
6864 })
6865 }
6866 }
6867
6868 pub fn pull_diagnostics(
6869 &mut self,
6870 buffer: Entity<Buffer>,
6871 cx: &mut Context<Self>,
6872 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6873 let buffer_id = buffer.read(cx).remote_id();
6874
6875 if let Some((client, upstream_project_id)) = self.upstream_client() {
6876 let mut suitable_capabilities = None;
6877 // Are we capable for proto request?
6878 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6879 &buffer,
6880 |capabilities| {
6881 if let Some(caps) = &capabilities.diagnostic_provider {
6882 suitable_capabilities = Some(caps.clone());
6883 true
6884 } else {
6885 false
6886 }
6887 },
6888 cx,
6889 );
6890 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6891 let Some(dynamic_caps) = suitable_capabilities else {
6892 return Task::ready(Ok(None));
6893 };
6894 assert!(any_server_has_diagnostics_provider);
6895
6896 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6897 let request = GetDocumentDiagnostics {
6898 previous_result_id: None,
6899 identifier,
6900 registration_id: None,
6901 };
6902 let request_timeout = ProjectSettings::get_global(cx)
6903 .global_lsp_settings
6904 .get_request_timeout();
6905 let request_task = client.request_lsp(
6906 upstream_project_id,
6907 None,
6908 request_timeout,
6909 cx.background_executor().clone(),
6910 request.to_proto(upstream_project_id, buffer.read(cx)),
6911 );
6912 cx.background_spawn(async move {
6913 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6914 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6915 // Do not attempt to further process the dummy responses here.
6916 let _response = request_task.await?;
6917 Ok(None)
6918 })
6919 } else {
6920 let servers = buffer.update(cx, |buffer, cx| {
6921 self.running_language_servers_for_local_buffer(buffer, cx)
6922 .map(|(_, server)| server.clone())
6923 .collect::<Vec<_>>()
6924 });
6925
6926 let pull_diagnostics = servers
6927 .into_iter()
6928 .flat_map(|server| {
6929 let result = maybe!({
6930 let local = self.as_local()?;
6931 let server_id = server.server_id();
6932 let providers_with_identifiers = local
6933 .language_server_dynamic_registrations
6934 .get(&server_id)
6935 .into_iter()
6936 .flat_map(|registrations| registrations.diagnostics.clone())
6937 .collect::<Vec<_>>();
6938 Some(
6939 providers_with_identifiers
6940 .into_iter()
6941 .map(|(registration_id, dynamic_caps)| {
6942 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6943 let registration_id = registration_id.map(SharedString::from);
6944 let result_id = self.result_id_for_buffer_pull(
6945 server_id,
6946 buffer_id,
6947 ®istration_id,
6948 cx,
6949 );
6950 self.request_lsp(
6951 buffer.clone(),
6952 LanguageServerToQuery::Other(server_id),
6953 GetDocumentDiagnostics {
6954 previous_result_id: result_id,
6955 registration_id,
6956 identifier,
6957 },
6958 cx,
6959 )
6960 })
6961 .collect::<Vec<_>>(),
6962 )
6963 });
6964
6965 result.unwrap_or_default()
6966 })
6967 .collect::<Vec<_>>();
6968
6969 cx.background_spawn(async move {
6970 let mut responses = Vec::new();
6971 for diagnostics in join_all(pull_diagnostics).await {
6972 responses.extend(diagnostics?);
6973 }
6974 Ok(Some(responses))
6975 })
6976 }
6977 }
6978
6979 pub fn applicable_inlay_chunks(
6980 &mut self,
6981 buffer: &Entity<Buffer>,
6982 ranges: &[Range<text::Anchor>],
6983 cx: &mut Context<Self>,
6984 ) -> Vec<Range<BufferRow>> {
6985 let buffer_snapshot = buffer.read(cx).snapshot();
6986 let ranges = ranges
6987 .iter()
6988 .map(|range| range.to_point(&buffer_snapshot))
6989 .collect::<Vec<_>>();
6990
6991 self.latest_lsp_data(buffer, cx)
6992 .inlay_hints
6993 .applicable_chunks(ranges.as_slice())
6994 .map(|chunk| chunk.row_range())
6995 .collect()
6996 }
6997
6998 pub fn invalidate_inlay_hints<'a>(
6999 &'a mut self,
7000 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7001 ) {
7002 for buffer_id in for_buffers {
7003 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7004 lsp_data.inlay_hints.clear();
7005 }
7006 }
7007 }
7008
7009 pub fn inlay_hints(
7010 &mut self,
7011 invalidate: InvalidationStrategy,
7012 buffer: Entity<Buffer>,
7013 ranges: Vec<Range<text::Anchor>>,
7014 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7015 cx: &mut Context<Self>,
7016 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7017 let next_hint_id = self.next_hint_id.clone();
7018 let lsp_data = self.latest_lsp_data(&buffer, cx);
7019 let query_version = lsp_data.buffer_version.clone();
7020 let mut lsp_refresh_requested = false;
7021 let for_server = if let InvalidationStrategy::RefreshRequested {
7022 server_id,
7023 request_id,
7024 } = invalidate
7025 {
7026 let invalidated = lsp_data
7027 .inlay_hints
7028 .invalidate_for_server_refresh(server_id, request_id);
7029 lsp_refresh_requested = invalidated;
7030 Some(server_id)
7031 } else {
7032 None
7033 };
7034 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7035 let known_chunks = known_chunks
7036 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7037 .map(|(_, known_chunks)| known_chunks)
7038 .unwrap_or_default();
7039
7040 let buffer_snapshot = buffer.read(cx).snapshot();
7041 let ranges = ranges
7042 .iter()
7043 .map(|range| range.to_point(&buffer_snapshot))
7044 .collect::<Vec<_>>();
7045
7046 let mut hint_fetch_tasks = Vec::new();
7047 let mut cached_inlay_hints = None;
7048 let mut ranges_to_query = None;
7049 let applicable_chunks = existing_inlay_hints
7050 .applicable_chunks(ranges.as_slice())
7051 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7052 .collect::<Vec<_>>();
7053 if applicable_chunks.is_empty() {
7054 return HashMap::default();
7055 }
7056
7057 for row_chunk in applicable_chunks {
7058 match (
7059 existing_inlay_hints
7060 .cached_hints(&row_chunk)
7061 .filter(|_| !lsp_refresh_requested)
7062 .cloned(),
7063 existing_inlay_hints
7064 .fetched_hints(&row_chunk)
7065 .as_ref()
7066 .filter(|_| !lsp_refresh_requested)
7067 .cloned(),
7068 ) {
7069 (None, None) => {
7070 let chunk_range = row_chunk.anchor_range();
7071 ranges_to_query
7072 .get_or_insert_with(Vec::new)
7073 .push((row_chunk, chunk_range));
7074 }
7075 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7076 (Some(cached_hints), None) => {
7077 for (server_id, cached_hints) in cached_hints {
7078 if for_server.is_none_or(|for_server| for_server == server_id) {
7079 cached_inlay_hints
7080 .get_or_insert_with(HashMap::default)
7081 .entry(row_chunk.row_range())
7082 .or_insert_with(HashMap::default)
7083 .entry(server_id)
7084 .or_insert_with(Vec::new)
7085 .extend(cached_hints);
7086 }
7087 }
7088 }
7089 (Some(cached_hints), Some(fetched_hints)) => {
7090 hint_fetch_tasks.push((row_chunk, fetched_hints));
7091 for (server_id, cached_hints) in cached_hints {
7092 if for_server.is_none_or(|for_server| for_server == server_id) {
7093 cached_inlay_hints
7094 .get_or_insert_with(HashMap::default)
7095 .entry(row_chunk.row_range())
7096 .or_insert_with(HashMap::default)
7097 .entry(server_id)
7098 .or_insert_with(Vec::new)
7099 .extend(cached_hints);
7100 }
7101 }
7102 }
7103 }
7104 }
7105
7106 if hint_fetch_tasks.is_empty()
7107 && ranges_to_query
7108 .as_ref()
7109 .is_none_or(|ranges| ranges.is_empty())
7110 && let Some(cached_inlay_hints) = cached_inlay_hints
7111 {
7112 cached_inlay_hints
7113 .into_iter()
7114 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7115 .collect()
7116 } else {
7117 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7118 // When a server refresh was requested, other servers' cached hints
7119 // are unaffected by the refresh and must be included in the result.
7120 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7121 // removes all visible hints but only adds back the requesting
7122 // server's new hints, permanently losing other servers' hints.
7123 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7124 lsp_data
7125 .inlay_hints
7126 .cached_hints(&chunk)
7127 .cloned()
7128 .unwrap_or_default()
7129 } else {
7130 HashMap::default()
7131 };
7132
7133 let next_hint_id = next_hint_id.clone();
7134 let buffer = buffer.clone();
7135 let query_version = query_version.clone();
7136 let new_inlay_hints = cx
7137 .spawn(async move |lsp_store, cx| {
7138 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7139 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7140 })?;
7141 new_fetch_task
7142 .await
7143 .and_then(|new_hints_by_server| {
7144 lsp_store.update(cx, |lsp_store, cx| {
7145 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7146 let update_cache = lsp_data.buffer_version == query_version;
7147 if new_hints_by_server.is_empty() {
7148 if update_cache {
7149 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7150 }
7151 other_servers_cached
7152 } else {
7153 let mut result = other_servers_cached;
7154 for (server_id, new_hints) in new_hints_by_server {
7155 let new_hints = new_hints
7156 .into_iter()
7157 .map(|new_hint| {
7158 (
7159 InlayId::Hint(next_hint_id.fetch_add(
7160 1,
7161 atomic::Ordering::AcqRel,
7162 )),
7163 new_hint,
7164 )
7165 })
7166 .collect::<Vec<_>>();
7167 if update_cache {
7168 lsp_data.inlay_hints.insert_new_hints(
7169 chunk,
7170 server_id,
7171 new_hints.clone(),
7172 );
7173 }
7174 result.insert(server_id, new_hints);
7175 }
7176 result
7177 }
7178 })
7179 })
7180 .map_err(Arc::new)
7181 })
7182 .shared();
7183
7184 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7185 *fetch_task = Some(new_inlay_hints.clone());
7186 hint_fetch_tasks.push((chunk, new_inlay_hints));
7187 }
7188
7189 cached_inlay_hints
7190 .unwrap_or_default()
7191 .into_iter()
7192 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7193 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7194 (
7195 chunk.row_range(),
7196 cx.spawn(async move |_, _| {
7197 hints_fetch.await.map_err(|e| {
7198 if e.error_code() != ErrorCode::Internal {
7199 anyhow!(e.error_code())
7200 } else {
7201 anyhow!("{e:#}")
7202 }
7203 })
7204 }),
7205 )
7206 }))
7207 .collect()
7208 }
7209 }
7210
7211 fn fetch_inlay_hints(
7212 &mut self,
7213 for_server: Option<LanguageServerId>,
7214 buffer: &Entity<Buffer>,
7215 range: Range<Anchor>,
7216 cx: &mut Context<Self>,
7217 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7218 let request = InlayHints {
7219 range: range.clone(),
7220 };
7221 if let Some((upstream_client, project_id)) = self.upstream_client() {
7222 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7223 return Task::ready(Ok(HashMap::default()));
7224 }
7225 let request_timeout = ProjectSettings::get_global(cx)
7226 .global_lsp_settings
7227 .get_request_timeout();
7228 let request_task = upstream_client.request_lsp(
7229 project_id,
7230 for_server.map(|id| id.to_proto()),
7231 request_timeout,
7232 cx.background_executor().clone(),
7233 request.to_proto(project_id, buffer.read(cx)),
7234 );
7235 let buffer = buffer.clone();
7236 cx.spawn(async move |weak_lsp_store, cx| {
7237 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7238 return Ok(HashMap::default());
7239 };
7240 let Some(responses) = request_task.await? else {
7241 return Ok(HashMap::default());
7242 };
7243
7244 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7245 let lsp_store = lsp_store.clone();
7246 let buffer = buffer.clone();
7247 let cx = cx.clone();
7248 let request = request.clone();
7249 async move {
7250 (
7251 LanguageServerId::from_proto(response.server_id),
7252 request
7253 .response_from_proto(response.response, lsp_store, buffer, cx)
7254 .await,
7255 )
7256 }
7257 }))
7258 .await;
7259
7260 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7261 let mut has_errors = false;
7262 let inlay_hints = inlay_hints
7263 .into_iter()
7264 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7265 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7266 Err(e) => {
7267 has_errors = true;
7268 log::error!("{e:#}");
7269 None
7270 }
7271 })
7272 .map(|(server_id, mut new_hints)| {
7273 new_hints.retain(|hint| {
7274 hint.position.is_valid(&buffer_snapshot)
7275 && range.start.is_valid(&buffer_snapshot)
7276 && range.end.is_valid(&buffer_snapshot)
7277 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7278 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7279 });
7280 (server_id, new_hints)
7281 })
7282 .collect::<HashMap<_, _>>();
7283 anyhow::ensure!(
7284 !has_errors || !inlay_hints.is_empty(),
7285 "Failed to fetch inlay hints"
7286 );
7287 Ok(inlay_hints)
7288 })
7289 } else {
7290 let inlay_hints_task = match for_server {
7291 Some(server_id) => {
7292 let server_task = self.request_lsp(
7293 buffer.clone(),
7294 LanguageServerToQuery::Other(server_id),
7295 request,
7296 cx,
7297 );
7298 cx.background_spawn(async move {
7299 let mut responses = Vec::new();
7300 match server_task.await {
7301 Ok(response) => responses.push((server_id, response)),
7302 // rust-analyzer likes to error with this when its still loading up
7303 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7304 Err(e) => log::error!(
7305 "Error handling response for inlay hints request: {e:#}"
7306 ),
7307 }
7308 responses
7309 })
7310 }
7311 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7312 };
7313 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7314 cx.background_spawn(async move {
7315 Ok(inlay_hints_task
7316 .await
7317 .into_iter()
7318 .map(|(server_id, mut new_hints)| {
7319 new_hints.retain(|hint| {
7320 hint.position.is_valid(&buffer_snapshot)
7321 && range.start.is_valid(&buffer_snapshot)
7322 && range.end.is_valid(&buffer_snapshot)
7323 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7324 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7325 });
7326 (server_id, new_hints)
7327 })
7328 .collect())
7329 })
7330 }
7331 }
7332
7333 fn diagnostic_registration_exists(
7334 &self,
7335 server_id: LanguageServerId,
7336 registration_id: &Option<SharedString>,
7337 ) -> bool {
7338 let Some(local) = self.as_local() else {
7339 return false;
7340 };
7341 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7342 else {
7343 return false;
7344 };
7345 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7346 registrations.diagnostics.contains_key(®istration_key)
7347 }
7348
7349 pub fn pull_diagnostics_for_buffer(
7350 &mut self,
7351 buffer: Entity<Buffer>,
7352 cx: &mut Context<Self>,
7353 ) -> Task<anyhow::Result<()>> {
7354 let diagnostics = self.pull_diagnostics(buffer, cx);
7355 cx.spawn(async move |lsp_store, cx| {
7356 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7357 return Ok(());
7358 };
7359 lsp_store.update(cx, |lsp_store, cx| {
7360 if lsp_store.as_local().is_none() {
7361 return;
7362 }
7363
7364 let mut unchanged_buffers = HashMap::default();
7365 let server_diagnostics_updates = diagnostics
7366 .into_iter()
7367 .filter_map(|diagnostics_set| match diagnostics_set {
7368 LspPullDiagnostics::Response {
7369 server_id,
7370 uri,
7371 diagnostics,
7372 registration_id,
7373 } => Some((server_id, uri, diagnostics, registration_id)),
7374 LspPullDiagnostics::Default => None,
7375 })
7376 .filter(|(server_id, _, _, registration_id)| {
7377 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7378 })
7379 .fold(
7380 HashMap::default(),
7381 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7382 let (result_id, diagnostics) = match diagnostics {
7383 PulledDiagnostics::Unchanged { result_id } => {
7384 unchanged_buffers
7385 .entry(new_registration_id.clone())
7386 .or_insert_with(HashSet::default)
7387 .insert(uri.clone());
7388 (Some(result_id), Vec::new())
7389 }
7390 PulledDiagnostics::Changed {
7391 result_id,
7392 diagnostics,
7393 } => (result_id, diagnostics),
7394 };
7395 let disk_based_sources = Cow::Owned(
7396 lsp_store
7397 .language_server_adapter_for_id(server_id)
7398 .as_ref()
7399 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7400 .unwrap_or(&[])
7401 .to_vec(),
7402 );
7403 acc.entry(server_id)
7404 .or_insert_with(HashMap::default)
7405 .entry(new_registration_id.clone())
7406 .or_insert_with(Vec::new)
7407 .push(DocumentDiagnosticsUpdate {
7408 server_id,
7409 diagnostics: lsp::PublishDiagnosticsParams {
7410 uri,
7411 diagnostics,
7412 version: None,
7413 },
7414 result_id: result_id.map(SharedString::new),
7415 disk_based_sources,
7416 registration_id: new_registration_id,
7417 });
7418 acc
7419 },
7420 );
7421
7422 for diagnostic_updates in server_diagnostics_updates.into_values() {
7423 for (registration_id, diagnostic_updates) in diagnostic_updates {
7424 lsp_store
7425 .merge_lsp_diagnostics(
7426 DiagnosticSourceKind::Pulled,
7427 diagnostic_updates,
7428 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7429 DiagnosticSourceKind::Pulled => {
7430 old_diagnostic.registration_id != registration_id
7431 || unchanged_buffers
7432 .get(&old_diagnostic.registration_id)
7433 .is_some_and(|unchanged_buffers| {
7434 unchanged_buffers.contains(&document_uri)
7435 })
7436 }
7437 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7438 true
7439 }
7440 },
7441 cx,
7442 )
7443 .log_err();
7444 }
7445 }
7446 })
7447 })
7448 }
7449
7450 pub fn signature_help<T: ToPointUtf16>(
7451 &mut self,
7452 buffer: &Entity<Buffer>,
7453 position: T,
7454 cx: &mut Context<Self>,
7455 ) -> Task<Option<Vec<SignatureHelp>>> {
7456 let position = position.to_point_utf16(buffer.read(cx));
7457
7458 if let Some((client, upstream_project_id)) = self.upstream_client() {
7459 let request = GetSignatureHelp { position };
7460 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7461 return Task::ready(None);
7462 }
7463 let request_timeout = ProjectSettings::get_global(cx)
7464 .global_lsp_settings
7465 .get_request_timeout();
7466 let request_task = client.request_lsp(
7467 upstream_project_id,
7468 None,
7469 request_timeout,
7470 cx.background_executor().clone(),
7471 request.to_proto(upstream_project_id, buffer.read(cx)),
7472 );
7473 let buffer = buffer.clone();
7474 cx.spawn(async move |weak_lsp_store, cx| {
7475 let lsp_store = weak_lsp_store.upgrade()?;
7476 let signatures = join_all(
7477 request_task
7478 .await
7479 .log_err()
7480 .flatten()
7481 .map(|response| response.payload)
7482 .unwrap_or_default()
7483 .into_iter()
7484 .map(|response| {
7485 let response = GetSignatureHelp { position }.response_from_proto(
7486 response.response,
7487 lsp_store.clone(),
7488 buffer.clone(),
7489 cx.clone(),
7490 );
7491 async move { response.await.log_err().flatten() }
7492 }),
7493 )
7494 .await
7495 .into_iter()
7496 .flatten()
7497 .collect();
7498 Some(signatures)
7499 })
7500 } else {
7501 let all_actions_task = self.request_multiple_lsp_locally(
7502 buffer,
7503 Some(position),
7504 GetSignatureHelp { position },
7505 cx,
7506 );
7507 cx.background_spawn(async move {
7508 Some(
7509 all_actions_task
7510 .await
7511 .into_iter()
7512 .flat_map(|(_, actions)| actions)
7513 .collect::<Vec<_>>(),
7514 )
7515 })
7516 }
7517 }
7518
7519 pub fn hover(
7520 &mut self,
7521 buffer: &Entity<Buffer>,
7522 position: PointUtf16,
7523 cx: &mut Context<Self>,
7524 ) -> Task<Option<Vec<Hover>>> {
7525 if let Some((client, upstream_project_id)) = self.upstream_client() {
7526 let request = GetHover { position };
7527 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7528 return Task::ready(None);
7529 }
7530 let request_timeout = ProjectSettings::get_global(cx)
7531 .global_lsp_settings
7532 .get_request_timeout();
7533 let request_task = client.request_lsp(
7534 upstream_project_id,
7535 None,
7536 request_timeout,
7537 cx.background_executor().clone(),
7538 request.to_proto(upstream_project_id, buffer.read(cx)),
7539 );
7540 let buffer = buffer.clone();
7541 cx.spawn(async move |weak_lsp_store, cx| {
7542 let lsp_store = weak_lsp_store.upgrade()?;
7543 let hovers = join_all(
7544 request_task
7545 .await
7546 .log_err()
7547 .flatten()
7548 .map(|response| response.payload)
7549 .unwrap_or_default()
7550 .into_iter()
7551 .map(|response| {
7552 let response = GetHover { position }.response_from_proto(
7553 response.response,
7554 lsp_store.clone(),
7555 buffer.clone(),
7556 cx.clone(),
7557 );
7558 async move {
7559 response
7560 .await
7561 .log_err()
7562 .flatten()
7563 .and_then(remove_empty_hover_blocks)
7564 }
7565 }),
7566 )
7567 .await
7568 .into_iter()
7569 .flatten()
7570 .collect();
7571 Some(hovers)
7572 })
7573 } else {
7574 let all_actions_task = self.request_multiple_lsp_locally(
7575 buffer,
7576 Some(position),
7577 GetHover { position },
7578 cx,
7579 );
7580 cx.background_spawn(async move {
7581 Some(
7582 all_actions_task
7583 .await
7584 .into_iter()
7585 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7586 .collect::<Vec<Hover>>(),
7587 )
7588 })
7589 }
7590 }
7591
7592 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7593 let language_registry = self.languages.clone();
7594
7595 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7596 let request = upstream_client.request(proto::GetProjectSymbols {
7597 project_id: *project_id,
7598 query: query.to_string(),
7599 });
7600 cx.foreground_executor().spawn(async move {
7601 let response = request.await?;
7602 let mut symbols = Vec::new();
7603 let core_symbols = response
7604 .symbols
7605 .into_iter()
7606 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7607 .collect::<Vec<_>>();
7608 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7609 .await;
7610 Ok(symbols)
7611 })
7612 } else if let Some(local) = self.as_local() {
7613 struct WorkspaceSymbolsResult {
7614 server_id: LanguageServerId,
7615 lsp_adapter: Arc<CachedLspAdapter>,
7616 worktree: WeakEntity<Worktree>,
7617 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7618 }
7619
7620 let mut requests = Vec::new();
7621 let mut requested_servers = BTreeSet::new();
7622 let request_timeout = ProjectSettings::get_global(cx)
7623 .global_lsp_settings
7624 .get_request_timeout();
7625
7626 for (seed, state) in local.language_server_ids.iter() {
7627 let Some(worktree_handle) = self
7628 .worktree_store
7629 .read(cx)
7630 .worktree_for_id(seed.worktree_id, cx)
7631 else {
7632 continue;
7633 };
7634
7635 let worktree = worktree_handle.read(cx);
7636 if !worktree.is_visible() {
7637 continue;
7638 }
7639
7640 if !requested_servers.insert(state.id) {
7641 continue;
7642 }
7643
7644 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7645 Some(LanguageServerState::Running {
7646 adapter, server, ..
7647 }) => (adapter.clone(), server),
7648
7649 _ => continue,
7650 };
7651
7652 let supports_workspace_symbol_request =
7653 match server.capabilities().workspace_symbol_provider {
7654 Some(OneOf::Left(supported)) => supported,
7655 Some(OneOf::Right(_)) => true,
7656 None => false,
7657 };
7658
7659 if !supports_workspace_symbol_request {
7660 continue;
7661 }
7662
7663 let worktree_handle = worktree_handle.clone();
7664 let server_id = server.server_id();
7665 requests.push(
7666 server
7667 .request::<lsp::request::WorkspaceSymbolRequest>(
7668 lsp::WorkspaceSymbolParams {
7669 query: query.to_string(),
7670 ..Default::default()
7671 },
7672 request_timeout,
7673 )
7674 .map(move |response| {
7675 let lsp_symbols = response
7676 .into_response()
7677 .context("workspace symbols request")
7678 .log_err()
7679 .flatten()
7680 .map(|symbol_response| match symbol_response {
7681 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7682 flat_responses
7683 .into_iter()
7684 .map(|lsp_symbol| {
7685 (
7686 lsp_symbol.name,
7687 lsp_symbol.kind,
7688 lsp_symbol.location,
7689 lsp_symbol.container_name,
7690 )
7691 })
7692 .collect::<Vec<_>>()
7693 }
7694 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7695 nested_responses
7696 .into_iter()
7697 .filter_map(|lsp_symbol| {
7698 let location = match lsp_symbol.location {
7699 OneOf::Left(location) => location,
7700 OneOf::Right(_) => {
7701 log::error!(
7702 "Unexpected: client capabilities \
7703 forbid symbol resolutions in \
7704 workspace.symbol.resolveSupport"
7705 );
7706 return None;
7707 }
7708 };
7709 Some((
7710 lsp_symbol.name,
7711 lsp_symbol.kind,
7712 location,
7713 lsp_symbol.container_name,
7714 ))
7715 })
7716 .collect::<Vec<_>>()
7717 }
7718 })
7719 .unwrap_or_default();
7720
7721 WorkspaceSymbolsResult {
7722 server_id,
7723 lsp_adapter,
7724 worktree: worktree_handle.downgrade(),
7725 lsp_symbols,
7726 }
7727 }),
7728 );
7729 }
7730
7731 cx.spawn(async move |this, cx| {
7732 let responses = futures::future::join_all(requests).await;
7733 let this = match this.upgrade() {
7734 Some(this) => this,
7735 None => return Ok(Vec::new()),
7736 };
7737
7738 let mut symbols = Vec::new();
7739 for result in responses {
7740 let core_symbols = this.update(cx, |this, cx| {
7741 result
7742 .lsp_symbols
7743 .into_iter()
7744 .filter_map(
7745 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7746 let abs_path = symbol_location.uri.to_file_path().ok()?;
7747 let source_worktree = result.worktree.upgrade()?;
7748 let source_worktree_id = source_worktree.read(cx).id();
7749
7750 let path = if let Some((tree, rel_path)) =
7751 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7752 {
7753 let worktree_id = tree.read(cx).id();
7754 SymbolLocation::InProject(ProjectPath {
7755 worktree_id,
7756 path: rel_path,
7757 })
7758 } else {
7759 SymbolLocation::OutsideProject {
7760 signature: this.symbol_signature(&abs_path),
7761 abs_path: abs_path.into(),
7762 }
7763 };
7764
7765 Some(CoreSymbol {
7766 source_language_server_id: result.server_id,
7767 language_server_name: result.lsp_adapter.name.clone(),
7768 source_worktree_id,
7769 path,
7770 kind: symbol_kind,
7771 name: collapse_newlines(&symbol_name, "↵ "),
7772 range: range_from_lsp(symbol_location.range),
7773 container_name: container_name
7774 .map(|c| collapse_newlines(&c, "↵ ")),
7775 })
7776 },
7777 )
7778 .collect::<Vec<_>>()
7779 });
7780
7781 populate_labels_for_symbols(
7782 core_symbols,
7783 &language_registry,
7784 Some(result.lsp_adapter),
7785 &mut symbols,
7786 )
7787 .await;
7788 }
7789
7790 Ok(symbols)
7791 })
7792 } else {
7793 Task::ready(Err(anyhow!("No upstream client or local language server")))
7794 }
7795 }
7796
7797 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7798 let mut summary = DiagnosticSummary::default();
7799 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7800 summary.error_count += path_summary.error_count;
7801 summary.warning_count += path_summary.warning_count;
7802 }
7803 summary
7804 }
7805
7806 /// Returns the diagnostic summary for a specific project path.
7807 pub fn diagnostic_summary_for_path(
7808 &self,
7809 project_path: &ProjectPath,
7810 _: &App,
7811 ) -> DiagnosticSummary {
7812 if let Some(summaries) = self
7813 .diagnostic_summaries
7814 .get(&project_path.worktree_id)
7815 .and_then(|map| map.get(&project_path.path))
7816 {
7817 let (error_count, warning_count) = summaries.iter().fold(
7818 (0, 0),
7819 |(error_count, warning_count), (_language_server_id, summary)| {
7820 (
7821 error_count + summary.error_count,
7822 warning_count + summary.warning_count,
7823 )
7824 },
7825 );
7826
7827 DiagnosticSummary {
7828 error_count,
7829 warning_count,
7830 }
7831 } else {
7832 DiagnosticSummary::default()
7833 }
7834 }
7835
7836 pub fn diagnostic_summaries<'a>(
7837 &'a self,
7838 include_ignored: bool,
7839 cx: &'a App,
7840 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7841 self.worktree_store
7842 .read(cx)
7843 .visible_worktrees(cx)
7844 .filter_map(|worktree| {
7845 let worktree = worktree.read(cx);
7846 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7847 })
7848 .flat_map(move |(worktree, summaries)| {
7849 let worktree_id = worktree.id();
7850 summaries
7851 .iter()
7852 .filter(move |(path, _)| {
7853 include_ignored
7854 || worktree
7855 .entry_for_path(path.as_ref())
7856 .is_some_and(|entry| !entry.is_ignored)
7857 })
7858 .flat_map(move |(path, summaries)| {
7859 summaries.iter().map(move |(server_id, summary)| {
7860 (
7861 ProjectPath {
7862 worktree_id,
7863 path: path.clone(),
7864 },
7865 *server_id,
7866 *summary,
7867 )
7868 })
7869 })
7870 })
7871 }
7872
7873 pub fn on_buffer_edited(
7874 &mut self,
7875 buffer: Entity<Buffer>,
7876 cx: &mut Context<Self>,
7877 ) -> Option<()> {
7878 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7879 Some(
7880 self.as_local()?
7881 .language_servers_for_buffer(buffer, cx)
7882 .map(|i| i.1.clone())
7883 .collect(),
7884 )
7885 })?;
7886
7887 let buffer = buffer.read(cx);
7888 let file = File::from_dyn(buffer.file())?;
7889 let abs_path = file.as_local()?.abs_path(cx);
7890 let uri = lsp::Uri::from_file_path(&abs_path)
7891 .ok()
7892 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7893 .log_err()?;
7894 let next_snapshot = buffer.text_snapshot();
7895 for language_server in language_servers {
7896 let language_server = language_server.clone();
7897
7898 let buffer_snapshots = self
7899 .as_local_mut()?
7900 .buffer_snapshots
7901 .get_mut(&buffer.remote_id())
7902 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7903 let previous_snapshot = buffer_snapshots.last()?;
7904
7905 let build_incremental_change = || {
7906 buffer
7907 .edits_since::<Dimensions<PointUtf16, usize>>(
7908 previous_snapshot.snapshot.version(),
7909 )
7910 .map(|edit| {
7911 let edit_start = edit.new.start.0;
7912 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7913 let new_text = next_snapshot
7914 .text_for_range(edit.new.start.1..edit.new.end.1)
7915 .collect();
7916 lsp::TextDocumentContentChangeEvent {
7917 range: Some(lsp::Range::new(
7918 point_to_lsp(edit_start),
7919 point_to_lsp(edit_end),
7920 )),
7921 range_length: None,
7922 text: new_text,
7923 }
7924 })
7925 .collect()
7926 };
7927
7928 let document_sync_kind = language_server
7929 .capabilities()
7930 .text_document_sync
7931 .as_ref()
7932 .and_then(|sync| match sync {
7933 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7934 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7935 });
7936
7937 let content_changes: Vec<_> = match document_sync_kind {
7938 Some(lsp::TextDocumentSyncKind::FULL) => {
7939 vec![lsp::TextDocumentContentChangeEvent {
7940 range: None,
7941 range_length: None,
7942 text: next_snapshot.text(),
7943 }]
7944 }
7945 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7946 _ => {
7947 #[cfg(any(test, feature = "test-support"))]
7948 {
7949 build_incremental_change()
7950 }
7951
7952 #[cfg(not(any(test, feature = "test-support")))]
7953 {
7954 continue;
7955 }
7956 }
7957 };
7958
7959 let next_version = previous_snapshot.version + 1;
7960 buffer_snapshots.push(LspBufferSnapshot {
7961 version: next_version,
7962 snapshot: next_snapshot.clone(),
7963 });
7964
7965 language_server
7966 .notify::<lsp::notification::DidChangeTextDocument>(
7967 lsp::DidChangeTextDocumentParams {
7968 text_document: lsp::VersionedTextDocumentIdentifier::new(
7969 uri.clone(),
7970 next_version,
7971 ),
7972 content_changes,
7973 },
7974 )
7975 .ok();
7976 self.pull_workspace_diagnostics(language_server.server_id());
7977 }
7978
7979 None
7980 }
7981
7982 pub fn on_buffer_saved(
7983 &mut self,
7984 buffer: Entity<Buffer>,
7985 cx: &mut Context<Self>,
7986 ) -> Option<()> {
7987 let file = File::from_dyn(buffer.read(cx).file())?;
7988 let worktree_id = file.worktree_id(cx);
7989 let abs_path = file.as_local()?.abs_path(cx);
7990 let text_document = lsp::TextDocumentIdentifier {
7991 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7992 };
7993 let local = self.as_local()?;
7994
7995 for server in local.language_servers_for_worktree(worktree_id) {
7996 if let Some(include_text) = include_text(server.as_ref()) {
7997 let text = if include_text {
7998 Some(buffer.read(cx).text())
7999 } else {
8000 None
8001 };
8002 server
8003 .notify::<lsp::notification::DidSaveTextDocument>(
8004 lsp::DidSaveTextDocumentParams {
8005 text_document: text_document.clone(),
8006 text,
8007 },
8008 )
8009 .ok();
8010 }
8011 }
8012
8013 let language_servers = buffer.update(cx, |buffer, cx| {
8014 local.language_server_ids_for_buffer(buffer, cx)
8015 });
8016 for language_server_id in language_servers {
8017 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8018 }
8019
8020 None
8021 }
8022
8023 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8024 maybe!(async move {
8025 let mut refreshed_servers = HashSet::default();
8026 let servers = lsp_store
8027 .update(cx, |lsp_store, cx| {
8028 let local = lsp_store.as_local()?;
8029
8030 let servers = local
8031 .language_server_ids
8032 .iter()
8033 .filter_map(|(seed, state)| {
8034 let worktree = lsp_store
8035 .worktree_store
8036 .read(cx)
8037 .worktree_for_id(seed.worktree_id, cx);
8038 let delegate: Arc<dyn LspAdapterDelegate> =
8039 worktree.map(|worktree| {
8040 LocalLspAdapterDelegate::new(
8041 local.languages.clone(),
8042 &local.environment,
8043 cx.weak_entity(),
8044 &worktree,
8045 local.http_client.clone(),
8046 local.fs.clone(),
8047 cx,
8048 )
8049 })?;
8050 let server_id = state.id;
8051
8052 let states = local.language_servers.get(&server_id)?;
8053
8054 match states {
8055 LanguageServerState::Starting { .. } => None,
8056 LanguageServerState::Running {
8057 adapter, server, ..
8058 } => {
8059 let adapter = adapter.clone();
8060 let server = server.clone();
8061 refreshed_servers.insert(server.name());
8062 let toolchain = seed.toolchain.clone();
8063 Some(cx.spawn(async move |_, cx| {
8064 let settings =
8065 LocalLspStore::workspace_configuration_for_adapter(
8066 adapter.adapter.clone(),
8067 &delegate,
8068 toolchain,
8069 None,
8070 cx,
8071 )
8072 .await
8073 .ok()?;
8074 server
8075 .notify::<lsp::notification::DidChangeConfiguration>(
8076 lsp::DidChangeConfigurationParams { settings },
8077 )
8078 .ok()?;
8079 Some(())
8080 }))
8081 }
8082 }
8083 })
8084 .collect::<Vec<_>>();
8085
8086 Some(servers)
8087 })
8088 .ok()
8089 .flatten()?;
8090
8091 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8092 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8093 // to stop and unregister its language server wrapper.
8094 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8095 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8096 let _: Vec<Option<()>> = join_all(servers).await;
8097
8098 Some(())
8099 })
8100 .await;
8101 }
8102
8103 fn maintain_workspace_config(
8104 external_refresh_requests: watch::Receiver<()>,
8105 cx: &mut Context<Self>,
8106 ) -> Task<Result<()>> {
8107 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8108 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8109
8110 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8111 *settings_changed_tx.borrow_mut() = ();
8112 });
8113
8114 let mut joint_future =
8115 futures::stream::select(settings_changed_rx, external_refresh_requests);
8116 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8117 // - 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).
8118 // - 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.
8119 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8120 // - 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,
8121 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8122 cx.spawn(async move |this, cx| {
8123 while let Some(()) = joint_future.next().await {
8124 this.update(cx, |this, cx| {
8125 this.refresh_server_tree(cx);
8126 })
8127 .ok();
8128
8129 Self::refresh_workspace_configurations(&this, cx).await;
8130 }
8131
8132 drop(settings_observation);
8133 anyhow::Ok(())
8134 })
8135 }
8136
8137 pub fn running_language_servers_for_local_buffer<'a>(
8138 &'a self,
8139 buffer: &Buffer,
8140 cx: &mut App,
8141 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8142 let local = self.as_local();
8143 let language_server_ids = local
8144 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8145 .unwrap_or_default();
8146
8147 language_server_ids
8148 .into_iter()
8149 .filter_map(
8150 move |server_id| match local?.language_servers.get(&server_id)? {
8151 LanguageServerState::Running {
8152 adapter, server, ..
8153 } => Some((adapter, server)),
8154 _ => None,
8155 },
8156 )
8157 }
8158
8159 pub fn language_servers_for_local_buffer(
8160 &self,
8161 buffer: &Buffer,
8162 cx: &mut App,
8163 ) -> Vec<LanguageServerId> {
8164 let local = self.as_local();
8165 local
8166 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8167 .unwrap_or_default()
8168 }
8169
8170 pub fn language_server_for_local_buffer<'a>(
8171 &'a self,
8172 buffer: &'a Buffer,
8173 server_id: LanguageServerId,
8174 cx: &'a mut App,
8175 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8176 self.as_local()?
8177 .language_servers_for_buffer(buffer, cx)
8178 .find(|(_, s)| s.server_id() == server_id)
8179 }
8180
8181 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8182 self.diagnostic_summaries.remove(&id_to_remove);
8183 if let Some(local) = self.as_local_mut() {
8184 let to_remove = local.remove_worktree(id_to_remove, cx);
8185 for server in to_remove {
8186 self.language_server_statuses.remove(&server);
8187 }
8188 }
8189 }
8190
8191 fn invalidate_diagnostic_summaries_for_removed_entries(
8192 &mut self,
8193 worktree_id: WorktreeId,
8194 changes: &UpdatedEntriesSet,
8195 cx: &mut Context<Self>,
8196 ) {
8197 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8198 return;
8199 };
8200
8201 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8202 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8203 let downstream = self.downstream_client.clone();
8204
8205 for (path, _, _) in changes
8206 .iter()
8207 .filter(|(_, _, change)| *change == PathChange::Removed)
8208 {
8209 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8210 for (server_id, _) in &summaries_by_server_id {
8211 cleared_server_ids.insert(*server_id);
8212 if let Some((client, project_id)) = &downstream {
8213 client
8214 .send(proto::UpdateDiagnosticSummary {
8215 project_id: *project_id,
8216 worktree_id: worktree_id.to_proto(),
8217 summary: Some(proto::DiagnosticSummary {
8218 path: path.as_ref().to_proto(),
8219 language_server_id: server_id.0 as u64,
8220 error_count: 0,
8221 warning_count: 0,
8222 }),
8223 more_summaries: Vec::new(),
8224 })
8225 .ok();
8226 }
8227 }
8228 cleared_paths.push(ProjectPath {
8229 worktree_id,
8230 path: path.clone(),
8231 });
8232 }
8233 }
8234
8235 if !cleared_paths.is_empty() {
8236 for server_id in cleared_server_ids {
8237 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8238 server_id,
8239 paths: cleared_paths.clone(),
8240 });
8241 }
8242 }
8243 }
8244
8245 pub fn shared(
8246 &mut self,
8247 project_id: u64,
8248 downstream_client: AnyProtoClient,
8249 _: &mut Context<Self>,
8250 ) {
8251 self.downstream_client = Some((downstream_client.clone(), project_id));
8252
8253 for (server_id, status) in &self.language_server_statuses {
8254 if let Some(server) = self.language_server_for_id(*server_id) {
8255 downstream_client
8256 .send(proto::StartLanguageServer {
8257 project_id,
8258 server: Some(proto::LanguageServer {
8259 id: server_id.to_proto(),
8260 name: status.name.to_string(),
8261 worktree_id: status.worktree.map(|id| id.to_proto()),
8262 }),
8263 capabilities: serde_json::to_string(&server.capabilities())
8264 .expect("serializing server LSP capabilities"),
8265 })
8266 .log_err();
8267 }
8268 }
8269 }
8270
8271 pub fn disconnected_from_host(&mut self) {
8272 self.downstream_client.take();
8273 }
8274
8275 pub fn disconnected_from_ssh_remote(&mut self) {
8276 if let LspStoreMode::Remote(RemoteLspStore {
8277 upstream_client, ..
8278 }) = &mut self.mode
8279 {
8280 upstream_client.take();
8281 }
8282 }
8283
8284 pub(crate) fn set_language_server_statuses_from_proto(
8285 &mut self,
8286 project: WeakEntity<Project>,
8287 language_servers: Vec<proto::LanguageServer>,
8288 server_capabilities: Vec<String>,
8289 cx: &mut Context<Self>,
8290 ) {
8291 let lsp_logs = cx
8292 .try_global::<GlobalLogStore>()
8293 .map(|lsp_store| lsp_store.0.clone());
8294
8295 self.language_server_statuses = language_servers
8296 .into_iter()
8297 .zip(server_capabilities)
8298 .map(|(server, server_capabilities)| {
8299 let server_id = LanguageServerId(server.id as usize);
8300 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8301 self.lsp_server_capabilities
8302 .insert(server_id, server_capabilities);
8303 }
8304
8305 let name = LanguageServerName::from_proto(server.name);
8306 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8307
8308 if let Some(lsp_logs) = &lsp_logs {
8309 lsp_logs.update(cx, |lsp_logs, cx| {
8310 lsp_logs.add_language_server(
8311 // Only remote clients get their language servers set from proto
8312 LanguageServerKind::Remote {
8313 project: project.clone(),
8314 },
8315 server_id,
8316 Some(name.clone()),
8317 worktree,
8318 None,
8319 cx,
8320 );
8321 });
8322 }
8323
8324 (
8325 server_id,
8326 LanguageServerStatus {
8327 name,
8328 server_version: None,
8329 server_readable_version: None,
8330 pending_work: Default::default(),
8331 has_pending_diagnostic_updates: false,
8332 progress_tokens: Default::default(),
8333 worktree,
8334 binary: None,
8335 configuration: None,
8336 workspace_folders: BTreeSet::new(),
8337 process_id: None,
8338 },
8339 )
8340 })
8341 .collect();
8342 }
8343
8344 #[cfg(feature = "test-support")]
8345 pub fn update_diagnostic_entries(
8346 &mut self,
8347 server_id: LanguageServerId,
8348 abs_path: PathBuf,
8349 result_id: Option<SharedString>,
8350 version: Option<i32>,
8351 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8352 cx: &mut Context<Self>,
8353 ) -> anyhow::Result<()> {
8354 self.merge_diagnostic_entries(
8355 vec![DocumentDiagnosticsUpdate {
8356 diagnostics: DocumentDiagnostics {
8357 diagnostics,
8358 document_abs_path: abs_path,
8359 version,
8360 },
8361 result_id,
8362 server_id,
8363 disk_based_sources: Cow::Borrowed(&[]),
8364 registration_id: None,
8365 }],
8366 |_, _, _| false,
8367 cx,
8368 )?;
8369 Ok(())
8370 }
8371
8372 pub fn merge_diagnostic_entries<'a>(
8373 &mut self,
8374 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8375 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8376 cx: &mut Context<Self>,
8377 ) -> anyhow::Result<()> {
8378 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8379 let mut updated_diagnostics_paths = HashMap::default();
8380 for mut update in diagnostic_updates {
8381 let abs_path = &update.diagnostics.document_abs_path;
8382 let server_id = update.server_id;
8383 let Some((worktree, relative_path)) =
8384 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8385 else {
8386 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8387 return Ok(());
8388 };
8389
8390 let worktree_id = worktree.read(cx).id();
8391 let project_path = ProjectPath {
8392 worktree_id,
8393 path: relative_path,
8394 };
8395
8396 let document_uri = lsp::Uri::from_file_path(abs_path)
8397 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8398 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8399 let snapshot = buffer_handle.read(cx).snapshot();
8400 let buffer = buffer_handle.read(cx);
8401 let reused_diagnostics = buffer
8402 .buffer_diagnostics(Some(server_id))
8403 .iter()
8404 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8405 .map(|v| {
8406 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8407 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8408 DiagnosticEntry {
8409 range: start..end,
8410 diagnostic: v.diagnostic.clone(),
8411 }
8412 })
8413 .collect::<Vec<_>>();
8414
8415 self.as_local_mut()
8416 .context("cannot merge diagnostics on a remote LspStore")?
8417 .update_buffer_diagnostics(
8418 &buffer_handle,
8419 server_id,
8420 Some(update.registration_id),
8421 update.result_id,
8422 update.diagnostics.version,
8423 update.diagnostics.diagnostics.clone(),
8424 reused_diagnostics.clone(),
8425 cx,
8426 )?;
8427
8428 update.diagnostics.diagnostics.extend(reused_diagnostics);
8429 } else if let Some(local) = self.as_local() {
8430 let reused_diagnostics = local
8431 .diagnostics
8432 .get(&worktree_id)
8433 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8434 .and_then(|diagnostics_by_server_id| {
8435 diagnostics_by_server_id
8436 .binary_search_by_key(&server_id, |e| e.0)
8437 .ok()
8438 .map(|ix| &diagnostics_by_server_id[ix].1)
8439 })
8440 .into_iter()
8441 .flatten()
8442 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8443
8444 update
8445 .diagnostics
8446 .diagnostics
8447 .extend(reused_diagnostics.cloned());
8448 }
8449
8450 let updated = worktree.update(cx, |worktree, cx| {
8451 self.update_worktree_diagnostics(
8452 worktree.id(),
8453 server_id,
8454 project_path.path.clone(),
8455 update.diagnostics.diagnostics,
8456 cx,
8457 )
8458 })?;
8459 match updated {
8460 ControlFlow::Continue(new_summary) => {
8461 if let Some((project_id, new_summary)) = new_summary {
8462 match &mut diagnostics_summary {
8463 Some(diagnostics_summary) => {
8464 diagnostics_summary
8465 .more_summaries
8466 .push(proto::DiagnosticSummary {
8467 path: project_path.path.as_ref().to_proto(),
8468 language_server_id: server_id.0 as u64,
8469 error_count: new_summary.error_count,
8470 warning_count: new_summary.warning_count,
8471 })
8472 }
8473 None => {
8474 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8475 project_id,
8476 worktree_id: worktree_id.to_proto(),
8477 summary: Some(proto::DiagnosticSummary {
8478 path: project_path.path.as_ref().to_proto(),
8479 language_server_id: server_id.0 as u64,
8480 error_count: new_summary.error_count,
8481 warning_count: new_summary.warning_count,
8482 }),
8483 more_summaries: Vec::new(),
8484 })
8485 }
8486 }
8487 }
8488 updated_diagnostics_paths
8489 .entry(server_id)
8490 .or_insert_with(Vec::new)
8491 .push(project_path);
8492 }
8493 ControlFlow::Break(()) => {}
8494 }
8495 }
8496
8497 if let Some((diagnostics_summary, (downstream_client, _))) =
8498 diagnostics_summary.zip(self.downstream_client.as_ref())
8499 {
8500 downstream_client.send(diagnostics_summary).log_err();
8501 }
8502 for (server_id, paths) in updated_diagnostics_paths {
8503 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8504 }
8505 Ok(())
8506 }
8507
8508 fn update_worktree_diagnostics(
8509 &mut self,
8510 worktree_id: WorktreeId,
8511 server_id: LanguageServerId,
8512 path_in_worktree: Arc<RelPath>,
8513 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8514 _: &mut Context<Worktree>,
8515 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8516 let local = match &mut self.mode {
8517 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8518 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8519 };
8520
8521 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8522 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8523 let summaries_by_server_id = summaries_for_tree
8524 .entry(path_in_worktree.clone())
8525 .or_default();
8526
8527 let old_summary = summaries_by_server_id
8528 .remove(&server_id)
8529 .unwrap_or_default();
8530
8531 let new_summary = DiagnosticSummary::new(&diagnostics);
8532 if diagnostics.is_empty() {
8533 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8534 {
8535 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8536 diagnostics_by_server_id.remove(ix);
8537 }
8538 if diagnostics_by_server_id.is_empty() {
8539 diagnostics_for_tree.remove(&path_in_worktree);
8540 }
8541 }
8542 } else {
8543 summaries_by_server_id.insert(server_id, new_summary);
8544 let diagnostics_by_server_id = diagnostics_for_tree
8545 .entry(path_in_worktree.clone())
8546 .or_default();
8547 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8548 Ok(ix) => {
8549 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8550 }
8551 Err(ix) => {
8552 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8553 }
8554 }
8555 }
8556
8557 if !old_summary.is_empty() || !new_summary.is_empty() {
8558 if let Some((_, project_id)) = &self.downstream_client {
8559 Ok(ControlFlow::Continue(Some((
8560 *project_id,
8561 proto::DiagnosticSummary {
8562 path: path_in_worktree.to_proto(),
8563 language_server_id: server_id.0 as u64,
8564 error_count: new_summary.error_count as u32,
8565 warning_count: new_summary.warning_count as u32,
8566 },
8567 ))))
8568 } else {
8569 Ok(ControlFlow::Continue(None))
8570 }
8571 } else {
8572 Ok(ControlFlow::Break(()))
8573 }
8574 }
8575
8576 pub fn open_buffer_for_symbol(
8577 &mut self,
8578 symbol: &Symbol,
8579 cx: &mut Context<Self>,
8580 ) -> Task<Result<Entity<Buffer>>> {
8581 if let Some((client, project_id)) = self.upstream_client() {
8582 let request = client.request(proto::OpenBufferForSymbol {
8583 project_id,
8584 symbol: Some(Self::serialize_symbol(symbol)),
8585 });
8586 cx.spawn(async move |this, cx| {
8587 let response = request.await?;
8588 let buffer_id = BufferId::new(response.buffer_id)?;
8589 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8590 .await
8591 })
8592 } else if let Some(local) = self.as_local() {
8593 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8594 seed.worktree_id == symbol.source_worktree_id
8595 && state.id == symbol.source_language_server_id
8596 && symbol.language_server_name == seed.name
8597 });
8598 if !is_valid {
8599 return Task::ready(Err(anyhow!(
8600 "language server for worktree and language not found"
8601 )));
8602 };
8603
8604 let symbol_abs_path = match &symbol.path {
8605 SymbolLocation::InProject(project_path) => self
8606 .worktree_store
8607 .read(cx)
8608 .absolutize(&project_path, cx)
8609 .context("no such worktree"),
8610 SymbolLocation::OutsideProject {
8611 abs_path,
8612 signature: _,
8613 } => Ok(abs_path.to_path_buf()),
8614 };
8615 let symbol_abs_path = match symbol_abs_path {
8616 Ok(abs_path) => abs_path,
8617 Err(err) => return Task::ready(Err(err)),
8618 };
8619 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8620 uri
8621 } else {
8622 return Task::ready(Err(anyhow!("invalid symbol path")));
8623 };
8624
8625 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8626 } else {
8627 Task::ready(Err(anyhow!("no upstream client or local store")))
8628 }
8629 }
8630
8631 pub(crate) fn open_local_buffer_via_lsp(
8632 &mut self,
8633 abs_path: lsp::Uri,
8634 language_server_id: LanguageServerId,
8635 cx: &mut Context<Self>,
8636 ) -> Task<Result<Entity<Buffer>>> {
8637 let path_style = self.worktree_store.read(cx).path_style();
8638 cx.spawn(async move |lsp_store, cx| {
8639 // Escape percent-encoded string.
8640 let current_scheme = abs_path.scheme().to_owned();
8641 // Uri is immutable, so we can't modify the scheme
8642
8643 let abs_path = abs_path
8644 .to_file_path_ext(path_style)
8645 .map_err(|()| anyhow!("can't convert URI to path"))?;
8646 let p = abs_path.clone();
8647 let yarn_worktree = lsp_store
8648 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8649 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8650 cx.spawn(async move |this, cx| {
8651 let t = this
8652 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8653 .ok()?;
8654 t.await
8655 })
8656 }),
8657 None => Task::ready(None),
8658 })?
8659 .await;
8660 let (worktree_root_target, known_relative_path) =
8661 if let Some((zip_root, relative_path)) = yarn_worktree {
8662 (zip_root, Some(relative_path))
8663 } else {
8664 (Arc::<Path>::from(abs_path.as_path()), None)
8665 };
8666 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8667 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8668 worktree_store.find_worktree(&worktree_root_target, cx)
8669 })
8670 })?;
8671 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8672 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8673 (result.0, relative_path, None)
8674 } else {
8675 let worktree = lsp_store
8676 .update(cx, |lsp_store, cx| {
8677 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8678 worktree_store.create_worktree(&worktree_root_target, false, cx)
8679 })
8680 })?
8681 .await?;
8682 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8683 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8684 lsp_store
8685 .update(cx, |lsp_store, cx| {
8686 if let Some(local) = lsp_store.as_local_mut() {
8687 local.register_language_server_for_invisible_worktree(
8688 &worktree,
8689 language_server_id,
8690 cx,
8691 )
8692 }
8693 match lsp_store.language_server_statuses.get(&language_server_id) {
8694 Some(status) => status.worktree,
8695 None => None,
8696 }
8697 })
8698 .ok()
8699 .flatten()
8700 .zip(Some(worktree_root.clone()))
8701 } else {
8702 None
8703 };
8704 let relative_path = if let Some(known_path) = known_relative_path {
8705 known_path
8706 } else {
8707 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8708 .into_arc()
8709 };
8710 (worktree, relative_path, source_ws)
8711 };
8712 let project_path = ProjectPath {
8713 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8714 path: relative_path,
8715 };
8716 let buffer = lsp_store
8717 .update(cx, |lsp_store, cx| {
8718 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8719 buffer_store.open_buffer(project_path, cx)
8720 })
8721 })?
8722 .await?;
8723 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8724 if let Some((source_ws, worktree_root)) = source_ws {
8725 buffer.update(cx, |buffer, cx| {
8726 let settings = WorktreeSettings::get(
8727 Some(
8728 (&ProjectPath {
8729 worktree_id: source_ws,
8730 path: Arc::from(RelPath::empty()),
8731 })
8732 .into(),
8733 ),
8734 cx,
8735 );
8736 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8737 if is_read_only {
8738 buffer.set_capability(Capability::ReadOnly, cx);
8739 }
8740 });
8741 }
8742 Ok(buffer)
8743 })
8744 }
8745
8746 fn local_lsp_servers_for_buffer(
8747 &self,
8748 buffer: &Entity<Buffer>,
8749 cx: &mut Context<Self>,
8750 ) -> Vec<LanguageServerId> {
8751 let Some(local) = self.as_local() else {
8752 return Vec::new();
8753 };
8754
8755 let snapshot = buffer.read(cx).snapshot();
8756
8757 buffer.update(cx, |buffer, cx| {
8758 local
8759 .language_servers_for_buffer(buffer, cx)
8760 .map(|(_, server)| server.server_id())
8761 .filter(|server_id| {
8762 self.as_local().is_none_or(|local| {
8763 local
8764 .buffers_opened_in_servers
8765 .get(&snapshot.remote_id())
8766 .is_some_and(|servers| servers.contains(server_id))
8767 })
8768 })
8769 .collect()
8770 })
8771 }
8772
8773 fn request_multiple_lsp_locally<P, R>(
8774 &mut self,
8775 buffer: &Entity<Buffer>,
8776 position: Option<P>,
8777 request: R,
8778 cx: &mut Context<Self>,
8779 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8780 where
8781 P: ToOffset,
8782 R: LspCommand + Clone,
8783 <R::LspRequest as lsp::request::Request>::Result: Send,
8784 <R::LspRequest as lsp::request::Request>::Params: Send,
8785 {
8786 let Some(local) = self.as_local() else {
8787 return Task::ready(Vec::new());
8788 };
8789
8790 let snapshot = buffer.read(cx).snapshot();
8791 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8792
8793 let server_ids = buffer.update(cx, |buffer, cx| {
8794 local
8795 .language_servers_for_buffer(buffer, cx)
8796 .filter(|(adapter, _)| {
8797 scope
8798 .as_ref()
8799 .map(|scope| scope.language_allowed(&adapter.name))
8800 .unwrap_or(true)
8801 })
8802 .map(|(_, server)| server.server_id())
8803 .filter(|server_id| {
8804 self.as_local().is_none_or(|local| {
8805 local
8806 .buffers_opened_in_servers
8807 .get(&snapshot.remote_id())
8808 .is_some_and(|servers| servers.contains(server_id))
8809 })
8810 })
8811 .collect::<Vec<_>>()
8812 });
8813
8814 let mut response_results = server_ids
8815 .into_iter()
8816 .map(|server_id| {
8817 let task = self.request_lsp(
8818 buffer.clone(),
8819 LanguageServerToQuery::Other(server_id),
8820 request.clone(),
8821 cx,
8822 );
8823 async move { (server_id, task.await) }
8824 })
8825 .collect::<FuturesUnordered<_>>();
8826
8827 cx.background_spawn(async move {
8828 let mut responses = Vec::with_capacity(response_results.len());
8829 while let Some((server_id, response_result)) = response_results.next().await {
8830 match response_result {
8831 Ok(response) => responses.push((server_id, response)),
8832 // rust-analyzer likes to error with this when its still loading up
8833 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8834 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8835 }
8836 }
8837 responses
8838 })
8839 }
8840
8841 async fn handle_lsp_get_completions(
8842 this: Entity<Self>,
8843 envelope: TypedEnvelope<proto::GetCompletions>,
8844 mut cx: AsyncApp,
8845 ) -> Result<proto::GetCompletionsResponse> {
8846 let sender_id = envelope.original_sender_id().unwrap_or_default();
8847
8848 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8849 let buffer_handle = this.update(&mut cx, |this, cx| {
8850 this.buffer_store.read(cx).get_existing(buffer_id)
8851 })?;
8852 let request = GetCompletions::from_proto(
8853 envelope.payload,
8854 this.clone(),
8855 buffer_handle.clone(),
8856 cx.clone(),
8857 )
8858 .await?;
8859
8860 let server_to_query = match request.server_id {
8861 Some(server_id) => LanguageServerToQuery::Other(server_id),
8862 None => LanguageServerToQuery::FirstCapable,
8863 };
8864
8865 let response = this
8866 .update(&mut cx, |this, cx| {
8867 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8868 })
8869 .await?;
8870 this.update(&mut cx, |this, cx| {
8871 Ok(GetCompletions::response_to_proto(
8872 response,
8873 this,
8874 sender_id,
8875 &buffer_handle.read(cx).version(),
8876 cx,
8877 ))
8878 })
8879 }
8880
8881 async fn handle_lsp_command<T: LspCommand>(
8882 this: Entity<Self>,
8883 envelope: TypedEnvelope<T::ProtoRequest>,
8884 mut cx: AsyncApp,
8885 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8886 where
8887 <T::LspRequest as lsp::request::Request>::Params: Send,
8888 <T::LspRequest as lsp::request::Request>::Result: Send,
8889 {
8890 let sender_id = envelope.original_sender_id().unwrap_or_default();
8891 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8892 let buffer_handle = this.update(&mut cx, |this, cx| {
8893 this.buffer_store.read(cx).get_existing(buffer_id)
8894 })?;
8895 let request = T::from_proto(
8896 envelope.payload,
8897 this.clone(),
8898 buffer_handle.clone(),
8899 cx.clone(),
8900 )
8901 .await?;
8902 let response = this
8903 .update(&mut cx, |this, cx| {
8904 this.request_lsp(
8905 buffer_handle.clone(),
8906 LanguageServerToQuery::FirstCapable,
8907 request,
8908 cx,
8909 )
8910 })
8911 .await?;
8912 this.update(&mut cx, |this, cx| {
8913 Ok(T::response_to_proto(
8914 response,
8915 this,
8916 sender_id,
8917 &buffer_handle.read(cx).version(),
8918 cx,
8919 ))
8920 })
8921 }
8922
8923 async fn handle_lsp_query(
8924 lsp_store: Entity<Self>,
8925 envelope: TypedEnvelope<proto::LspQuery>,
8926 mut cx: AsyncApp,
8927 ) -> Result<proto::Ack> {
8928 use proto::lsp_query::Request;
8929 let sender_id = envelope.original_sender_id().unwrap_or_default();
8930 let lsp_query = envelope.payload;
8931 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8932 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8933 match lsp_query.request.context("invalid LSP query request")? {
8934 Request::GetReferences(get_references) => {
8935 let position = get_references.position.clone().and_then(deserialize_anchor);
8936 Self::query_lsp_locally::<GetReferences>(
8937 lsp_store,
8938 server_id,
8939 sender_id,
8940 lsp_request_id,
8941 get_references,
8942 position,
8943 &mut cx,
8944 )
8945 .await?;
8946 }
8947 Request::GetDocumentColor(get_document_color) => {
8948 Self::query_lsp_locally::<GetDocumentColor>(
8949 lsp_store,
8950 server_id,
8951 sender_id,
8952 lsp_request_id,
8953 get_document_color,
8954 None,
8955 &mut cx,
8956 )
8957 .await?;
8958 }
8959 Request::GetFoldingRanges(get_folding_ranges) => {
8960 Self::query_lsp_locally::<GetFoldingRanges>(
8961 lsp_store,
8962 server_id,
8963 sender_id,
8964 lsp_request_id,
8965 get_folding_ranges,
8966 None,
8967 &mut cx,
8968 )
8969 .await?;
8970 }
8971 Request::GetDocumentSymbols(get_document_symbols) => {
8972 Self::query_lsp_locally::<GetDocumentSymbols>(
8973 lsp_store,
8974 server_id,
8975 sender_id,
8976 lsp_request_id,
8977 get_document_symbols,
8978 None,
8979 &mut cx,
8980 )
8981 .await?;
8982 }
8983 Request::GetHover(get_hover) => {
8984 let position = get_hover.position.clone().and_then(deserialize_anchor);
8985 Self::query_lsp_locally::<GetHover>(
8986 lsp_store,
8987 server_id,
8988 sender_id,
8989 lsp_request_id,
8990 get_hover,
8991 position,
8992 &mut cx,
8993 )
8994 .await?;
8995 }
8996 Request::GetCodeActions(get_code_actions) => {
8997 Self::query_lsp_locally::<GetCodeActions>(
8998 lsp_store,
8999 server_id,
9000 sender_id,
9001 lsp_request_id,
9002 get_code_actions,
9003 None,
9004 &mut cx,
9005 )
9006 .await?;
9007 }
9008 Request::GetSignatureHelp(get_signature_help) => {
9009 let position = get_signature_help
9010 .position
9011 .clone()
9012 .and_then(deserialize_anchor);
9013 Self::query_lsp_locally::<GetSignatureHelp>(
9014 lsp_store,
9015 server_id,
9016 sender_id,
9017 lsp_request_id,
9018 get_signature_help,
9019 position,
9020 &mut cx,
9021 )
9022 .await?;
9023 }
9024 Request::GetCodeLens(get_code_lens) => {
9025 Self::query_lsp_locally::<GetCodeLens>(
9026 lsp_store,
9027 server_id,
9028 sender_id,
9029 lsp_request_id,
9030 get_code_lens,
9031 None,
9032 &mut cx,
9033 )
9034 .await?;
9035 }
9036 Request::GetDefinition(get_definition) => {
9037 let position = get_definition.position.clone().and_then(deserialize_anchor);
9038 Self::query_lsp_locally::<GetDefinitions>(
9039 lsp_store,
9040 server_id,
9041 sender_id,
9042 lsp_request_id,
9043 get_definition,
9044 position,
9045 &mut cx,
9046 )
9047 .await?;
9048 }
9049 Request::GetDeclaration(get_declaration) => {
9050 let position = get_declaration
9051 .position
9052 .clone()
9053 .and_then(deserialize_anchor);
9054 Self::query_lsp_locally::<GetDeclarations>(
9055 lsp_store,
9056 server_id,
9057 sender_id,
9058 lsp_request_id,
9059 get_declaration,
9060 position,
9061 &mut cx,
9062 )
9063 .await?;
9064 }
9065 Request::GetTypeDefinition(get_type_definition) => {
9066 let position = get_type_definition
9067 .position
9068 .clone()
9069 .and_then(deserialize_anchor);
9070 Self::query_lsp_locally::<GetTypeDefinitions>(
9071 lsp_store,
9072 server_id,
9073 sender_id,
9074 lsp_request_id,
9075 get_type_definition,
9076 position,
9077 &mut cx,
9078 )
9079 .await?;
9080 }
9081 Request::GetImplementation(get_implementation) => {
9082 let position = get_implementation
9083 .position
9084 .clone()
9085 .and_then(deserialize_anchor);
9086 Self::query_lsp_locally::<GetImplementations>(
9087 lsp_store,
9088 server_id,
9089 sender_id,
9090 lsp_request_id,
9091 get_implementation,
9092 position,
9093 &mut cx,
9094 )
9095 .await?;
9096 }
9097 Request::InlayHints(inlay_hints) => {
9098 let query_start = inlay_hints
9099 .start
9100 .clone()
9101 .and_then(deserialize_anchor)
9102 .context("invalid inlay hints range start")?;
9103 let query_end = inlay_hints
9104 .end
9105 .clone()
9106 .and_then(deserialize_anchor)
9107 .context("invalid inlay hints range end")?;
9108 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9109 &lsp_store,
9110 server_id,
9111 lsp_request_id,
9112 &inlay_hints,
9113 query_start..query_end,
9114 &mut cx,
9115 )
9116 .await
9117 .context("preparing inlay hints request")?;
9118 Self::query_lsp_locally::<InlayHints>(
9119 lsp_store,
9120 server_id,
9121 sender_id,
9122 lsp_request_id,
9123 inlay_hints,
9124 None,
9125 &mut cx,
9126 )
9127 .await
9128 .context("querying for inlay hints")?
9129 }
9130 //////////////////////////////
9131 // Below are LSP queries that need to fetch more data,
9132 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9133 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9134 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9135 &lsp_store,
9136 &get_document_diagnostics,
9137 &mut cx,
9138 )
9139 .await?;
9140 lsp_store.update(&mut cx, |lsp_store, cx| {
9141 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9142 let key = LspKey {
9143 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9144 server_queried: server_id,
9145 };
9146 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9147 ) {
9148 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9149 lsp_requests.clear();
9150 };
9151 }
9152
9153 lsp_data.lsp_requests.entry(key).or_default().insert(
9154 lsp_request_id,
9155 cx.spawn(async move |lsp_store, cx| {
9156 let diagnostics_pull = lsp_store
9157 .update(cx, |lsp_store, cx| {
9158 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9159 })
9160 .ok();
9161 if let Some(diagnostics_pull) = diagnostics_pull {
9162 match diagnostics_pull.await {
9163 Ok(()) => {}
9164 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9165 };
9166 }
9167 }),
9168 );
9169 });
9170 }
9171 Request::SemanticTokens(semantic_tokens) => {
9172 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9173 &lsp_store,
9174 &semantic_tokens,
9175 &mut cx,
9176 )
9177 .await?;
9178 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9179 lsp_store.update(&mut cx, |lsp_store, cx| {
9180 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9181 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9182 let key = LspKey {
9183 request_type: TypeId::of::<SemanticTokensFull>(),
9184 server_queried: server_id,
9185 };
9186 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9187 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9188 lsp_requests.clear();
9189 };
9190 }
9191
9192 lsp_data.lsp_requests.entry(key).or_default().insert(
9193 lsp_request_id,
9194 cx.spawn(async move |lsp_store, cx| {
9195 let tokens_fetch = lsp_store
9196 .update(cx, |lsp_store, cx| {
9197 lsp_store
9198 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9199 })
9200 .ok();
9201 if let Some(tokens_fetch) = tokens_fetch {
9202 let new_tokens = tokens_fetch.await;
9203 if let Some(new_tokens) = new_tokens {
9204 lsp_store
9205 .update(cx, |lsp_store, cx| {
9206 let response = new_tokens
9207 .into_iter()
9208 .map(|(server_id, response)| {
9209 (
9210 server_id.to_proto(),
9211 SemanticTokensFull::response_to_proto(
9212 response,
9213 lsp_store,
9214 sender_id,
9215 &buffer_version,
9216 cx,
9217 ),
9218 )
9219 })
9220 .collect::<HashMap<_, _>>();
9221 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9222 project_id,
9223 lsp_request_id,
9224 response,
9225 ) {
9226 Ok(()) => {}
9227 Err(e) => {
9228 log::error!(
9229 "Failed to send semantic tokens LSP response: {e:#}",
9230 )
9231 }
9232 }
9233 })
9234 .ok();
9235 }
9236 }
9237 }),
9238 );
9239 }
9240 });
9241 }
9242 }
9243 Ok(proto::Ack {})
9244 }
9245
9246 async fn handle_lsp_query_response(
9247 lsp_store: Entity<Self>,
9248 envelope: TypedEnvelope<proto::LspQueryResponse>,
9249 cx: AsyncApp,
9250 ) -> Result<()> {
9251 lsp_store.read_with(&cx, |lsp_store, _| {
9252 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9253 upstream_client.handle_lsp_response(envelope.clone());
9254 }
9255 });
9256 Ok(())
9257 }
9258
9259 async fn handle_apply_code_action(
9260 this: Entity<Self>,
9261 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9262 mut cx: AsyncApp,
9263 ) -> Result<proto::ApplyCodeActionResponse> {
9264 let sender_id = envelope.original_sender_id().unwrap_or_default();
9265 let action =
9266 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9267 let apply_code_action = this.update(&mut cx, |this, cx| {
9268 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9269 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9270 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9271 })?;
9272
9273 let project_transaction = apply_code_action.await?;
9274 let project_transaction = this.update(&mut cx, |this, cx| {
9275 this.buffer_store.update(cx, |buffer_store, cx| {
9276 buffer_store.serialize_project_transaction_for_peer(
9277 project_transaction,
9278 sender_id,
9279 cx,
9280 )
9281 })
9282 });
9283 Ok(proto::ApplyCodeActionResponse {
9284 transaction: Some(project_transaction),
9285 })
9286 }
9287
9288 async fn handle_register_buffer_with_language_servers(
9289 this: Entity<Self>,
9290 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9291 mut cx: AsyncApp,
9292 ) -> Result<proto::Ack> {
9293 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9294 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9295 this.update(&mut cx, |this, cx| {
9296 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9297 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9298 project_id: upstream_project_id,
9299 buffer_id: buffer_id.to_proto(),
9300 only_servers: envelope.payload.only_servers,
9301 });
9302 }
9303
9304 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9305 anyhow::bail!("buffer is not open");
9306 };
9307
9308 let handle = this.register_buffer_with_language_servers(
9309 &buffer,
9310 envelope
9311 .payload
9312 .only_servers
9313 .into_iter()
9314 .filter_map(|selector| {
9315 Some(match selector.selector? {
9316 proto::language_server_selector::Selector::ServerId(server_id) => {
9317 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9318 }
9319 proto::language_server_selector::Selector::Name(name) => {
9320 LanguageServerSelector::Name(LanguageServerName(
9321 SharedString::from(name),
9322 ))
9323 }
9324 })
9325 })
9326 .collect(),
9327 false,
9328 cx,
9329 );
9330 // Pull diagnostics for the buffer even if it was already registered.
9331 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9332 // but it's unclear if we need it.
9333 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9334 .detach();
9335 this.buffer_store().update(cx, |buffer_store, _| {
9336 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9337 });
9338
9339 Ok(())
9340 })?;
9341 Ok(proto::Ack {})
9342 }
9343
9344 async fn handle_rename_project_entry(
9345 this: Entity<Self>,
9346 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9347 mut cx: AsyncApp,
9348 ) -> Result<proto::ProjectEntryResponse> {
9349 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9350 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9351 let new_path =
9352 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9353
9354 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9355 .update(&mut cx, |this, cx| {
9356 let (worktree, entry) = this
9357 .worktree_store
9358 .read(cx)
9359 .worktree_and_entry_for_id(entry_id, cx)?;
9360 let new_worktree = this
9361 .worktree_store
9362 .read(cx)
9363 .worktree_for_id(new_worktree_id, cx)?;
9364 Some((
9365 this.worktree_store.clone(),
9366 worktree,
9367 new_worktree,
9368 entry.clone(),
9369 ))
9370 })
9371 .context("worktree not found")?;
9372 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9373 (worktree.absolutize(&old_entry.path), worktree.id())
9374 });
9375 let new_abs_path =
9376 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9377
9378 let _transaction = Self::will_rename_entry(
9379 this.downgrade(),
9380 old_worktree_id,
9381 &old_abs_path,
9382 &new_abs_path,
9383 old_entry.is_dir(),
9384 cx.clone(),
9385 )
9386 .await;
9387 let response = WorktreeStore::handle_rename_project_entry(
9388 worktree_store,
9389 envelope.payload,
9390 cx.clone(),
9391 )
9392 .await;
9393 this.read_with(&cx, |this, _| {
9394 this.did_rename_entry(
9395 old_worktree_id,
9396 &old_abs_path,
9397 &new_abs_path,
9398 old_entry.is_dir(),
9399 );
9400 });
9401 response
9402 }
9403
9404 async fn handle_update_diagnostic_summary(
9405 this: Entity<Self>,
9406 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9407 mut cx: AsyncApp,
9408 ) -> Result<()> {
9409 this.update(&mut cx, |lsp_store, cx| {
9410 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9411 let mut updated_diagnostics_paths = HashMap::default();
9412 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9413 for message_summary in envelope
9414 .payload
9415 .summary
9416 .into_iter()
9417 .chain(envelope.payload.more_summaries)
9418 {
9419 let project_path = ProjectPath {
9420 worktree_id,
9421 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9422 };
9423 let path = project_path.path.clone();
9424 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9425 let summary = DiagnosticSummary {
9426 error_count: message_summary.error_count as usize,
9427 warning_count: message_summary.warning_count as usize,
9428 };
9429
9430 if summary.is_empty() {
9431 if let Some(worktree_summaries) =
9432 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9433 && let Some(summaries) = worktree_summaries.get_mut(&path)
9434 {
9435 summaries.remove(&server_id);
9436 if summaries.is_empty() {
9437 worktree_summaries.remove(&path);
9438 }
9439 }
9440 } else {
9441 lsp_store
9442 .diagnostic_summaries
9443 .entry(worktree_id)
9444 .or_default()
9445 .entry(path)
9446 .or_default()
9447 .insert(server_id, summary);
9448 }
9449
9450 if let Some((_, project_id)) = &lsp_store.downstream_client {
9451 match &mut diagnostics_summary {
9452 Some(diagnostics_summary) => {
9453 diagnostics_summary
9454 .more_summaries
9455 .push(proto::DiagnosticSummary {
9456 path: project_path.path.as_ref().to_proto(),
9457 language_server_id: server_id.0 as u64,
9458 error_count: summary.error_count as u32,
9459 warning_count: summary.warning_count as u32,
9460 })
9461 }
9462 None => {
9463 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9464 project_id: *project_id,
9465 worktree_id: worktree_id.to_proto(),
9466 summary: Some(proto::DiagnosticSummary {
9467 path: project_path.path.as_ref().to_proto(),
9468 language_server_id: server_id.0 as u64,
9469 error_count: summary.error_count as u32,
9470 warning_count: summary.warning_count as u32,
9471 }),
9472 more_summaries: Vec::new(),
9473 })
9474 }
9475 }
9476 }
9477 updated_diagnostics_paths
9478 .entry(server_id)
9479 .or_insert_with(Vec::new)
9480 .push(project_path);
9481 }
9482
9483 if let Some((diagnostics_summary, (downstream_client, _))) =
9484 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9485 {
9486 downstream_client.send(diagnostics_summary).log_err();
9487 }
9488 for (server_id, paths) in updated_diagnostics_paths {
9489 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9490 }
9491 Ok(())
9492 })
9493 }
9494
9495 async fn handle_start_language_server(
9496 lsp_store: Entity<Self>,
9497 envelope: TypedEnvelope<proto::StartLanguageServer>,
9498 mut cx: AsyncApp,
9499 ) -> Result<()> {
9500 let server = envelope.payload.server.context("invalid server")?;
9501 let server_capabilities =
9502 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9503 .with_context(|| {
9504 format!(
9505 "incorrect server capabilities {}",
9506 envelope.payload.capabilities
9507 )
9508 })?;
9509 lsp_store.update(&mut cx, |lsp_store, cx| {
9510 let server_id = LanguageServerId(server.id as usize);
9511 let server_name = LanguageServerName::from_proto(server.name.clone());
9512 lsp_store
9513 .lsp_server_capabilities
9514 .insert(server_id, server_capabilities);
9515 lsp_store.language_server_statuses.insert(
9516 server_id,
9517 LanguageServerStatus {
9518 name: server_name.clone(),
9519 server_version: None,
9520 server_readable_version: None,
9521 pending_work: Default::default(),
9522 has_pending_diagnostic_updates: false,
9523 progress_tokens: Default::default(),
9524 worktree: server.worktree_id.map(WorktreeId::from_proto),
9525 binary: None,
9526 configuration: None,
9527 workspace_folders: BTreeSet::new(),
9528 process_id: None,
9529 },
9530 );
9531 cx.emit(LspStoreEvent::LanguageServerAdded(
9532 server_id,
9533 server_name,
9534 server.worktree_id.map(WorktreeId::from_proto),
9535 ));
9536 cx.notify();
9537 });
9538 Ok(())
9539 }
9540
9541 async fn handle_update_language_server(
9542 lsp_store: Entity<Self>,
9543 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9544 mut cx: AsyncApp,
9545 ) -> Result<()> {
9546 lsp_store.update(&mut cx, |lsp_store, cx| {
9547 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9548
9549 match envelope.payload.variant.context("invalid variant")? {
9550 proto::update_language_server::Variant::WorkStart(payload) => {
9551 lsp_store.on_lsp_work_start(
9552 language_server_id,
9553 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9554 .context("invalid progress token value")?,
9555 LanguageServerProgress {
9556 title: payload.title,
9557 is_disk_based_diagnostics_progress: false,
9558 is_cancellable: payload.is_cancellable.unwrap_or(false),
9559 message: payload.message,
9560 percentage: payload.percentage.map(|p| p as usize),
9561 last_update_at: cx.background_executor().now(),
9562 },
9563 cx,
9564 );
9565 }
9566 proto::update_language_server::Variant::WorkProgress(payload) => {
9567 lsp_store.on_lsp_work_progress(
9568 language_server_id,
9569 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9570 .context("invalid progress token value")?,
9571 LanguageServerProgress {
9572 title: None,
9573 is_disk_based_diagnostics_progress: false,
9574 is_cancellable: payload.is_cancellable.unwrap_or(false),
9575 message: payload.message,
9576 percentage: payload.percentage.map(|p| p as usize),
9577 last_update_at: cx.background_executor().now(),
9578 },
9579 cx,
9580 );
9581 }
9582
9583 proto::update_language_server::Variant::WorkEnd(payload) => {
9584 lsp_store.on_lsp_work_end(
9585 language_server_id,
9586 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9587 .context("invalid progress token value")?,
9588 cx,
9589 );
9590 }
9591
9592 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9593 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9594 }
9595
9596 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9597 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9598 }
9599
9600 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9601 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9602 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9603 cx.emit(LspStoreEvent::LanguageServerUpdate {
9604 language_server_id,
9605 name: envelope
9606 .payload
9607 .server_name
9608 .map(SharedString::new)
9609 .map(LanguageServerName),
9610 message: non_lsp,
9611 });
9612 }
9613 }
9614
9615 Ok(())
9616 })
9617 }
9618
9619 async fn handle_language_server_log(
9620 this: Entity<Self>,
9621 envelope: TypedEnvelope<proto::LanguageServerLog>,
9622 mut cx: AsyncApp,
9623 ) -> Result<()> {
9624 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9625 let log_type = envelope
9626 .payload
9627 .log_type
9628 .map(LanguageServerLogType::from_proto)
9629 .context("invalid language server log type")?;
9630
9631 let message = envelope.payload.message;
9632
9633 this.update(&mut cx, |_, cx| {
9634 cx.emit(LspStoreEvent::LanguageServerLog(
9635 language_server_id,
9636 log_type,
9637 message,
9638 ));
9639 });
9640 Ok(())
9641 }
9642
9643 async fn handle_lsp_ext_cancel_flycheck(
9644 lsp_store: Entity<Self>,
9645 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9646 cx: AsyncApp,
9647 ) -> Result<proto::Ack> {
9648 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9649 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9650 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9651 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9652 } else {
9653 None
9654 }
9655 });
9656 if let Some(task) = task {
9657 task.context("handling lsp ext cancel flycheck")?;
9658 }
9659
9660 Ok(proto::Ack {})
9661 }
9662
9663 async fn handle_lsp_ext_run_flycheck(
9664 lsp_store: Entity<Self>,
9665 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9666 mut cx: AsyncApp,
9667 ) -> Result<proto::Ack> {
9668 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9669 lsp_store.update(&mut cx, |lsp_store, cx| {
9670 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9671 let text_document = if envelope.payload.current_file_only {
9672 let buffer_id = envelope
9673 .payload
9674 .buffer_id
9675 .map(|id| BufferId::new(id))
9676 .transpose()?;
9677 buffer_id
9678 .and_then(|buffer_id| {
9679 lsp_store
9680 .buffer_store()
9681 .read(cx)
9682 .get(buffer_id)
9683 .and_then(|buffer| {
9684 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9685 })
9686 .map(|path| make_text_document_identifier(&path))
9687 })
9688 .transpose()?
9689 } else {
9690 None
9691 };
9692 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9693 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9694 )?;
9695 }
9696 anyhow::Ok(())
9697 })?;
9698
9699 Ok(proto::Ack {})
9700 }
9701
9702 async fn handle_lsp_ext_clear_flycheck(
9703 lsp_store: Entity<Self>,
9704 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9705 cx: AsyncApp,
9706 ) -> Result<proto::Ack> {
9707 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9708 lsp_store.read_with(&cx, |lsp_store, _| {
9709 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9710 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9711 } else {
9712 None
9713 }
9714 });
9715
9716 Ok(proto::Ack {})
9717 }
9718
9719 pub fn disk_based_diagnostics_started(
9720 &mut self,
9721 language_server_id: LanguageServerId,
9722 cx: &mut Context<Self>,
9723 ) {
9724 if let Some(language_server_status) =
9725 self.language_server_statuses.get_mut(&language_server_id)
9726 {
9727 language_server_status.has_pending_diagnostic_updates = true;
9728 }
9729
9730 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9731 cx.emit(LspStoreEvent::LanguageServerUpdate {
9732 language_server_id,
9733 name: self
9734 .language_server_adapter_for_id(language_server_id)
9735 .map(|adapter| adapter.name()),
9736 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9737 Default::default(),
9738 ),
9739 })
9740 }
9741
9742 pub fn disk_based_diagnostics_finished(
9743 &mut self,
9744 language_server_id: LanguageServerId,
9745 cx: &mut Context<Self>,
9746 ) {
9747 if let Some(language_server_status) =
9748 self.language_server_statuses.get_mut(&language_server_id)
9749 {
9750 language_server_status.has_pending_diagnostic_updates = false;
9751 }
9752
9753 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9754 cx.emit(LspStoreEvent::LanguageServerUpdate {
9755 language_server_id,
9756 name: self
9757 .language_server_adapter_for_id(language_server_id)
9758 .map(|adapter| adapter.name()),
9759 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9760 Default::default(),
9761 ),
9762 })
9763 }
9764
9765 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9766 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9767 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9768 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9769 // the language server might take some time to publish diagnostics.
9770 fn simulate_disk_based_diagnostics_events_if_needed(
9771 &mut self,
9772 language_server_id: LanguageServerId,
9773 cx: &mut Context<Self>,
9774 ) {
9775 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9776
9777 let Some(LanguageServerState::Running {
9778 simulate_disk_based_diagnostics_completion,
9779 adapter,
9780 ..
9781 }) = self
9782 .as_local_mut()
9783 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9784 else {
9785 return;
9786 };
9787
9788 if adapter.disk_based_diagnostics_progress_token.is_some() {
9789 return;
9790 }
9791
9792 let prev_task =
9793 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9794 cx.background_executor()
9795 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9796 .await;
9797
9798 this.update(cx, |this, cx| {
9799 this.disk_based_diagnostics_finished(language_server_id, cx);
9800
9801 if let Some(LanguageServerState::Running {
9802 simulate_disk_based_diagnostics_completion,
9803 ..
9804 }) = this.as_local_mut().and_then(|local_store| {
9805 local_store.language_servers.get_mut(&language_server_id)
9806 }) {
9807 *simulate_disk_based_diagnostics_completion = None;
9808 }
9809 })
9810 .ok();
9811 }));
9812
9813 if prev_task.is_none() {
9814 self.disk_based_diagnostics_started(language_server_id, cx);
9815 }
9816 }
9817
9818 pub fn language_server_statuses(
9819 &self,
9820 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9821 self.language_server_statuses
9822 .iter()
9823 .map(|(key, value)| (*key, value))
9824 }
9825
9826 pub(super) fn did_rename_entry(
9827 &self,
9828 worktree_id: WorktreeId,
9829 old_path: &Path,
9830 new_path: &Path,
9831 is_dir: bool,
9832 ) {
9833 maybe!({
9834 let local_store = self.as_local()?;
9835
9836 let old_uri = lsp::Uri::from_file_path(old_path)
9837 .ok()
9838 .map(|uri| uri.to_string())?;
9839 let new_uri = lsp::Uri::from_file_path(new_path)
9840 .ok()
9841 .map(|uri| uri.to_string())?;
9842
9843 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9844 let Some(filter) = local_store
9845 .language_server_paths_watched_for_rename
9846 .get(&language_server.server_id())
9847 else {
9848 continue;
9849 };
9850
9851 if filter.should_send_did_rename(&old_uri, is_dir) {
9852 language_server
9853 .notify::<DidRenameFiles>(RenameFilesParams {
9854 files: vec![FileRename {
9855 old_uri: old_uri.clone(),
9856 new_uri: new_uri.clone(),
9857 }],
9858 })
9859 .ok();
9860 }
9861 }
9862 Some(())
9863 });
9864 }
9865
9866 pub(super) fn will_rename_entry(
9867 this: WeakEntity<Self>,
9868 worktree_id: WorktreeId,
9869 old_path: &Path,
9870 new_path: &Path,
9871 is_dir: bool,
9872 cx: AsyncApp,
9873 ) -> Task<ProjectTransaction> {
9874 let old_uri = lsp::Uri::from_file_path(old_path)
9875 .ok()
9876 .map(|uri| uri.to_string());
9877 let new_uri = lsp::Uri::from_file_path(new_path)
9878 .ok()
9879 .map(|uri| uri.to_string());
9880 cx.spawn(async move |cx| {
9881 let mut tasks = vec![];
9882 this.update(cx, |this, cx| {
9883 let local_store = this.as_local()?;
9884 let old_uri = old_uri?;
9885 let new_uri = new_uri?;
9886 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9887 let Some(filter) = local_store
9888 .language_server_paths_watched_for_rename
9889 .get(&language_server.server_id())
9890 else {
9891 continue;
9892 };
9893
9894 if !filter.should_send_will_rename(&old_uri, is_dir) {
9895 continue;
9896 }
9897 let request_timeout = ProjectSettings::get_global(cx)
9898 .global_lsp_settings
9899 .get_request_timeout();
9900
9901 let apply_edit = cx.spawn({
9902 let old_uri = old_uri.clone();
9903 let new_uri = new_uri.clone();
9904 let language_server = language_server.clone();
9905 async move |this, cx| {
9906 let edit = language_server
9907 .request::<WillRenameFiles>(
9908 RenameFilesParams {
9909 files: vec![FileRename { old_uri, new_uri }],
9910 },
9911 request_timeout,
9912 )
9913 .await
9914 .into_response()
9915 .context("will rename files")
9916 .log_err()
9917 .flatten()?;
9918
9919 LocalLspStore::deserialize_workspace_edit(
9920 this.upgrade()?,
9921 edit,
9922 false,
9923 language_server.clone(),
9924 cx,
9925 )
9926 .await
9927 .ok()
9928 }
9929 });
9930 tasks.push(apply_edit);
9931 }
9932 Some(())
9933 })
9934 .ok()
9935 .flatten();
9936 let mut merged_transaction = ProjectTransaction::default();
9937 for task in tasks {
9938 // Await on tasks sequentially so that the order of application of edits is deterministic
9939 // (at least with regards to the order of registration of language servers)
9940 if let Some(transaction) = task.await {
9941 for (buffer, buffer_transaction) in transaction.0 {
9942 merged_transaction.0.insert(buffer, buffer_transaction);
9943 }
9944 }
9945 }
9946 merged_transaction
9947 })
9948 }
9949
9950 fn lsp_notify_abs_paths_changed(
9951 &mut self,
9952 server_id: LanguageServerId,
9953 changes: Vec<PathEvent>,
9954 ) {
9955 maybe!({
9956 let server = self.language_server_for_id(server_id)?;
9957 let changes = changes
9958 .into_iter()
9959 .filter_map(|event| {
9960 let typ = match event.kind? {
9961 PathEventKind::Created => lsp::FileChangeType::CREATED,
9962 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9963 PathEventKind::Changed | PathEventKind::Rescan => {
9964 lsp::FileChangeType::CHANGED
9965 }
9966 };
9967 Some(lsp::FileEvent {
9968 uri: file_path_to_lsp_url(&event.path).log_err()?,
9969 typ,
9970 })
9971 })
9972 .collect::<Vec<_>>();
9973 if !changes.is_empty() {
9974 server
9975 .notify::<lsp::notification::DidChangeWatchedFiles>(
9976 lsp::DidChangeWatchedFilesParams { changes },
9977 )
9978 .ok();
9979 }
9980 Some(())
9981 });
9982 }
9983
9984 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9985 self.as_local()?.language_server_for_id(id)
9986 }
9987
9988 fn on_lsp_progress(
9989 &mut self,
9990 progress_params: lsp::ProgressParams,
9991 language_server_id: LanguageServerId,
9992 disk_based_diagnostics_progress_token: Option<String>,
9993 cx: &mut Context<Self>,
9994 ) {
9995 match progress_params.value {
9996 lsp::ProgressParamsValue::WorkDone(progress) => {
9997 self.handle_work_done_progress(
9998 progress,
9999 language_server_id,
10000 disk_based_diagnostics_progress_token,
10001 ProgressToken::from_lsp(progress_params.token),
10002 cx,
10003 );
10004 }
10005 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10006 let registration_id = match progress_params.token {
10007 lsp::NumberOrString::Number(_) => None,
10008 lsp::NumberOrString::String(token) => token
10009 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10010 .map(|(_, id)| id.to_owned()),
10011 };
10012 if let Some(LanguageServerState::Running {
10013 workspace_diagnostics_refresh_tasks,
10014 ..
10015 }) = self
10016 .as_local_mut()
10017 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10018 && let Some(workspace_diagnostics) =
10019 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10020 {
10021 workspace_diagnostics.progress_tx.try_send(()).ok();
10022 self.apply_workspace_diagnostic_report(
10023 language_server_id,
10024 report,
10025 registration_id.map(SharedString::from),
10026 cx,
10027 )
10028 }
10029 }
10030 }
10031 }
10032
10033 fn handle_work_done_progress(
10034 &mut self,
10035 progress: lsp::WorkDoneProgress,
10036 language_server_id: LanguageServerId,
10037 disk_based_diagnostics_progress_token: Option<String>,
10038 token: ProgressToken,
10039 cx: &mut Context<Self>,
10040 ) {
10041 let language_server_status =
10042 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10043 status
10044 } else {
10045 return;
10046 };
10047
10048 if !language_server_status.progress_tokens.contains(&token) {
10049 return;
10050 }
10051
10052 let is_disk_based_diagnostics_progress =
10053 if let (Some(disk_based_token), ProgressToken::String(token)) =
10054 (&disk_based_diagnostics_progress_token, &token)
10055 {
10056 token.starts_with(disk_based_token)
10057 } else {
10058 false
10059 };
10060
10061 match progress {
10062 lsp::WorkDoneProgress::Begin(report) => {
10063 if is_disk_based_diagnostics_progress {
10064 self.disk_based_diagnostics_started(language_server_id, cx);
10065 }
10066 self.on_lsp_work_start(
10067 language_server_id,
10068 token.clone(),
10069 LanguageServerProgress {
10070 title: Some(report.title),
10071 is_disk_based_diagnostics_progress,
10072 is_cancellable: report.cancellable.unwrap_or(false),
10073 message: report.message.clone(),
10074 percentage: report.percentage.map(|p| p as usize),
10075 last_update_at: cx.background_executor().now(),
10076 },
10077 cx,
10078 );
10079 }
10080 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10081 language_server_id,
10082 token,
10083 LanguageServerProgress {
10084 title: None,
10085 is_disk_based_diagnostics_progress,
10086 is_cancellable: report.cancellable.unwrap_or(false),
10087 message: report.message,
10088 percentage: report.percentage.map(|p| p as usize),
10089 last_update_at: cx.background_executor().now(),
10090 },
10091 cx,
10092 ),
10093 lsp::WorkDoneProgress::End(_) => {
10094 language_server_status.progress_tokens.remove(&token);
10095 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10096 if is_disk_based_diagnostics_progress {
10097 self.disk_based_diagnostics_finished(language_server_id, cx);
10098 }
10099 }
10100 }
10101 }
10102
10103 fn on_lsp_work_start(
10104 &mut self,
10105 language_server_id: LanguageServerId,
10106 token: ProgressToken,
10107 progress: LanguageServerProgress,
10108 cx: &mut Context<Self>,
10109 ) {
10110 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10111 status.pending_work.insert(token.clone(), progress.clone());
10112 cx.notify();
10113 }
10114 cx.emit(LspStoreEvent::LanguageServerUpdate {
10115 language_server_id,
10116 name: self
10117 .language_server_adapter_for_id(language_server_id)
10118 .map(|adapter| adapter.name()),
10119 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10120 token: Some(token.to_proto()),
10121 title: progress.title,
10122 message: progress.message,
10123 percentage: progress.percentage.map(|p| p as u32),
10124 is_cancellable: Some(progress.is_cancellable),
10125 }),
10126 })
10127 }
10128
10129 fn on_lsp_work_progress(
10130 &mut self,
10131 language_server_id: LanguageServerId,
10132 token: ProgressToken,
10133 progress: LanguageServerProgress,
10134 cx: &mut Context<Self>,
10135 ) {
10136 let mut did_update = false;
10137 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10138 match status.pending_work.entry(token.clone()) {
10139 btree_map::Entry::Vacant(entry) => {
10140 entry.insert(progress.clone());
10141 did_update = true;
10142 }
10143 btree_map::Entry::Occupied(mut entry) => {
10144 let entry = entry.get_mut();
10145 if (progress.last_update_at - entry.last_update_at)
10146 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10147 {
10148 entry.last_update_at = progress.last_update_at;
10149 if progress.message.is_some() {
10150 entry.message = progress.message.clone();
10151 }
10152 if progress.percentage.is_some() {
10153 entry.percentage = progress.percentage;
10154 }
10155 if progress.is_cancellable != entry.is_cancellable {
10156 entry.is_cancellable = progress.is_cancellable;
10157 }
10158 did_update = true;
10159 }
10160 }
10161 }
10162 }
10163
10164 if did_update {
10165 cx.emit(LspStoreEvent::LanguageServerUpdate {
10166 language_server_id,
10167 name: self
10168 .language_server_adapter_for_id(language_server_id)
10169 .map(|adapter| adapter.name()),
10170 message: proto::update_language_server::Variant::WorkProgress(
10171 proto::LspWorkProgress {
10172 token: Some(token.to_proto()),
10173 message: progress.message,
10174 percentage: progress.percentage.map(|p| p as u32),
10175 is_cancellable: Some(progress.is_cancellable),
10176 },
10177 ),
10178 })
10179 }
10180 }
10181
10182 fn on_lsp_work_end(
10183 &mut self,
10184 language_server_id: LanguageServerId,
10185 token: ProgressToken,
10186 cx: &mut Context<Self>,
10187 ) {
10188 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10189 if let Some(work) = status.pending_work.remove(&token)
10190 && !work.is_disk_based_diagnostics_progress
10191 {
10192 cx.emit(LspStoreEvent::RefreshInlayHints {
10193 server_id: language_server_id,
10194 request_id: None,
10195 });
10196 }
10197 cx.notify();
10198 }
10199
10200 cx.emit(LspStoreEvent::LanguageServerUpdate {
10201 language_server_id,
10202 name: self
10203 .language_server_adapter_for_id(language_server_id)
10204 .map(|adapter| adapter.name()),
10205 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10206 token: Some(token.to_proto()),
10207 }),
10208 })
10209 }
10210
10211 pub async fn handle_resolve_completion_documentation(
10212 this: Entity<Self>,
10213 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10214 mut cx: AsyncApp,
10215 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10216 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10217
10218 let completion = this
10219 .read_with(&cx, |this, cx| {
10220 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10221 let server = this
10222 .language_server_for_id(id)
10223 .with_context(|| format!("No language server {id}"))?;
10224
10225 let request_timeout = ProjectSettings::get_global(cx)
10226 .global_lsp_settings
10227 .get_request_timeout();
10228
10229 anyhow::Ok(cx.background_spawn(async move {
10230 let can_resolve = server
10231 .capabilities()
10232 .completion_provider
10233 .as_ref()
10234 .and_then(|options| options.resolve_provider)
10235 .unwrap_or(false);
10236 if can_resolve {
10237 server
10238 .request::<lsp::request::ResolveCompletionItem>(
10239 lsp_completion,
10240 request_timeout,
10241 )
10242 .await
10243 .into_response()
10244 .context("resolve completion item")
10245 } else {
10246 anyhow::Ok(lsp_completion)
10247 }
10248 }))
10249 })?
10250 .await?;
10251
10252 let mut documentation_is_markdown = false;
10253 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10254 let documentation = match completion.documentation {
10255 Some(lsp::Documentation::String(text)) => text,
10256
10257 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10258 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10259 value
10260 }
10261
10262 _ => String::new(),
10263 };
10264
10265 // If we have a new buffer_id, that means we're talking to a new client
10266 // and want to check for new text_edits in the completion too.
10267 let mut old_replace_start = None;
10268 let mut old_replace_end = None;
10269 let mut old_insert_start = None;
10270 let mut old_insert_end = None;
10271 let mut new_text = String::default();
10272 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10273 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10274 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10275 anyhow::Ok(buffer.read(cx).snapshot())
10276 })?;
10277
10278 if let Some(text_edit) = completion.text_edit.as_ref() {
10279 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10280
10281 if let Some(mut edit) = edit {
10282 LineEnding::normalize(&mut edit.new_text);
10283
10284 new_text = edit.new_text;
10285 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10286 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10287 if let Some(insert_range) = edit.insert_range {
10288 old_insert_start = Some(serialize_anchor(&insert_range.start));
10289 old_insert_end = Some(serialize_anchor(&insert_range.end));
10290 }
10291 }
10292 }
10293 }
10294
10295 Ok(proto::ResolveCompletionDocumentationResponse {
10296 documentation,
10297 documentation_is_markdown,
10298 old_replace_start,
10299 old_replace_end,
10300 new_text,
10301 lsp_completion,
10302 old_insert_start,
10303 old_insert_end,
10304 })
10305 }
10306
10307 async fn handle_on_type_formatting(
10308 this: Entity<Self>,
10309 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10310 mut cx: AsyncApp,
10311 ) -> Result<proto::OnTypeFormattingResponse> {
10312 let on_type_formatting = this.update(&mut cx, |this, cx| {
10313 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10314 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10315 let position = envelope
10316 .payload
10317 .position
10318 .and_then(deserialize_anchor)
10319 .context("invalid position")?;
10320 anyhow::Ok(this.apply_on_type_formatting(
10321 buffer,
10322 position,
10323 envelope.payload.trigger.clone(),
10324 cx,
10325 ))
10326 })?;
10327
10328 let transaction = on_type_formatting
10329 .await?
10330 .as_ref()
10331 .map(language::proto::serialize_transaction);
10332 Ok(proto::OnTypeFormattingResponse { transaction })
10333 }
10334
10335 async fn handle_pull_workspace_diagnostics(
10336 lsp_store: Entity<Self>,
10337 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10338 mut cx: AsyncApp,
10339 ) -> Result<proto::Ack> {
10340 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10341 lsp_store.update(&mut cx, |lsp_store, _| {
10342 lsp_store.pull_workspace_diagnostics(server_id);
10343 });
10344 Ok(proto::Ack {})
10345 }
10346
10347 async fn handle_open_buffer_for_symbol(
10348 this: Entity<Self>,
10349 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10350 mut cx: AsyncApp,
10351 ) -> Result<proto::OpenBufferForSymbolResponse> {
10352 let peer_id = envelope.original_sender_id().unwrap_or_default();
10353 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10354 let symbol = Self::deserialize_symbol(symbol)?;
10355 this.read_with(&cx, |this, _| {
10356 if let SymbolLocation::OutsideProject {
10357 abs_path,
10358 signature,
10359 } = &symbol.path
10360 {
10361 let new_signature = this.symbol_signature(&abs_path);
10362 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10363 }
10364 Ok(())
10365 })?;
10366 let buffer = this
10367 .update(&mut cx, |this, cx| {
10368 this.open_buffer_for_symbol(
10369 &Symbol {
10370 language_server_name: symbol.language_server_name,
10371 source_worktree_id: symbol.source_worktree_id,
10372 source_language_server_id: symbol.source_language_server_id,
10373 path: symbol.path,
10374 name: symbol.name,
10375 kind: symbol.kind,
10376 range: symbol.range,
10377 label: CodeLabel::default(),
10378 container_name: symbol.container_name,
10379 },
10380 cx,
10381 )
10382 })
10383 .await?;
10384
10385 this.update(&mut cx, |this, cx| {
10386 let is_private = buffer
10387 .read(cx)
10388 .file()
10389 .map(|f| f.is_private())
10390 .unwrap_or_default();
10391 if is_private {
10392 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10393 } else {
10394 this.buffer_store
10395 .update(cx, |buffer_store, cx| {
10396 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10397 })
10398 .detach_and_log_err(cx);
10399 let buffer_id = buffer.read(cx).remote_id().to_proto();
10400 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10401 }
10402 })
10403 }
10404
10405 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10406 let mut hasher = Sha256::new();
10407 hasher.update(abs_path.to_string_lossy().as_bytes());
10408 hasher.update(self.nonce.to_be_bytes());
10409 hasher.finalize().as_slice().try_into().unwrap()
10410 }
10411
10412 pub async fn handle_get_project_symbols(
10413 this: Entity<Self>,
10414 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10415 mut cx: AsyncApp,
10416 ) -> Result<proto::GetProjectSymbolsResponse> {
10417 let symbols = this
10418 .update(&mut cx, |this, cx| {
10419 this.symbols(&envelope.payload.query, cx)
10420 })
10421 .await?;
10422
10423 Ok(proto::GetProjectSymbolsResponse {
10424 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10425 })
10426 }
10427
10428 pub async fn handle_restart_language_servers(
10429 this: Entity<Self>,
10430 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10431 mut cx: AsyncApp,
10432 ) -> Result<proto::Ack> {
10433 this.update(&mut cx, |lsp_store, cx| {
10434 let buffers =
10435 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10436 lsp_store.restart_language_servers_for_buffers(
10437 buffers,
10438 envelope
10439 .payload
10440 .only_servers
10441 .into_iter()
10442 .filter_map(|selector| {
10443 Some(match selector.selector? {
10444 proto::language_server_selector::Selector::ServerId(server_id) => {
10445 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10446 }
10447 proto::language_server_selector::Selector::Name(name) => {
10448 LanguageServerSelector::Name(LanguageServerName(
10449 SharedString::from(name),
10450 ))
10451 }
10452 })
10453 })
10454 .collect(),
10455 cx,
10456 );
10457 });
10458
10459 Ok(proto::Ack {})
10460 }
10461
10462 pub async fn handle_stop_language_servers(
10463 lsp_store: Entity<Self>,
10464 envelope: TypedEnvelope<proto::StopLanguageServers>,
10465 mut cx: AsyncApp,
10466 ) -> Result<proto::Ack> {
10467 lsp_store.update(&mut cx, |lsp_store, cx| {
10468 if envelope.payload.all
10469 && envelope.payload.also_servers.is_empty()
10470 && envelope.payload.buffer_ids.is_empty()
10471 {
10472 lsp_store.stop_all_language_servers(cx);
10473 } else {
10474 let buffers =
10475 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10476 lsp_store
10477 .stop_language_servers_for_buffers(
10478 buffers,
10479 envelope
10480 .payload
10481 .also_servers
10482 .into_iter()
10483 .filter_map(|selector| {
10484 Some(match selector.selector? {
10485 proto::language_server_selector::Selector::ServerId(
10486 server_id,
10487 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10488 server_id,
10489 )),
10490 proto::language_server_selector::Selector::Name(name) => {
10491 LanguageServerSelector::Name(LanguageServerName(
10492 SharedString::from(name),
10493 ))
10494 }
10495 })
10496 })
10497 .collect(),
10498 cx,
10499 )
10500 .detach_and_log_err(cx);
10501 }
10502 });
10503
10504 Ok(proto::Ack {})
10505 }
10506
10507 pub async fn handle_cancel_language_server_work(
10508 lsp_store: Entity<Self>,
10509 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10510 mut cx: AsyncApp,
10511 ) -> Result<proto::Ack> {
10512 lsp_store.update(&mut cx, |lsp_store, cx| {
10513 if let Some(work) = envelope.payload.work {
10514 match work {
10515 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10516 let buffers =
10517 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10518 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10519 }
10520 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10521 let server_id = LanguageServerId::from_proto(work.language_server_id);
10522 let token = work
10523 .token
10524 .map(|token| {
10525 ProgressToken::from_proto(token)
10526 .context("invalid work progress token")
10527 })
10528 .transpose()?;
10529 lsp_store.cancel_language_server_work(server_id, token, cx);
10530 }
10531 }
10532 }
10533 anyhow::Ok(())
10534 })?;
10535
10536 Ok(proto::Ack {})
10537 }
10538
10539 fn buffer_ids_to_buffers(
10540 &mut self,
10541 buffer_ids: impl Iterator<Item = u64>,
10542 cx: &mut Context<Self>,
10543 ) -> Vec<Entity<Buffer>> {
10544 buffer_ids
10545 .into_iter()
10546 .flat_map(|buffer_id| {
10547 self.buffer_store
10548 .read(cx)
10549 .get(BufferId::new(buffer_id).log_err()?)
10550 })
10551 .collect::<Vec<_>>()
10552 }
10553
10554 async fn handle_apply_additional_edits_for_completion(
10555 this: Entity<Self>,
10556 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10557 mut cx: AsyncApp,
10558 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10559 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10560 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10561 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10562 let completion = Self::deserialize_completion(
10563 envelope.payload.completion.context("invalid completion")?,
10564 )?;
10565 let all_commit_ranges = envelope
10566 .payload
10567 .all_commit_ranges
10568 .into_iter()
10569 .map(language::proto::deserialize_anchor_range)
10570 .collect::<Result<Vec<_>, _>>()?;
10571 anyhow::Ok((buffer, completion, all_commit_ranges))
10572 })?;
10573
10574 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10575 this.apply_additional_edits_for_completion(
10576 buffer,
10577 Rc::new(RefCell::new(Box::new([Completion {
10578 replace_range: completion.replace_range,
10579 new_text: completion.new_text,
10580 source: completion.source,
10581 documentation: None,
10582 label: CodeLabel::default(),
10583 match_start: None,
10584 snippet_deduplication_key: None,
10585 insert_text_mode: None,
10586 icon_path: None,
10587 confirm: None,
10588 }]))),
10589 0,
10590 false,
10591 all_commit_ranges,
10592 cx,
10593 )
10594 });
10595
10596 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10597 transaction: apply_additional_edits
10598 .await?
10599 .as_ref()
10600 .map(language::proto::serialize_transaction),
10601 })
10602 }
10603
10604 pub fn last_formatting_failure(&self) -> Option<&str> {
10605 self.last_formatting_failure.as_deref()
10606 }
10607
10608 pub fn reset_last_formatting_failure(&mut self) {
10609 self.last_formatting_failure = None;
10610 }
10611
10612 pub fn environment_for_buffer(
10613 &self,
10614 buffer: &Entity<Buffer>,
10615 cx: &mut Context<Self>,
10616 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10617 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10618 environment.update(cx, |env, cx| {
10619 env.buffer_environment(buffer, &self.worktree_store, cx)
10620 })
10621 } else {
10622 Task::ready(None).shared()
10623 }
10624 }
10625
10626 pub fn format(
10627 &mut self,
10628 buffers: HashSet<Entity<Buffer>>,
10629 target: LspFormatTarget,
10630 push_to_history: bool,
10631 trigger: FormatTrigger,
10632 cx: &mut Context<Self>,
10633 ) -> Task<anyhow::Result<ProjectTransaction>> {
10634 let logger = zlog::scoped!("format");
10635 if self.as_local().is_some() {
10636 zlog::trace!(logger => "Formatting locally");
10637 let logger = zlog::scoped!(logger => "local");
10638 let buffers = buffers
10639 .into_iter()
10640 .map(|buffer_handle| {
10641 let buffer = buffer_handle.read(cx);
10642 let buffer_abs_path = File::from_dyn(buffer.file())
10643 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10644
10645 (buffer_handle, buffer_abs_path, buffer.remote_id())
10646 })
10647 .collect::<Vec<_>>();
10648
10649 cx.spawn(async move |lsp_store, cx| {
10650 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10651
10652 for (handle, abs_path, id) in buffers {
10653 let env = lsp_store
10654 .update(cx, |lsp_store, cx| {
10655 lsp_store.environment_for_buffer(&handle, cx)
10656 })?
10657 .await;
10658
10659 let ranges = match &target {
10660 LspFormatTarget::Buffers => None,
10661 LspFormatTarget::Ranges(ranges) => {
10662 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10663 }
10664 };
10665
10666 formattable_buffers.push(FormattableBuffer {
10667 handle,
10668 abs_path,
10669 env,
10670 ranges,
10671 });
10672 }
10673 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10674
10675 let format_timer = zlog::time!(logger => "Formatting buffers");
10676 let result = LocalLspStore::format_locally(
10677 lsp_store.clone(),
10678 formattable_buffers,
10679 push_to_history,
10680 trigger,
10681 logger,
10682 cx,
10683 )
10684 .await;
10685 format_timer.end();
10686
10687 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10688
10689 lsp_store.update(cx, |lsp_store, _| {
10690 lsp_store.update_last_formatting_failure(&result);
10691 })?;
10692
10693 result
10694 })
10695 } else if let Some((client, project_id)) = self.upstream_client() {
10696 zlog::trace!(logger => "Formatting remotely");
10697 let logger = zlog::scoped!(logger => "remote");
10698
10699 let buffer_ranges = match &target {
10700 LspFormatTarget::Buffers => Vec::new(),
10701 LspFormatTarget::Ranges(ranges) => ranges
10702 .iter()
10703 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10704 buffer_id: buffer_id.to_proto(),
10705 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10706 })
10707 .collect(),
10708 };
10709
10710 let buffer_store = self.buffer_store();
10711 cx.spawn(async move |lsp_store, cx| {
10712 zlog::trace!(logger => "Sending remote format request");
10713 let request_timer = zlog::time!(logger => "remote format request");
10714 let result = client
10715 .request(proto::FormatBuffers {
10716 project_id,
10717 trigger: trigger as i32,
10718 buffer_ids: buffers
10719 .iter()
10720 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10721 .collect(),
10722 buffer_ranges,
10723 })
10724 .await
10725 .and_then(|result| result.transaction.context("missing transaction"));
10726 request_timer.end();
10727
10728 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10729
10730 lsp_store.update(cx, |lsp_store, _| {
10731 lsp_store.update_last_formatting_failure(&result);
10732 })?;
10733
10734 let transaction_response = result?;
10735 let _timer = zlog::time!(logger => "deserializing project transaction");
10736 buffer_store
10737 .update(cx, |buffer_store, cx| {
10738 buffer_store.deserialize_project_transaction(
10739 transaction_response,
10740 push_to_history,
10741 cx,
10742 )
10743 })
10744 .await
10745 })
10746 } else {
10747 zlog::trace!(logger => "Not formatting");
10748 Task::ready(Ok(ProjectTransaction::default()))
10749 }
10750 }
10751
10752 async fn handle_format_buffers(
10753 this: Entity<Self>,
10754 envelope: TypedEnvelope<proto::FormatBuffers>,
10755 mut cx: AsyncApp,
10756 ) -> Result<proto::FormatBuffersResponse> {
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
10765 let target = if envelope.payload.buffer_ranges.is_empty() {
10766 LspFormatTarget::Buffers
10767 } else {
10768 let mut ranges_map = BTreeMap::new();
10769 for buffer_range in &envelope.payload.buffer_ranges {
10770 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10771 let ranges: Result<Vec<_>> = buffer_range
10772 .ranges
10773 .iter()
10774 .map(|range| {
10775 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10776 })
10777 .collect();
10778 ranges_map.insert(buffer_id, ranges?);
10779 }
10780 LspFormatTarget::Ranges(ranges_map)
10781 };
10782
10783 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10784 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10785 })?;
10786
10787 let project_transaction = format.await?;
10788 let project_transaction = this.update(&mut cx, |this, cx| {
10789 this.buffer_store.update(cx, |buffer_store, cx| {
10790 buffer_store.serialize_project_transaction_for_peer(
10791 project_transaction,
10792 sender_id,
10793 cx,
10794 )
10795 })
10796 });
10797 Ok(proto::FormatBuffersResponse {
10798 transaction: Some(project_transaction),
10799 })
10800 }
10801
10802 async fn handle_apply_code_action_kind(
10803 this: Entity<Self>,
10804 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10805 mut cx: AsyncApp,
10806 ) -> Result<proto::ApplyCodeActionKindResponse> {
10807 let sender_id = envelope.original_sender_id().unwrap_or_default();
10808 let format = this.update(&mut cx, |this, cx| {
10809 let mut buffers = HashSet::default();
10810 for buffer_id in &envelope.payload.buffer_ids {
10811 let buffer_id = BufferId::new(*buffer_id)?;
10812 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10813 }
10814 let kind = match envelope.payload.kind.as_str() {
10815 "" => CodeActionKind::EMPTY,
10816 "quickfix" => CodeActionKind::QUICKFIX,
10817 "refactor" => CodeActionKind::REFACTOR,
10818 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10819 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10820 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10821 "source" => CodeActionKind::SOURCE,
10822 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10823 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10824 _ => anyhow::bail!(
10825 "Invalid code action kind {}",
10826 envelope.payload.kind.as_str()
10827 ),
10828 };
10829 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10830 })?;
10831
10832 let project_transaction = format.await?;
10833 let project_transaction = this.update(&mut cx, |this, cx| {
10834 this.buffer_store.update(cx, |buffer_store, cx| {
10835 buffer_store.serialize_project_transaction_for_peer(
10836 project_transaction,
10837 sender_id,
10838 cx,
10839 )
10840 })
10841 });
10842 Ok(proto::ApplyCodeActionKindResponse {
10843 transaction: Some(project_transaction),
10844 })
10845 }
10846
10847 async fn shutdown_language_server(
10848 server_state: Option<LanguageServerState>,
10849 name: LanguageServerName,
10850 cx: &mut AsyncApp,
10851 ) {
10852 let server = match server_state {
10853 Some(LanguageServerState::Starting { startup, .. }) => {
10854 let mut timer = cx
10855 .background_executor()
10856 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10857 .fuse();
10858
10859 select! {
10860 server = startup.fuse() => server,
10861 () = timer => {
10862 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10863 None
10864 },
10865 }
10866 }
10867
10868 Some(LanguageServerState::Running { server, .. }) => Some(server),
10869
10870 None => None,
10871 };
10872
10873 let Some(server) = server else { return };
10874 if let Some(shutdown) = server.shutdown() {
10875 shutdown.await;
10876 }
10877 }
10878
10879 // Returns a list of all of the worktrees which no longer have a language server and the root path
10880 // for the stopped server
10881 fn stop_local_language_server(
10882 &mut self,
10883 server_id: LanguageServerId,
10884 cx: &mut Context<Self>,
10885 ) -> Task<()> {
10886 let local = match &mut self.mode {
10887 LspStoreMode::Local(local) => local,
10888 _ => {
10889 return Task::ready(());
10890 }
10891 };
10892
10893 // Remove this server ID from all entries in the given worktree.
10894 local
10895 .language_server_ids
10896 .retain(|_, state| state.id != server_id);
10897 self.buffer_store.update(cx, |buffer_store, cx| {
10898 for buffer in buffer_store.buffers() {
10899 buffer.update(cx, |buffer, cx| {
10900 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10901 buffer.set_completion_triggers(server_id, Default::default(), cx);
10902 });
10903 }
10904 });
10905
10906 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10907 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10908 summaries.retain(|path, summaries_by_server_id| {
10909 if summaries_by_server_id.remove(&server_id).is_some() {
10910 if let Some((client, project_id)) = self.downstream_client.clone() {
10911 client
10912 .send(proto::UpdateDiagnosticSummary {
10913 project_id,
10914 worktree_id: worktree_id.to_proto(),
10915 summary: Some(proto::DiagnosticSummary {
10916 path: path.as_ref().to_proto(),
10917 language_server_id: server_id.0 as u64,
10918 error_count: 0,
10919 warning_count: 0,
10920 }),
10921 more_summaries: Vec::new(),
10922 })
10923 .log_err();
10924 }
10925 cleared_paths.push(ProjectPath {
10926 worktree_id: *worktree_id,
10927 path: path.clone(),
10928 });
10929 !summaries_by_server_id.is_empty()
10930 } else {
10931 true
10932 }
10933 });
10934 }
10935 if !cleared_paths.is_empty() {
10936 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10937 server_id,
10938 paths: cleared_paths,
10939 });
10940 }
10941
10942 let local = self.as_local_mut().unwrap();
10943 for diagnostics in local.diagnostics.values_mut() {
10944 diagnostics.retain(|_, diagnostics_by_server_id| {
10945 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10946 diagnostics_by_server_id.remove(ix);
10947 !diagnostics_by_server_id.is_empty()
10948 } else {
10949 true
10950 }
10951 });
10952 }
10953 local.language_server_watched_paths.remove(&server_id);
10954
10955 let server_state = local.language_servers.remove(&server_id);
10956 self.cleanup_lsp_data(server_id);
10957 let name = self
10958 .language_server_statuses
10959 .remove(&server_id)
10960 .map(|status| status.name)
10961 .or_else(|| {
10962 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10963 Some(adapter.name())
10964 } else {
10965 None
10966 }
10967 });
10968
10969 if let Some(name) = name {
10970 log::info!("stopping language server {name}");
10971 self.languages
10972 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10973 cx.notify();
10974
10975 return cx.spawn(async move |lsp_store, cx| {
10976 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10977 lsp_store
10978 .update(cx, |lsp_store, cx| {
10979 lsp_store
10980 .languages
10981 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10982 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10983 cx.notify();
10984 })
10985 .ok();
10986 });
10987 }
10988
10989 if server_state.is_some() {
10990 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10991 }
10992 Task::ready(())
10993 }
10994
10995 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10996 self.shutdown_all_language_servers(cx).detach();
10997 }
10998
10999 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11000 if let Some((client, project_id)) = self.upstream_client() {
11001 let request = client.request(proto::StopLanguageServers {
11002 project_id,
11003 buffer_ids: Vec::new(),
11004 also_servers: Vec::new(),
11005 all: true,
11006 });
11007 cx.background_spawn(async move {
11008 request.await.ok();
11009 })
11010 } else {
11011 let Some(local) = self.as_local_mut() else {
11012 return Task::ready(());
11013 };
11014 let language_servers_to_stop = local
11015 .language_server_ids
11016 .values()
11017 .map(|state| state.id)
11018 .collect();
11019 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11020 let tasks = language_servers_to_stop
11021 .into_iter()
11022 .map(|server| self.stop_local_language_server(server, cx))
11023 .collect::<Vec<_>>();
11024 cx.background_spawn(async move {
11025 futures::future::join_all(tasks).await;
11026 })
11027 }
11028 }
11029
11030 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11031 let buffers = self.buffer_store.read(cx).buffers().collect();
11032 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11033 }
11034
11035 pub fn restart_language_servers_for_buffers(
11036 &mut self,
11037 buffers: Vec<Entity<Buffer>>,
11038 only_restart_servers: HashSet<LanguageServerSelector>,
11039 cx: &mut Context<Self>,
11040 ) {
11041 if let Some((client, project_id)) = self.upstream_client() {
11042 let request = client.request(proto::RestartLanguageServers {
11043 project_id,
11044 buffer_ids: buffers
11045 .into_iter()
11046 .map(|b| b.read(cx).remote_id().to_proto())
11047 .collect(),
11048 only_servers: only_restart_servers
11049 .into_iter()
11050 .map(|selector| {
11051 let selector = match selector {
11052 LanguageServerSelector::Id(language_server_id) => {
11053 proto::language_server_selector::Selector::ServerId(
11054 language_server_id.to_proto(),
11055 )
11056 }
11057 LanguageServerSelector::Name(language_server_name) => {
11058 proto::language_server_selector::Selector::Name(
11059 language_server_name.to_string(),
11060 )
11061 }
11062 };
11063 proto::LanguageServerSelector {
11064 selector: Some(selector),
11065 }
11066 })
11067 .collect(),
11068 all: false,
11069 });
11070 cx.background_spawn(request).detach_and_log_err(cx);
11071 } else {
11072 let stop_task = if only_restart_servers.is_empty() {
11073 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11074 } else {
11075 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11076 };
11077 cx.spawn(async move |lsp_store, cx| {
11078 stop_task.await;
11079 lsp_store.update(cx, |lsp_store, cx| {
11080 for buffer in buffers {
11081 lsp_store.register_buffer_with_language_servers(
11082 &buffer,
11083 only_restart_servers.clone(),
11084 true,
11085 cx,
11086 );
11087 }
11088 })
11089 })
11090 .detach();
11091 }
11092 }
11093
11094 pub fn stop_language_servers_for_buffers(
11095 &mut self,
11096 buffers: Vec<Entity<Buffer>>,
11097 also_stop_servers: HashSet<LanguageServerSelector>,
11098 cx: &mut Context<Self>,
11099 ) -> Task<Result<()>> {
11100 if let Some((client, project_id)) = self.upstream_client() {
11101 let request = client.request(proto::StopLanguageServers {
11102 project_id,
11103 buffer_ids: buffers
11104 .into_iter()
11105 .map(|b| b.read(cx).remote_id().to_proto())
11106 .collect(),
11107 also_servers: also_stop_servers
11108 .into_iter()
11109 .map(|selector| {
11110 let selector = match selector {
11111 LanguageServerSelector::Id(language_server_id) => {
11112 proto::language_server_selector::Selector::ServerId(
11113 language_server_id.to_proto(),
11114 )
11115 }
11116 LanguageServerSelector::Name(language_server_name) => {
11117 proto::language_server_selector::Selector::Name(
11118 language_server_name.to_string(),
11119 )
11120 }
11121 };
11122 proto::LanguageServerSelector {
11123 selector: Some(selector),
11124 }
11125 })
11126 .collect(),
11127 all: false,
11128 });
11129 cx.background_spawn(async move {
11130 let _ = request.await?;
11131 Ok(())
11132 })
11133 } else {
11134 let task =
11135 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11136 cx.background_spawn(async move {
11137 task.await;
11138 Ok(())
11139 })
11140 }
11141 }
11142
11143 fn stop_local_language_servers_for_buffers(
11144 &mut self,
11145 buffers: &[Entity<Buffer>],
11146 also_stop_servers: HashSet<LanguageServerSelector>,
11147 cx: &mut Context<Self>,
11148 ) -> Task<()> {
11149 let Some(local) = self.as_local_mut() else {
11150 return Task::ready(());
11151 };
11152 let mut language_server_names_to_stop = BTreeSet::default();
11153 let mut language_servers_to_stop = also_stop_servers
11154 .into_iter()
11155 .flat_map(|selector| match selector {
11156 LanguageServerSelector::Id(id) => Some(id),
11157 LanguageServerSelector::Name(name) => {
11158 language_server_names_to_stop.insert(name);
11159 None
11160 }
11161 })
11162 .collect::<BTreeSet<_>>();
11163
11164 let mut covered_worktrees = HashSet::default();
11165 for buffer in buffers {
11166 buffer.update(cx, |buffer, cx| {
11167 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11168 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11169 && covered_worktrees.insert(worktree_id)
11170 {
11171 language_server_names_to_stop.retain(|name| {
11172 let old_ids_count = language_servers_to_stop.len();
11173 let all_language_servers_with_this_name = local
11174 .language_server_ids
11175 .iter()
11176 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11177 language_servers_to_stop.extend(all_language_servers_with_this_name);
11178 old_ids_count == language_servers_to_stop.len()
11179 });
11180 }
11181 });
11182 }
11183 for name in language_server_names_to_stop {
11184 language_servers_to_stop.extend(
11185 local
11186 .language_server_ids
11187 .iter()
11188 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11189 );
11190 }
11191
11192 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11193 let tasks = language_servers_to_stop
11194 .into_iter()
11195 .map(|server| self.stop_local_language_server(server, cx))
11196 .collect::<Vec<_>>();
11197
11198 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11199 }
11200
11201 #[cfg(any(test, feature = "test-support"))]
11202 pub fn update_diagnostics(
11203 &mut self,
11204 server_id: LanguageServerId,
11205 diagnostics: lsp::PublishDiagnosticsParams,
11206 result_id: Option<SharedString>,
11207 source_kind: DiagnosticSourceKind,
11208 disk_based_sources: &[String],
11209 cx: &mut Context<Self>,
11210 ) -> Result<()> {
11211 self.merge_lsp_diagnostics(
11212 source_kind,
11213 vec![DocumentDiagnosticsUpdate {
11214 diagnostics,
11215 result_id,
11216 server_id,
11217 disk_based_sources: Cow::Borrowed(disk_based_sources),
11218 registration_id: None,
11219 }],
11220 |_, _, _| false,
11221 cx,
11222 )
11223 }
11224
11225 pub fn merge_lsp_diagnostics(
11226 &mut self,
11227 source_kind: DiagnosticSourceKind,
11228 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11229 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11230 cx: &mut Context<Self>,
11231 ) -> Result<()> {
11232 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11233 let updates = lsp_diagnostics
11234 .into_iter()
11235 .filter_map(|update| {
11236 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11237 Some(DocumentDiagnosticsUpdate {
11238 diagnostics: self.lsp_to_document_diagnostics(
11239 abs_path,
11240 source_kind,
11241 update.server_id,
11242 update.diagnostics,
11243 &update.disk_based_sources,
11244 update.registration_id.clone(),
11245 ),
11246 result_id: update.result_id,
11247 server_id: update.server_id,
11248 disk_based_sources: update.disk_based_sources,
11249 registration_id: update.registration_id,
11250 })
11251 })
11252 .collect();
11253 self.merge_diagnostic_entries(updates, merge, cx)?;
11254 Ok(())
11255 }
11256
11257 fn lsp_to_document_diagnostics(
11258 &mut self,
11259 document_abs_path: PathBuf,
11260 source_kind: DiagnosticSourceKind,
11261 server_id: LanguageServerId,
11262 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11263 disk_based_sources: &[String],
11264 registration_id: Option<SharedString>,
11265 ) -> DocumentDiagnostics {
11266 let mut diagnostics = Vec::default();
11267 let mut primary_diagnostic_group_ids = HashMap::default();
11268 let mut sources_by_group_id = HashMap::default();
11269 let mut supporting_diagnostics = HashMap::default();
11270
11271 let adapter = self.language_server_adapter_for_id(server_id);
11272
11273 // Ensure that primary diagnostics are always the most severe
11274 lsp_diagnostics
11275 .diagnostics
11276 .sort_by_key(|item| item.severity);
11277
11278 for diagnostic in &lsp_diagnostics.diagnostics {
11279 let source = diagnostic.source.as_ref();
11280 let range = range_from_lsp(diagnostic.range);
11281 let is_supporting = diagnostic
11282 .related_information
11283 .as_ref()
11284 .is_some_and(|infos| {
11285 infos.iter().any(|info| {
11286 primary_diagnostic_group_ids.contains_key(&(
11287 source,
11288 diagnostic.code.clone(),
11289 range_from_lsp(info.location.range),
11290 ))
11291 })
11292 });
11293
11294 let is_unnecessary = diagnostic
11295 .tags
11296 .as_ref()
11297 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11298
11299 let underline = self
11300 .language_server_adapter_for_id(server_id)
11301 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11302
11303 if is_supporting {
11304 supporting_diagnostics.insert(
11305 (source, diagnostic.code.clone(), range),
11306 (diagnostic.severity, is_unnecessary),
11307 );
11308 } else {
11309 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11310 let is_disk_based =
11311 source.is_some_and(|source| disk_based_sources.contains(source));
11312
11313 sources_by_group_id.insert(group_id, source);
11314 primary_diagnostic_group_ids
11315 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11316
11317 diagnostics.push(DiagnosticEntry {
11318 range,
11319 diagnostic: Diagnostic {
11320 source: diagnostic.source.clone(),
11321 source_kind,
11322 code: diagnostic.code.clone(),
11323 code_description: diagnostic
11324 .code_description
11325 .as_ref()
11326 .and_then(|d| d.href.clone()),
11327 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11328 markdown: adapter.as_ref().and_then(|adapter| {
11329 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11330 }),
11331 message: diagnostic.message.trim().to_string(),
11332 group_id,
11333 is_primary: true,
11334 is_disk_based,
11335 is_unnecessary,
11336 underline,
11337 data: diagnostic.data.clone(),
11338 registration_id: registration_id.clone(),
11339 },
11340 });
11341 if let Some(infos) = &diagnostic.related_information {
11342 for info in infos {
11343 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11344 let range = range_from_lsp(info.location.range);
11345 diagnostics.push(DiagnosticEntry {
11346 range,
11347 diagnostic: Diagnostic {
11348 source: diagnostic.source.clone(),
11349 source_kind,
11350 code: diagnostic.code.clone(),
11351 code_description: diagnostic
11352 .code_description
11353 .as_ref()
11354 .and_then(|d| d.href.clone()),
11355 severity: DiagnosticSeverity::INFORMATION,
11356 markdown: adapter.as_ref().and_then(|adapter| {
11357 adapter.diagnostic_message_to_markdown(&info.message)
11358 }),
11359 message: info.message.trim().to_string(),
11360 group_id,
11361 is_primary: false,
11362 is_disk_based,
11363 is_unnecessary: false,
11364 underline,
11365 data: diagnostic.data.clone(),
11366 registration_id: registration_id.clone(),
11367 },
11368 });
11369 }
11370 }
11371 }
11372 }
11373 }
11374
11375 for entry in &mut diagnostics {
11376 let diagnostic = &mut entry.diagnostic;
11377 if !diagnostic.is_primary {
11378 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11379 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11380 source,
11381 diagnostic.code.clone(),
11382 entry.range.clone(),
11383 )) {
11384 if let Some(severity) = severity {
11385 diagnostic.severity = severity;
11386 }
11387 diagnostic.is_unnecessary = is_unnecessary;
11388 }
11389 }
11390 }
11391
11392 DocumentDiagnostics {
11393 diagnostics,
11394 document_abs_path,
11395 version: lsp_diagnostics.version,
11396 }
11397 }
11398
11399 fn insert_newly_running_language_server(
11400 &mut self,
11401 adapter: Arc<CachedLspAdapter>,
11402 language_server: Arc<LanguageServer>,
11403 server_id: LanguageServerId,
11404 key: LanguageServerSeed,
11405 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11406 cx: &mut Context<Self>,
11407 ) {
11408 let Some(local) = self.as_local_mut() else {
11409 return;
11410 };
11411 // If the language server for this key doesn't match the server id, don't store the
11412 // server. Which will cause it to be dropped, killing the process
11413 if local
11414 .language_server_ids
11415 .get(&key)
11416 .map(|state| state.id != server_id)
11417 .unwrap_or(false)
11418 {
11419 return;
11420 }
11421
11422 // Update language_servers collection with Running variant of LanguageServerState
11423 // indicating that the server is up and running and ready
11424 let workspace_folders = workspace_folders.lock().clone();
11425 language_server.set_workspace_folders(workspace_folders);
11426
11427 let workspace_diagnostics_refresh_tasks = language_server
11428 .capabilities()
11429 .diagnostic_provider
11430 .and_then(|provider| {
11431 local
11432 .language_server_dynamic_registrations
11433 .entry(server_id)
11434 .or_default()
11435 .diagnostics
11436 .entry(None)
11437 .or_insert(provider.clone());
11438 let workspace_refresher =
11439 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11440
11441 Some((None, workspace_refresher))
11442 })
11443 .into_iter()
11444 .collect();
11445 local.language_servers.insert(
11446 server_id,
11447 LanguageServerState::Running {
11448 workspace_diagnostics_refresh_tasks,
11449 adapter: adapter.clone(),
11450 server: language_server.clone(),
11451 simulate_disk_based_diagnostics_completion: None,
11452 },
11453 );
11454 local
11455 .languages
11456 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11457 if let Some(file_ops_caps) = language_server
11458 .capabilities()
11459 .workspace
11460 .as_ref()
11461 .and_then(|ws| ws.file_operations.as_ref())
11462 {
11463 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11464 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11465 if did_rename_caps.or(will_rename_caps).is_some() {
11466 let watcher = RenamePathsWatchedForServer::default()
11467 .with_did_rename_patterns(did_rename_caps)
11468 .with_will_rename_patterns(will_rename_caps);
11469 local
11470 .language_server_paths_watched_for_rename
11471 .insert(server_id, watcher);
11472 }
11473 }
11474
11475 self.language_server_statuses.insert(
11476 server_id,
11477 LanguageServerStatus {
11478 name: language_server.name(),
11479 server_version: language_server.version(),
11480 server_readable_version: language_server.readable_version(),
11481 pending_work: Default::default(),
11482 has_pending_diagnostic_updates: false,
11483 progress_tokens: Default::default(),
11484 worktree: Some(key.worktree_id),
11485 binary: Some(language_server.binary().clone()),
11486 configuration: Some(language_server.configuration().clone()),
11487 workspace_folders: language_server.workspace_folders(),
11488 process_id: language_server.process_id(),
11489 },
11490 );
11491
11492 cx.emit(LspStoreEvent::LanguageServerAdded(
11493 server_id,
11494 language_server.name(),
11495 Some(key.worktree_id),
11496 ));
11497
11498 let server_capabilities = language_server.capabilities();
11499 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11500 downstream_client
11501 .send(proto::StartLanguageServer {
11502 project_id: *project_id,
11503 server: Some(proto::LanguageServer {
11504 id: server_id.to_proto(),
11505 name: language_server.name().to_string(),
11506 worktree_id: Some(key.worktree_id.to_proto()),
11507 }),
11508 capabilities: serde_json::to_string(&server_capabilities)
11509 .expect("serializing server LSP capabilities"),
11510 })
11511 .log_err();
11512 }
11513 self.lsp_server_capabilities
11514 .insert(server_id, server_capabilities);
11515
11516 // Tell the language server about every open buffer in the worktree that matches the language.
11517 // Also check for buffers in worktrees that reused this server
11518 let mut worktrees_using_server = vec![key.worktree_id];
11519 if let Some(local) = self.as_local() {
11520 // Find all worktrees that have this server in their language server tree
11521 for (worktree_id, servers) in &local.lsp_tree.instances {
11522 if *worktree_id != key.worktree_id {
11523 for server_map in servers.roots.values() {
11524 if server_map
11525 .values()
11526 .any(|(node, _)| node.id() == Some(server_id))
11527 {
11528 worktrees_using_server.push(*worktree_id);
11529 }
11530 }
11531 }
11532 }
11533 }
11534
11535 let mut buffer_paths_registered = Vec::new();
11536 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11537 let mut lsp_adapters = HashMap::default();
11538 for buffer_handle in buffer_store.buffers() {
11539 let buffer = buffer_handle.read(cx);
11540 let file = match File::from_dyn(buffer.file()) {
11541 Some(file) => file,
11542 None => continue,
11543 };
11544 let language = match buffer.language() {
11545 Some(language) => language,
11546 None => continue,
11547 };
11548
11549 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11550 || !lsp_adapters
11551 .entry(language.name())
11552 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11553 .iter()
11554 .any(|a| a.name == key.name)
11555 {
11556 continue;
11557 }
11558 // didOpen
11559 let file = match file.as_local() {
11560 Some(file) => file,
11561 None => continue,
11562 };
11563
11564 let local = self.as_local_mut().unwrap();
11565
11566 let buffer_id = buffer.remote_id();
11567 if local.registered_buffers.contains_key(&buffer_id) {
11568 let abs_path = file.abs_path(cx);
11569 let uri = match lsp::Uri::from_file_path(&abs_path) {
11570 Ok(uri) => uri,
11571 Err(()) => {
11572 log::error!("failed to convert path to URI: {:?}", abs_path);
11573 continue;
11574 }
11575 };
11576
11577 let versions = local
11578 .buffer_snapshots
11579 .entry(buffer_id)
11580 .or_default()
11581 .entry(server_id)
11582 .and_modify(|_| {
11583 assert!(
11584 false,
11585 "There should not be an existing snapshot for a newly inserted buffer"
11586 )
11587 })
11588 .or_insert_with(|| {
11589 vec![LspBufferSnapshot {
11590 version: 0,
11591 snapshot: buffer.text_snapshot(),
11592 }]
11593 });
11594
11595 let snapshot = versions.last().unwrap();
11596 let version = snapshot.version;
11597 let initial_snapshot = &snapshot.snapshot;
11598 language_server.register_buffer(
11599 uri,
11600 adapter.language_id(&language.name()),
11601 version,
11602 initial_snapshot.text(),
11603 );
11604 buffer_paths_registered.push((buffer_id, abs_path));
11605 local
11606 .buffers_opened_in_servers
11607 .entry(buffer_id)
11608 .or_default()
11609 .insert(server_id);
11610 }
11611 buffer_handle.update(cx, |buffer, cx| {
11612 buffer.set_completion_triggers(
11613 server_id,
11614 language_server
11615 .capabilities()
11616 .completion_provider
11617 .as_ref()
11618 .and_then(|provider| {
11619 provider
11620 .trigger_characters
11621 .as_ref()
11622 .map(|characters| characters.iter().cloned().collect())
11623 })
11624 .unwrap_or_default(),
11625 cx,
11626 )
11627 });
11628 }
11629 });
11630
11631 for (buffer_id, abs_path) in buffer_paths_registered {
11632 cx.emit(LspStoreEvent::LanguageServerUpdate {
11633 language_server_id: server_id,
11634 name: Some(adapter.name()),
11635 message: proto::update_language_server::Variant::RegisteredForBuffer(
11636 proto::RegisteredForBuffer {
11637 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11638 buffer_id: buffer_id.to_proto(),
11639 },
11640 ),
11641 });
11642 }
11643
11644 cx.notify();
11645 }
11646
11647 pub fn language_servers_running_disk_based_diagnostics(
11648 &self,
11649 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11650 self.language_server_statuses
11651 .iter()
11652 .filter_map(|(id, status)| {
11653 if status.has_pending_diagnostic_updates {
11654 Some(*id)
11655 } else {
11656 None
11657 }
11658 })
11659 }
11660
11661 pub(crate) fn cancel_language_server_work_for_buffers(
11662 &mut self,
11663 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11664 cx: &mut Context<Self>,
11665 ) {
11666 if let Some((client, project_id)) = self.upstream_client() {
11667 let request = client.request(proto::CancelLanguageServerWork {
11668 project_id,
11669 work: Some(proto::cancel_language_server_work::Work::Buffers(
11670 proto::cancel_language_server_work::Buffers {
11671 buffer_ids: buffers
11672 .into_iter()
11673 .map(|b| b.read(cx).remote_id().to_proto())
11674 .collect(),
11675 },
11676 )),
11677 });
11678 cx.background_spawn(request).detach_and_log_err(cx);
11679 } else if let Some(local) = self.as_local() {
11680 let servers = buffers
11681 .into_iter()
11682 .flat_map(|buffer| {
11683 buffer.update(cx, |buffer, cx| {
11684 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11685 })
11686 })
11687 .collect::<HashSet<_>>();
11688 for server_id in servers {
11689 self.cancel_language_server_work(server_id, None, cx);
11690 }
11691 }
11692 }
11693
11694 pub(crate) fn cancel_language_server_work(
11695 &mut self,
11696 server_id: LanguageServerId,
11697 token_to_cancel: Option<ProgressToken>,
11698 cx: &mut Context<Self>,
11699 ) {
11700 if let Some(local) = self.as_local() {
11701 let status = self.language_server_statuses.get(&server_id);
11702 let server = local.language_servers.get(&server_id);
11703 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11704 {
11705 for (token, progress) in &status.pending_work {
11706 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11707 && token != token_to_cancel
11708 {
11709 continue;
11710 }
11711 if progress.is_cancellable {
11712 server
11713 .notify::<lsp::notification::WorkDoneProgressCancel>(
11714 WorkDoneProgressCancelParams {
11715 token: token.to_lsp(),
11716 },
11717 )
11718 .ok();
11719 }
11720 }
11721 }
11722 } else if let Some((client, project_id)) = self.upstream_client() {
11723 let request = client.request(proto::CancelLanguageServerWork {
11724 project_id,
11725 work: Some(
11726 proto::cancel_language_server_work::Work::LanguageServerWork(
11727 proto::cancel_language_server_work::LanguageServerWork {
11728 language_server_id: server_id.to_proto(),
11729 token: token_to_cancel.map(|token| token.to_proto()),
11730 },
11731 ),
11732 ),
11733 });
11734 cx.background_spawn(request).detach_and_log_err(cx);
11735 }
11736 }
11737
11738 fn register_supplementary_language_server(
11739 &mut self,
11740 id: LanguageServerId,
11741 name: LanguageServerName,
11742 server: Arc<LanguageServer>,
11743 cx: &mut Context<Self>,
11744 ) {
11745 if let Some(local) = self.as_local_mut() {
11746 local
11747 .supplementary_language_servers
11748 .insert(id, (name.clone(), server));
11749 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11750 }
11751 }
11752
11753 fn unregister_supplementary_language_server(
11754 &mut self,
11755 id: LanguageServerId,
11756 cx: &mut Context<Self>,
11757 ) {
11758 if let Some(local) = self.as_local_mut() {
11759 local.supplementary_language_servers.remove(&id);
11760 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11761 }
11762 }
11763
11764 pub(crate) fn supplementary_language_servers(
11765 &self,
11766 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11767 self.as_local().into_iter().flat_map(|local| {
11768 local
11769 .supplementary_language_servers
11770 .iter()
11771 .map(|(id, (name, _))| (*id, name.clone()))
11772 })
11773 }
11774
11775 pub fn language_server_adapter_for_id(
11776 &self,
11777 id: LanguageServerId,
11778 ) -> Option<Arc<CachedLspAdapter>> {
11779 self.as_local()
11780 .and_then(|local| local.language_servers.get(&id))
11781 .and_then(|language_server_state| match language_server_state {
11782 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11783 _ => None,
11784 })
11785 }
11786
11787 pub(super) fn update_local_worktree_language_servers(
11788 &mut self,
11789 worktree_handle: &Entity<Worktree>,
11790 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11791 cx: &mut Context<Self>,
11792 ) {
11793 if changes.is_empty() {
11794 return;
11795 }
11796
11797 let Some(local) = self.as_local() else { return };
11798
11799 local.prettier_store.update(cx, |prettier_store, cx| {
11800 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11801 });
11802
11803 let worktree_id = worktree_handle.read(cx).id();
11804 let mut language_server_ids = local
11805 .language_server_ids
11806 .iter()
11807 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11808 .collect::<Vec<_>>();
11809 language_server_ids.sort();
11810 language_server_ids.dedup();
11811
11812 // let abs_path = worktree_handle.read(cx).abs_path();
11813 for server_id in &language_server_ids {
11814 if let Some(LanguageServerState::Running { server, .. }) =
11815 local.language_servers.get(server_id)
11816 && let Some(watched_paths) = local
11817 .language_server_watched_paths
11818 .get(server_id)
11819 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11820 {
11821 let params = lsp::DidChangeWatchedFilesParams {
11822 changes: changes
11823 .iter()
11824 .filter_map(|(path, _, change)| {
11825 if !watched_paths.is_match(path.as_std_path()) {
11826 return None;
11827 }
11828 let typ = match change {
11829 PathChange::Loaded => return None,
11830 PathChange::Added => lsp::FileChangeType::CREATED,
11831 PathChange::Removed => lsp::FileChangeType::DELETED,
11832 PathChange::Updated => lsp::FileChangeType::CHANGED,
11833 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11834 };
11835 let uri = lsp::Uri::from_file_path(
11836 worktree_handle.read(cx).absolutize(&path),
11837 )
11838 .ok()?;
11839 Some(lsp::FileEvent { uri, typ })
11840 })
11841 .collect(),
11842 };
11843 if !params.changes.is_empty() {
11844 server
11845 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11846 .ok();
11847 }
11848 }
11849 }
11850 for (path, _, _) in changes {
11851 if let Some(file_name) = path.file_name()
11852 && local.watched_manifest_filenames.contains(file_name)
11853 {
11854 self.request_workspace_config_refresh();
11855 break;
11856 }
11857 }
11858 }
11859
11860 pub fn wait_for_remote_buffer(
11861 &mut self,
11862 id: BufferId,
11863 cx: &mut Context<Self>,
11864 ) -> Task<Result<Entity<Buffer>>> {
11865 self.buffer_store.update(cx, |buffer_store, cx| {
11866 buffer_store.wait_for_remote_buffer(id, cx)
11867 })
11868 }
11869
11870 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11871 let mut result = proto::Symbol {
11872 language_server_name: symbol.language_server_name.0.to_string(),
11873 source_worktree_id: symbol.source_worktree_id.to_proto(),
11874 language_server_id: symbol.source_language_server_id.to_proto(),
11875 name: symbol.name.clone(),
11876 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11877 start: Some(proto::PointUtf16 {
11878 row: symbol.range.start.0.row,
11879 column: symbol.range.start.0.column,
11880 }),
11881 end: Some(proto::PointUtf16 {
11882 row: symbol.range.end.0.row,
11883 column: symbol.range.end.0.column,
11884 }),
11885 worktree_id: Default::default(),
11886 path: Default::default(),
11887 signature: Default::default(),
11888 container_name: symbol.container_name.clone(),
11889 };
11890 match &symbol.path {
11891 SymbolLocation::InProject(path) => {
11892 result.worktree_id = path.worktree_id.to_proto();
11893 result.path = path.path.to_proto();
11894 }
11895 SymbolLocation::OutsideProject {
11896 abs_path,
11897 signature,
11898 } => {
11899 result.path = abs_path.to_string_lossy().into_owned();
11900 result.signature = signature.to_vec();
11901 }
11902 }
11903 result
11904 }
11905
11906 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11907 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11908 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11909 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11910
11911 let path = if serialized_symbol.signature.is_empty() {
11912 SymbolLocation::InProject(ProjectPath {
11913 worktree_id,
11914 path: RelPath::from_proto(&serialized_symbol.path)
11915 .context("invalid symbol path")?,
11916 })
11917 } else {
11918 SymbolLocation::OutsideProject {
11919 abs_path: Path::new(&serialized_symbol.path).into(),
11920 signature: serialized_symbol
11921 .signature
11922 .try_into()
11923 .map_err(|_| anyhow!("invalid signature"))?,
11924 }
11925 };
11926
11927 let start = serialized_symbol.start.context("invalid start")?;
11928 let end = serialized_symbol.end.context("invalid end")?;
11929 Ok(CoreSymbol {
11930 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11931 source_worktree_id,
11932 source_language_server_id: LanguageServerId::from_proto(
11933 serialized_symbol.language_server_id,
11934 ),
11935 path,
11936 name: serialized_symbol.name,
11937 range: Unclipped(PointUtf16::new(start.row, start.column))
11938 ..Unclipped(PointUtf16::new(end.row, end.column)),
11939 kind,
11940 container_name: serialized_symbol.container_name,
11941 })
11942 }
11943
11944 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11945 let mut serialized_completion = proto::Completion {
11946 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11947 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11948 new_text: completion.new_text.clone(),
11949 ..proto::Completion::default()
11950 };
11951 match &completion.source {
11952 CompletionSource::Lsp {
11953 insert_range,
11954 server_id,
11955 lsp_completion,
11956 lsp_defaults,
11957 resolved,
11958 } => {
11959 let (old_insert_start, old_insert_end) = insert_range
11960 .as_ref()
11961 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11962 .unzip();
11963
11964 serialized_completion.old_insert_start = old_insert_start;
11965 serialized_completion.old_insert_end = old_insert_end;
11966 serialized_completion.source = proto::completion::Source::Lsp as i32;
11967 serialized_completion.server_id = server_id.0 as u64;
11968 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11969 serialized_completion.lsp_defaults = lsp_defaults
11970 .as_deref()
11971 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11972 serialized_completion.resolved = *resolved;
11973 }
11974 CompletionSource::BufferWord {
11975 word_range,
11976 resolved,
11977 } => {
11978 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11979 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11980 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11981 serialized_completion.resolved = *resolved;
11982 }
11983 CompletionSource::Custom => {
11984 serialized_completion.source = proto::completion::Source::Custom as i32;
11985 serialized_completion.resolved = true;
11986 }
11987 CompletionSource::Dap { sort_text } => {
11988 serialized_completion.source = proto::completion::Source::Dap as i32;
11989 serialized_completion.sort_text = Some(sort_text.clone());
11990 }
11991 }
11992
11993 serialized_completion
11994 }
11995
11996 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11997 let old_replace_start = completion
11998 .old_replace_start
11999 .and_then(deserialize_anchor)
12000 .context("invalid old start")?;
12001 let old_replace_end = completion
12002 .old_replace_end
12003 .and_then(deserialize_anchor)
12004 .context("invalid old end")?;
12005 let insert_range = {
12006 match completion.old_insert_start.zip(completion.old_insert_end) {
12007 Some((start, end)) => {
12008 let start = deserialize_anchor(start).context("invalid insert old start")?;
12009 let end = deserialize_anchor(end).context("invalid insert old end")?;
12010 Some(start..end)
12011 }
12012 None => None,
12013 }
12014 };
12015 Ok(CoreCompletion {
12016 replace_range: old_replace_start..old_replace_end,
12017 new_text: completion.new_text,
12018 source: match proto::completion::Source::from_i32(completion.source) {
12019 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12020 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12021 insert_range,
12022 server_id: LanguageServerId::from_proto(completion.server_id),
12023 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12024 lsp_defaults: completion
12025 .lsp_defaults
12026 .as_deref()
12027 .map(serde_json::from_slice)
12028 .transpose()?,
12029 resolved: completion.resolved,
12030 },
12031 Some(proto::completion::Source::BufferWord) => {
12032 let word_range = completion
12033 .buffer_word_start
12034 .and_then(deserialize_anchor)
12035 .context("invalid buffer word start")?
12036 ..completion
12037 .buffer_word_end
12038 .and_then(deserialize_anchor)
12039 .context("invalid buffer word end")?;
12040 CompletionSource::BufferWord {
12041 word_range,
12042 resolved: completion.resolved,
12043 }
12044 }
12045 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12046 sort_text: completion
12047 .sort_text
12048 .context("expected sort text to exist")?,
12049 },
12050 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12051 },
12052 })
12053 }
12054
12055 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12056 let (kind, lsp_action) = match &action.lsp_action {
12057 LspAction::Action(code_action) => (
12058 proto::code_action::Kind::Action as i32,
12059 serde_json::to_vec(code_action).unwrap(),
12060 ),
12061 LspAction::Command(command) => (
12062 proto::code_action::Kind::Command as i32,
12063 serde_json::to_vec(command).unwrap(),
12064 ),
12065 LspAction::CodeLens(code_lens) => (
12066 proto::code_action::Kind::CodeLens as i32,
12067 serde_json::to_vec(code_lens).unwrap(),
12068 ),
12069 };
12070
12071 proto::CodeAction {
12072 server_id: action.server_id.0 as u64,
12073 start: Some(serialize_anchor(&action.range.start)),
12074 end: Some(serialize_anchor(&action.range.end)),
12075 lsp_action,
12076 kind,
12077 resolved: action.resolved,
12078 }
12079 }
12080
12081 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12082 let start = action
12083 .start
12084 .and_then(deserialize_anchor)
12085 .context("invalid start")?;
12086 let end = action
12087 .end
12088 .and_then(deserialize_anchor)
12089 .context("invalid end")?;
12090 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12091 Some(proto::code_action::Kind::Action) => {
12092 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12093 }
12094 Some(proto::code_action::Kind::Command) => {
12095 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12096 }
12097 Some(proto::code_action::Kind::CodeLens) => {
12098 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12099 }
12100 None => anyhow::bail!("Unknown action kind {}", action.kind),
12101 };
12102 Ok(CodeAction {
12103 server_id: LanguageServerId(action.server_id as usize),
12104 range: start..end,
12105 resolved: action.resolved,
12106 lsp_action,
12107 })
12108 }
12109
12110 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12111 match &formatting_result {
12112 Ok(_) => self.last_formatting_failure = None,
12113 Err(error) => {
12114 let error_string = format!("{error:#}");
12115 log::error!("Formatting failed: {error_string}");
12116 self.last_formatting_failure
12117 .replace(error_string.lines().join(" "));
12118 }
12119 }
12120 }
12121
12122 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12123 self.lsp_server_capabilities.remove(&for_server);
12124 self.semantic_token_config.remove_server_data(for_server);
12125 for lsp_data in self.lsp_data.values_mut() {
12126 lsp_data.remove_server_data(for_server);
12127 }
12128 if let Some(local) = self.as_local_mut() {
12129 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12130 local
12131 .workspace_pull_diagnostics_result_ids
12132 .remove(&for_server);
12133 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12134 buffer_servers.remove(&for_server);
12135 }
12136 }
12137 }
12138
12139 pub fn result_id_for_buffer_pull(
12140 &self,
12141 server_id: LanguageServerId,
12142 buffer_id: BufferId,
12143 registration_id: &Option<SharedString>,
12144 cx: &App,
12145 ) -> Option<SharedString> {
12146 let abs_path = self
12147 .buffer_store
12148 .read(cx)
12149 .get(buffer_id)
12150 .and_then(|b| File::from_dyn(b.read(cx).file()))
12151 .map(|f| f.abs_path(cx))?;
12152 self.as_local()?
12153 .buffer_pull_diagnostics_result_ids
12154 .get(&server_id)?
12155 .get(registration_id)?
12156 .get(&abs_path)?
12157 .clone()
12158 }
12159
12160 /// Gets all result_ids for a workspace diagnostics pull request.
12161 /// 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.
12162 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12163 pub fn result_ids_for_workspace_refresh(
12164 &self,
12165 server_id: LanguageServerId,
12166 registration_id: &Option<SharedString>,
12167 ) -> HashMap<PathBuf, SharedString> {
12168 let Some(local) = self.as_local() else {
12169 return HashMap::default();
12170 };
12171 local
12172 .workspace_pull_diagnostics_result_ids
12173 .get(&server_id)
12174 .into_iter()
12175 .filter_map(|diagnostics| diagnostics.get(registration_id))
12176 .flatten()
12177 .filter_map(|(abs_path, result_id)| {
12178 let result_id = local
12179 .buffer_pull_diagnostics_result_ids
12180 .get(&server_id)
12181 .and_then(|buffer_ids_result_ids| {
12182 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12183 })
12184 .cloned()
12185 .flatten()
12186 .or_else(|| result_id.clone())?;
12187 Some((abs_path.clone(), result_id))
12188 })
12189 .collect()
12190 }
12191
12192 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12193 if let Some(LanguageServerState::Running {
12194 workspace_diagnostics_refresh_tasks,
12195 ..
12196 }) = self
12197 .as_local_mut()
12198 .and_then(|local| local.language_servers.get_mut(&server_id))
12199 {
12200 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12201 diagnostics.refresh_tx.try_send(()).ok();
12202 }
12203 }
12204 }
12205
12206 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12207 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12208 /// which requires refreshing both workspace and document diagnostics.
12209 pub fn pull_document_diagnostics_for_server(
12210 &mut self,
12211 server_id: LanguageServerId,
12212 source_buffer_id: Option<BufferId>,
12213 cx: &mut Context<Self>,
12214 ) -> Shared<Task<()>> {
12215 let Some(local) = self.as_local_mut() else {
12216 return Task::ready(()).shared();
12217 };
12218 let mut buffers_to_refresh = HashSet::default();
12219 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12220 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12221 buffers_to_refresh.insert(*buffer_id);
12222 }
12223 }
12224
12225 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12226 }
12227
12228 pub fn pull_document_diagnostics_for_buffer_edit(
12229 &mut self,
12230 buffer_id: BufferId,
12231 cx: &mut Context<Self>,
12232 ) {
12233 let Some(local) = self.as_local_mut() else {
12234 return;
12235 };
12236 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12237 else {
12238 return;
12239 };
12240 for server_id in languages_servers {
12241 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12242 }
12243 }
12244
12245 fn apply_workspace_diagnostic_report(
12246 &mut self,
12247 server_id: LanguageServerId,
12248 report: lsp::WorkspaceDiagnosticReportResult,
12249 registration_id: Option<SharedString>,
12250 cx: &mut Context<Self>,
12251 ) {
12252 let mut workspace_diagnostics =
12253 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12254 report,
12255 server_id,
12256 registration_id,
12257 );
12258 workspace_diagnostics.retain(|d| match &d.diagnostics {
12259 LspPullDiagnostics::Response {
12260 server_id,
12261 registration_id,
12262 ..
12263 } => self.diagnostic_registration_exists(*server_id, registration_id),
12264 LspPullDiagnostics::Default => false,
12265 });
12266 let mut unchanged_buffers = HashMap::default();
12267 let workspace_diagnostics_updates = workspace_diagnostics
12268 .into_iter()
12269 .filter_map(
12270 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12271 LspPullDiagnostics::Response {
12272 server_id,
12273 uri,
12274 diagnostics,
12275 registration_id,
12276 } => Some((
12277 server_id,
12278 uri,
12279 diagnostics,
12280 workspace_diagnostics.version,
12281 registration_id,
12282 )),
12283 LspPullDiagnostics::Default => None,
12284 },
12285 )
12286 .fold(
12287 HashMap::default(),
12288 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12289 let (result_id, diagnostics) = match diagnostics {
12290 PulledDiagnostics::Unchanged { result_id } => {
12291 unchanged_buffers
12292 .entry(new_registration_id.clone())
12293 .or_insert_with(HashSet::default)
12294 .insert(uri.clone());
12295 (Some(result_id), Vec::new())
12296 }
12297 PulledDiagnostics::Changed {
12298 result_id,
12299 diagnostics,
12300 } => (result_id, diagnostics),
12301 };
12302 let disk_based_sources = Cow::Owned(
12303 self.language_server_adapter_for_id(server_id)
12304 .as_ref()
12305 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12306 .unwrap_or(&[])
12307 .to_vec(),
12308 );
12309
12310 let Some(abs_path) = uri.to_file_path().ok() else {
12311 return acc;
12312 };
12313 let Some((worktree, relative_path)) =
12314 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12315 else {
12316 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12317 return acc;
12318 };
12319 let worktree_id = worktree.read(cx).id();
12320 let project_path = ProjectPath {
12321 worktree_id,
12322 path: relative_path,
12323 };
12324 if let Some(local_lsp_store) = self.as_local_mut() {
12325 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12326 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12327 }
12328 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12329 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12330 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12331 acc.entry(server_id)
12332 .or_insert_with(HashMap::default)
12333 .entry(new_registration_id.clone())
12334 .or_insert_with(Vec::new)
12335 .push(DocumentDiagnosticsUpdate {
12336 server_id,
12337 diagnostics: lsp::PublishDiagnosticsParams {
12338 uri,
12339 diagnostics,
12340 version,
12341 },
12342 result_id: result_id.map(SharedString::new),
12343 disk_based_sources,
12344 registration_id: new_registration_id,
12345 });
12346 }
12347 acc
12348 },
12349 );
12350
12351 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12352 for (registration_id, diagnostic_updates) in diagnostic_updates {
12353 self.merge_lsp_diagnostics(
12354 DiagnosticSourceKind::Pulled,
12355 diagnostic_updates,
12356 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12357 DiagnosticSourceKind::Pulled => {
12358 old_diagnostic.registration_id != registration_id
12359 || unchanged_buffers
12360 .get(&old_diagnostic.registration_id)
12361 .is_some_and(|unchanged_buffers| {
12362 unchanged_buffers.contains(&document_uri)
12363 })
12364 }
12365 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12366 },
12367 cx,
12368 )
12369 .log_err();
12370 }
12371 }
12372 }
12373
12374 fn register_server_capabilities(
12375 &mut self,
12376 server_id: LanguageServerId,
12377 params: lsp::RegistrationParams,
12378 cx: &mut Context<Self>,
12379 ) -> anyhow::Result<()> {
12380 let server = self
12381 .language_server_for_id(server_id)
12382 .with_context(|| format!("no server {server_id} found"))?;
12383 for reg in params.registrations {
12384 match reg.method.as_str() {
12385 "workspace/didChangeWatchedFiles" => {
12386 if let Some(options) = reg.register_options {
12387 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12388 let caps = serde_json::from_value(options)?;
12389 local_lsp_store
12390 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12391 true
12392 } else {
12393 false
12394 };
12395 if notify {
12396 notify_server_capabilities_updated(&server, cx);
12397 }
12398 }
12399 }
12400 "workspace/didChangeConfiguration" => {
12401 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12402 }
12403 "workspace/didChangeWorkspaceFolders" => {
12404 // In this case register options is an empty object, we can ignore it
12405 let caps = lsp::WorkspaceFoldersServerCapabilities {
12406 supported: Some(true),
12407 change_notifications: Some(OneOf::Right(reg.id)),
12408 };
12409 server.update_capabilities(|capabilities| {
12410 capabilities
12411 .workspace
12412 .get_or_insert_default()
12413 .workspace_folders = Some(caps);
12414 });
12415 notify_server_capabilities_updated(&server, cx);
12416 }
12417 "workspace/symbol" => {
12418 let options = parse_register_capabilities(reg)?;
12419 server.update_capabilities(|capabilities| {
12420 capabilities.workspace_symbol_provider = Some(options);
12421 });
12422 notify_server_capabilities_updated(&server, cx);
12423 }
12424 "workspace/fileOperations" => {
12425 if let Some(options) = reg.register_options {
12426 let caps = serde_json::from_value(options)?;
12427 server.update_capabilities(|capabilities| {
12428 capabilities
12429 .workspace
12430 .get_or_insert_default()
12431 .file_operations = Some(caps);
12432 });
12433 notify_server_capabilities_updated(&server, cx);
12434 }
12435 }
12436 "workspace/executeCommand" => {
12437 if let Some(options) = reg.register_options {
12438 let options = serde_json::from_value(options)?;
12439 server.update_capabilities(|capabilities| {
12440 capabilities.execute_command_provider = Some(options);
12441 });
12442 notify_server_capabilities_updated(&server, cx);
12443 }
12444 }
12445 "textDocument/rangeFormatting" => {
12446 let options = parse_register_capabilities(reg)?;
12447 server.update_capabilities(|capabilities| {
12448 capabilities.document_range_formatting_provider = Some(options);
12449 });
12450 notify_server_capabilities_updated(&server, cx);
12451 }
12452 "textDocument/onTypeFormatting" => {
12453 if let Some(options) = reg
12454 .register_options
12455 .map(serde_json::from_value)
12456 .transpose()?
12457 {
12458 server.update_capabilities(|capabilities| {
12459 capabilities.document_on_type_formatting_provider = Some(options);
12460 });
12461 notify_server_capabilities_updated(&server, cx);
12462 }
12463 }
12464 "textDocument/formatting" => {
12465 let options = parse_register_capabilities(reg)?;
12466 server.update_capabilities(|capabilities| {
12467 capabilities.document_formatting_provider = Some(options);
12468 });
12469 notify_server_capabilities_updated(&server, cx);
12470 }
12471 "textDocument/rename" => {
12472 let options = parse_register_capabilities(reg)?;
12473 server.update_capabilities(|capabilities| {
12474 capabilities.rename_provider = Some(options);
12475 });
12476 notify_server_capabilities_updated(&server, cx);
12477 }
12478 "textDocument/inlayHint" => {
12479 let options = parse_register_capabilities(reg)?;
12480 server.update_capabilities(|capabilities| {
12481 capabilities.inlay_hint_provider = Some(options);
12482 });
12483 notify_server_capabilities_updated(&server, cx);
12484 }
12485 "textDocument/documentSymbol" => {
12486 let options = parse_register_capabilities(reg)?;
12487 server.update_capabilities(|capabilities| {
12488 capabilities.document_symbol_provider = Some(options);
12489 });
12490 notify_server_capabilities_updated(&server, cx);
12491 }
12492 "textDocument/codeAction" => {
12493 let options = parse_register_capabilities(reg)?;
12494 let provider = match options {
12495 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12496 OneOf::Right(caps) => caps,
12497 };
12498 server.update_capabilities(|capabilities| {
12499 capabilities.code_action_provider = Some(provider);
12500 });
12501 notify_server_capabilities_updated(&server, cx);
12502 }
12503 "textDocument/definition" => {
12504 let options = parse_register_capabilities(reg)?;
12505 server.update_capabilities(|capabilities| {
12506 capabilities.definition_provider = Some(options);
12507 });
12508 notify_server_capabilities_updated(&server, cx);
12509 }
12510 "textDocument/completion" => {
12511 if let Some(caps) = reg
12512 .register_options
12513 .map(serde_json::from_value::<CompletionOptions>)
12514 .transpose()?
12515 {
12516 server.update_capabilities(|capabilities| {
12517 capabilities.completion_provider = Some(caps.clone());
12518 });
12519
12520 if let Some(local) = self.as_local() {
12521 let mut buffers_with_language_server = Vec::new();
12522 for handle in self.buffer_store.read(cx).buffers() {
12523 let buffer_id = handle.read(cx).remote_id();
12524 if local
12525 .buffers_opened_in_servers
12526 .get(&buffer_id)
12527 .filter(|s| s.contains(&server_id))
12528 .is_some()
12529 {
12530 buffers_with_language_server.push(handle);
12531 }
12532 }
12533 let triggers = caps
12534 .trigger_characters
12535 .unwrap_or_default()
12536 .into_iter()
12537 .collect::<BTreeSet<_>>();
12538 for handle in buffers_with_language_server {
12539 let triggers = triggers.clone();
12540 let _ = handle.update(cx, move |buffer, cx| {
12541 buffer.set_completion_triggers(server_id, triggers, cx);
12542 });
12543 }
12544 }
12545 notify_server_capabilities_updated(&server, cx);
12546 }
12547 }
12548 "textDocument/hover" => {
12549 let options = parse_register_capabilities(reg)?;
12550 let provider = match options {
12551 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12552 OneOf::Right(caps) => caps,
12553 };
12554 server.update_capabilities(|capabilities| {
12555 capabilities.hover_provider = Some(provider);
12556 });
12557 notify_server_capabilities_updated(&server, cx);
12558 }
12559 "textDocument/signatureHelp" => {
12560 if let Some(caps) = reg
12561 .register_options
12562 .map(serde_json::from_value)
12563 .transpose()?
12564 {
12565 server.update_capabilities(|capabilities| {
12566 capabilities.signature_help_provider = Some(caps);
12567 });
12568 notify_server_capabilities_updated(&server, cx);
12569 }
12570 }
12571 "textDocument/didChange" => {
12572 if let Some(sync_kind) = reg
12573 .register_options
12574 .and_then(|opts| opts.get("syncKind").cloned())
12575 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12576 .transpose()?
12577 {
12578 server.update_capabilities(|capabilities| {
12579 let mut sync_options =
12580 Self::take_text_document_sync_options(capabilities);
12581 sync_options.change = Some(sync_kind);
12582 capabilities.text_document_sync =
12583 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12584 });
12585 notify_server_capabilities_updated(&server, cx);
12586 }
12587 }
12588 "textDocument/didSave" => {
12589 if let Some(include_text) = reg
12590 .register_options
12591 .map(|opts| {
12592 let transpose = opts
12593 .get("includeText")
12594 .cloned()
12595 .map(serde_json::from_value::<Option<bool>>)
12596 .transpose();
12597 match transpose {
12598 Ok(value) => Ok(value.flatten()),
12599 Err(e) => Err(e),
12600 }
12601 })
12602 .transpose()?
12603 {
12604 server.update_capabilities(|capabilities| {
12605 let mut sync_options =
12606 Self::take_text_document_sync_options(capabilities);
12607 sync_options.save =
12608 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12609 include_text,
12610 }));
12611 capabilities.text_document_sync =
12612 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12613 });
12614 notify_server_capabilities_updated(&server, cx);
12615 }
12616 }
12617 "textDocument/codeLens" => {
12618 if let Some(caps) = reg
12619 .register_options
12620 .map(serde_json::from_value)
12621 .transpose()?
12622 {
12623 server.update_capabilities(|capabilities| {
12624 capabilities.code_lens_provider = Some(caps);
12625 });
12626 notify_server_capabilities_updated(&server, cx);
12627 }
12628 }
12629 "textDocument/diagnostic" => {
12630 if let Some(caps) = reg
12631 .register_options
12632 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12633 .transpose()?
12634 {
12635 let local = self
12636 .as_local_mut()
12637 .context("Expected LSP Store to be local")?;
12638 let state = local
12639 .language_servers
12640 .get_mut(&server_id)
12641 .context("Could not obtain Language Servers state")?;
12642 local
12643 .language_server_dynamic_registrations
12644 .entry(server_id)
12645 .or_default()
12646 .diagnostics
12647 .insert(Some(reg.id.clone()), caps.clone());
12648
12649 let supports_workspace_diagnostics =
12650 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12651 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12652 diagnostic_options.workspace_diagnostics
12653 }
12654 DiagnosticServerCapabilities::RegistrationOptions(
12655 diagnostic_registration_options,
12656 ) => {
12657 diagnostic_registration_options
12658 .diagnostic_options
12659 .workspace_diagnostics
12660 }
12661 };
12662
12663 if supports_workspace_diagnostics(&caps) {
12664 if let LanguageServerState::Running {
12665 workspace_diagnostics_refresh_tasks,
12666 ..
12667 } = state
12668 && let Some(task) = lsp_workspace_diagnostics_refresh(
12669 Some(reg.id.clone()),
12670 caps.clone(),
12671 server.clone(),
12672 cx,
12673 )
12674 {
12675 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12676 }
12677 }
12678
12679 server.update_capabilities(|capabilities| {
12680 capabilities.diagnostic_provider = Some(caps);
12681 });
12682
12683 notify_server_capabilities_updated(&server, cx);
12684
12685 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12686 }
12687 }
12688 "textDocument/documentColor" => {
12689 let options = parse_register_capabilities(reg)?;
12690 let provider = match options {
12691 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12692 OneOf::Right(caps) => caps,
12693 };
12694 server.update_capabilities(|capabilities| {
12695 capabilities.color_provider = Some(provider);
12696 });
12697 notify_server_capabilities_updated(&server, cx);
12698 }
12699 "textDocument/foldingRange" => {
12700 let options = parse_register_capabilities(reg)?;
12701 let provider = match options {
12702 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12703 OneOf::Right(caps) => caps,
12704 };
12705 server.update_capabilities(|capabilities| {
12706 capabilities.folding_range_provider = Some(provider);
12707 });
12708 notify_server_capabilities_updated(&server, cx);
12709 }
12710 _ => log::warn!("unhandled capability registration: {reg:?}"),
12711 }
12712 }
12713
12714 Ok(())
12715 }
12716
12717 fn unregister_server_capabilities(
12718 &mut self,
12719 server_id: LanguageServerId,
12720 params: lsp::UnregistrationParams,
12721 cx: &mut Context<Self>,
12722 ) -> anyhow::Result<()> {
12723 let server = self
12724 .language_server_for_id(server_id)
12725 .with_context(|| format!("no server {server_id} found"))?;
12726 for unreg in params.unregisterations.iter() {
12727 match unreg.method.as_str() {
12728 "workspace/didChangeWatchedFiles" => {
12729 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12730 local_lsp_store
12731 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12732 true
12733 } else {
12734 false
12735 };
12736 if notify {
12737 notify_server_capabilities_updated(&server, cx);
12738 }
12739 }
12740 "workspace/didChangeConfiguration" => {
12741 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12742 }
12743 "workspace/didChangeWorkspaceFolders" => {
12744 server.update_capabilities(|capabilities| {
12745 capabilities
12746 .workspace
12747 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12748 workspace_folders: None,
12749 file_operations: None,
12750 })
12751 .workspace_folders = None;
12752 });
12753 notify_server_capabilities_updated(&server, cx);
12754 }
12755 "workspace/symbol" => {
12756 server.update_capabilities(|capabilities| {
12757 capabilities.workspace_symbol_provider = None
12758 });
12759 notify_server_capabilities_updated(&server, cx);
12760 }
12761 "workspace/fileOperations" => {
12762 server.update_capabilities(|capabilities| {
12763 capabilities
12764 .workspace
12765 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12766 workspace_folders: None,
12767 file_operations: None,
12768 })
12769 .file_operations = None;
12770 });
12771 notify_server_capabilities_updated(&server, cx);
12772 }
12773 "workspace/executeCommand" => {
12774 server.update_capabilities(|capabilities| {
12775 capabilities.execute_command_provider = None;
12776 });
12777 notify_server_capabilities_updated(&server, cx);
12778 }
12779 "textDocument/rangeFormatting" => {
12780 server.update_capabilities(|capabilities| {
12781 capabilities.document_range_formatting_provider = None
12782 });
12783 notify_server_capabilities_updated(&server, cx);
12784 }
12785 "textDocument/onTypeFormatting" => {
12786 server.update_capabilities(|capabilities| {
12787 capabilities.document_on_type_formatting_provider = None;
12788 });
12789 notify_server_capabilities_updated(&server, cx);
12790 }
12791 "textDocument/formatting" => {
12792 server.update_capabilities(|capabilities| {
12793 capabilities.document_formatting_provider = None;
12794 });
12795 notify_server_capabilities_updated(&server, cx);
12796 }
12797 "textDocument/rename" => {
12798 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12799 notify_server_capabilities_updated(&server, cx);
12800 }
12801 "textDocument/codeAction" => {
12802 server.update_capabilities(|capabilities| {
12803 capabilities.code_action_provider = None;
12804 });
12805 notify_server_capabilities_updated(&server, cx);
12806 }
12807 "textDocument/definition" => {
12808 server.update_capabilities(|capabilities| {
12809 capabilities.definition_provider = None;
12810 });
12811 notify_server_capabilities_updated(&server, cx);
12812 }
12813 "textDocument/completion" => {
12814 server.update_capabilities(|capabilities| {
12815 capabilities.completion_provider = None;
12816 });
12817 notify_server_capabilities_updated(&server, cx);
12818 }
12819 "textDocument/hover" => {
12820 server.update_capabilities(|capabilities| {
12821 capabilities.hover_provider = None;
12822 });
12823 notify_server_capabilities_updated(&server, cx);
12824 }
12825 "textDocument/signatureHelp" => {
12826 server.update_capabilities(|capabilities| {
12827 capabilities.signature_help_provider = None;
12828 });
12829 notify_server_capabilities_updated(&server, cx);
12830 }
12831 "textDocument/didChange" => {
12832 server.update_capabilities(|capabilities| {
12833 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12834 sync_options.change = None;
12835 capabilities.text_document_sync =
12836 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12837 });
12838 notify_server_capabilities_updated(&server, cx);
12839 }
12840 "textDocument/didSave" => {
12841 server.update_capabilities(|capabilities| {
12842 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12843 sync_options.save = None;
12844 capabilities.text_document_sync =
12845 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12846 });
12847 notify_server_capabilities_updated(&server, cx);
12848 }
12849 "textDocument/codeLens" => {
12850 server.update_capabilities(|capabilities| {
12851 capabilities.code_lens_provider = None;
12852 });
12853 notify_server_capabilities_updated(&server, cx);
12854 }
12855 "textDocument/diagnostic" => {
12856 let local = self
12857 .as_local_mut()
12858 .context("Expected LSP Store to be local")?;
12859
12860 let state = local
12861 .language_servers
12862 .get_mut(&server_id)
12863 .context("Could not obtain Language Servers state")?;
12864 let registrations = local
12865 .language_server_dynamic_registrations
12866 .get_mut(&server_id)
12867 .with_context(|| {
12868 format!("Expected dynamic registration to exist for server {server_id}")
12869 })?;
12870 registrations.diagnostics
12871 .remove(&Some(unreg.id.clone()))
12872 .with_context(|| format!(
12873 "Attempted to unregister non-existent diagnostic registration with ID {}",
12874 unreg.id)
12875 )?;
12876 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12877
12878 if let LanguageServerState::Running {
12879 workspace_diagnostics_refresh_tasks,
12880 ..
12881 } = state
12882 {
12883 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12884 }
12885
12886 self.clear_unregistered_diagnostics(
12887 server_id,
12888 SharedString::from(unreg.id.clone()),
12889 cx,
12890 )?;
12891
12892 if removed_last_diagnostic_provider {
12893 server.update_capabilities(|capabilities| {
12894 debug_assert!(capabilities.diagnostic_provider.is_some());
12895 capabilities.diagnostic_provider = None;
12896 });
12897 }
12898
12899 notify_server_capabilities_updated(&server, cx);
12900 }
12901 "textDocument/documentColor" => {
12902 server.update_capabilities(|capabilities| {
12903 capabilities.color_provider = None;
12904 });
12905 notify_server_capabilities_updated(&server, cx);
12906 }
12907 "textDocument/foldingRange" => {
12908 server.update_capabilities(|capabilities| {
12909 capabilities.folding_range_provider = None;
12910 });
12911 notify_server_capabilities_updated(&server, cx);
12912 }
12913 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12914 }
12915 }
12916
12917 Ok(())
12918 }
12919
12920 fn clear_unregistered_diagnostics(
12921 &mut self,
12922 server_id: LanguageServerId,
12923 cleared_registration_id: SharedString,
12924 cx: &mut Context<Self>,
12925 ) -> anyhow::Result<()> {
12926 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12927
12928 self.buffer_store.update(cx, |buffer_store, cx| {
12929 for buffer_handle in buffer_store.buffers() {
12930 let buffer = buffer_handle.read(cx);
12931 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12932 let Some(abs_path) = abs_path else {
12933 continue;
12934 };
12935 affected_abs_paths.insert(abs_path);
12936 }
12937 });
12938
12939 let local = self.as_local().context("Expected LSP Store to be local")?;
12940 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12941 let Some(worktree) = self
12942 .worktree_store
12943 .read(cx)
12944 .worktree_for_id(*worktree_id, cx)
12945 else {
12946 continue;
12947 };
12948
12949 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12950 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12951 let has_matching_registration =
12952 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12953 entry.diagnostic.registration_id.as_ref()
12954 == Some(&cleared_registration_id)
12955 });
12956 if has_matching_registration {
12957 let abs_path = worktree.read(cx).absolutize(rel_path);
12958 affected_abs_paths.insert(abs_path);
12959 }
12960 }
12961 }
12962 }
12963
12964 if affected_abs_paths.is_empty() {
12965 return Ok(());
12966 }
12967
12968 // Send a fake diagnostic update which clears the state for the registration ID
12969 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12970 affected_abs_paths
12971 .into_iter()
12972 .map(|abs_path| DocumentDiagnosticsUpdate {
12973 diagnostics: DocumentDiagnostics {
12974 diagnostics: Vec::new(),
12975 document_abs_path: abs_path,
12976 version: None,
12977 },
12978 result_id: None,
12979 registration_id: Some(cleared_registration_id.clone()),
12980 server_id,
12981 disk_based_sources: Cow::Borrowed(&[]),
12982 })
12983 .collect();
12984
12985 let merge_registration_id = cleared_registration_id.clone();
12986 self.merge_diagnostic_entries(
12987 clears,
12988 move |_, diagnostic, _| {
12989 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12990 diagnostic.registration_id != Some(merge_registration_id.clone())
12991 } else {
12992 true
12993 }
12994 },
12995 cx,
12996 )?;
12997
12998 Ok(())
12999 }
13000
13001 async fn deduplicate_range_based_lsp_requests<T>(
13002 lsp_store: &Entity<Self>,
13003 server_id: Option<LanguageServerId>,
13004 lsp_request_id: LspRequestId,
13005 proto_request: &T::ProtoRequest,
13006 range: Range<Anchor>,
13007 cx: &mut AsyncApp,
13008 ) -> Result<()>
13009 where
13010 T: LspCommand,
13011 T::ProtoRequest: proto::LspRequestMessage,
13012 {
13013 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13014 let version = deserialize_version(proto_request.buffer_version());
13015 let buffer = lsp_store.update(cx, |this, cx| {
13016 this.buffer_store.read(cx).get_existing(buffer_id)
13017 })?;
13018 buffer
13019 .update(cx, |buffer, _| buffer.wait_for_version(version))
13020 .await?;
13021 lsp_store.update(cx, |lsp_store, cx| {
13022 let buffer_snapshot = buffer.read(cx).snapshot();
13023 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13024 let chunks_queried_for = lsp_data
13025 .inlay_hints
13026 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13027 .collect::<Vec<_>>();
13028 match chunks_queried_for.as_slice() {
13029 &[chunk] => {
13030 let key = LspKey {
13031 request_type: TypeId::of::<T>(),
13032 server_queried: server_id,
13033 };
13034 let previous_request = lsp_data
13035 .chunk_lsp_requests
13036 .entry(key)
13037 .or_default()
13038 .insert(chunk, lsp_request_id);
13039 if let Some((previous_request, running_requests)) =
13040 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13041 {
13042 running_requests.remove(&previous_request);
13043 }
13044 }
13045 _ambiguous_chunks => {
13046 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13047 // there, a buffer version-based check will be performed and outdated requests discarded.
13048 }
13049 }
13050 anyhow::Ok(())
13051 })?;
13052
13053 Ok(())
13054 }
13055
13056 async fn query_lsp_locally<T>(
13057 lsp_store: Entity<Self>,
13058 for_server_id: Option<LanguageServerId>,
13059 sender_id: proto::PeerId,
13060 lsp_request_id: LspRequestId,
13061 proto_request: T::ProtoRequest,
13062 position: Option<Anchor>,
13063 cx: &mut AsyncApp,
13064 ) -> Result<()>
13065 where
13066 T: LspCommand + Clone,
13067 T::ProtoRequest: proto::LspRequestMessage,
13068 <T::ProtoRequest as proto::RequestMessage>::Response:
13069 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13070 {
13071 let (buffer_version, buffer) =
13072 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13073 let request =
13074 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13075 let key = LspKey {
13076 request_type: TypeId::of::<T>(),
13077 server_queried: for_server_id,
13078 };
13079 lsp_store.update(cx, |lsp_store, cx| {
13080 let request_task = match for_server_id {
13081 Some(server_id) => {
13082 let server_task = lsp_store.request_lsp(
13083 buffer.clone(),
13084 LanguageServerToQuery::Other(server_id),
13085 request.clone(),
13086 cx,
13087 );
13088 cx.background_spawn(async move {
13089 let mut responses = Vec::new();
13090 match server_task.await {
13091 Ok(response) => responses.push((server_id, response)),
13092 // rust-analyzer likes to error with this when its still loading up
13093 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13094 Err(e) => log::error!(
13095 "Error handling response for request {request:?}: {e:#}"
13096 ),
13097 }
13098 responses
13099 })
13100 }
13101 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13102 };
13103 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13104 if T::ProtoRequest::stop_previous_requests() {
13105 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13106 lsp_requests.clear();
13107 }
13108 }
13109 lsp_data.lsp_requests.entry(key).or_default().insert(
13110 lsp_request_id,
13111 cx.spawn(async move |lsp_store, cx| {
13112 let response = request_task.await;
13113 lsp_store
13114 .update(cx, |lsp_store, cx| {
13115 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13116 {
13117 let response = response
13118 .into_iter()
13119 .map(|(server_id, response)| {
13120 (
13121 server_id.to_proto(),
13122 T::response_to_proto(
13123 response,
13124 lsp_store,
13125 sender_id,
13126 &buffer_version,
13127 cx,
13128 )
13129 .into(),
13130 )
13131 })
13132 .collect::<HashMap<_, _>>();
13133 match client.send_lsp_response::<T::ProtoRequest>(
13134 project_id,
13135 lsp_request_id,
13136 response,
13137 ) {
13138 Ok(()) => {}
13139 Err(e) => {
13140 log::error!("Failed to send LSP response: {e:#}",)
13141 }
13142 }
13143 }
13144 })
13145 .ok();
13146 }),
13147 );
13148 });
13149 Ok(())
13150 }
13151
13152 async fn wait_for_buffer_version<T>(
13153 lsp_store: &Entity<Self>,
13154 proto_request: &T::ProtoRequest,
13155 cx: &mut AsyncApp,
13156 ) -> Result<(Global, Entity<Buffer>)>
13157 where
13158 T: LspCommand,
13159 T::ProtoRequest: proto::LspRequestMessage,
13160 {
13161 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13162 let version = deserialize_version(proto_request.buffer_version());
13163 let buffer = lsp_store.update(cx, |this, cx| {
13164 this.buffer_store.read(cx).get_existing(buffer_id)
13165 })?;
13166 buffer
13167 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13168 .await?;
13169 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13170 Ok((buffer_version, buffer))
13171 }
13172
13173 fn take_text_document_sync_options(
13174 capabilities: &mut lsp::ServerCapabilities,
13175 ) -> lsp::TextDocumentSyncOptions {
13176 match capabilities.text_document_sync.take() {
13177 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13178 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13179 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13180 sync_options.change = Some(sync_kind);
13181 sync_options
13182 }
13183 None => lsp::TextDocumentSyncOptions::default(),
13184 }
13185 }
13186
13187 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13188 self.downstream_client.clone()
13189 }
13190
13191 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13192 self.worktree_store.clone()
13193 }
13194
13195 /// Gets what's stored in the LSP data for the given buffer.
13196 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13197 self.lsp_data.get_mut(&buffer_id)
13198 }
13199
13200 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13201 /// new [`BufferLspData`] will be created to replace the previous state.
13202 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13203 let (buffer_id, buffer_version) =
13204 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13205 let lsp_data = self
13206 .lsp_data
13207 .entry(buffer_id)
13208 .or_insert_with(|| BufferLspData::new(buffer, cx));
13209 if buffer_version.changed_since(&lsp_data.buffer_version) {
13210 // To send delta requests for semantic tokens, the previous tokens
13211 // need to be kept between buffer changes.
13212 let semantic_tokens = lsp_data.semantic_tokens.take();
13213 *lsp_data = BufferLspData::new(buffer, cx);
13214 lsp_data.semantic_tokens = semantic_tokens;
13215 }
13216 lsp_data
13217 }
13218}
13219
13220// Registration with registerOptions as null, should fallback to true.
13221// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13222fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13223 reg: lsp::Registration,
13224) -> Result<OneOf<bool, T>> {
13225 Ok(match reg.register_options {
13226 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13227 None => OneOf::Left(true),
13228 })
13229}
13230
13231fn subscribe_to_binary_statuses(
13232 languages: &Arc<LanguageRegistry>,
13233 cx: &mut Context<'_, LspStore>,
13234) -> Task<()> {
13235 let mut server_statuses = languages.language_server_binary_statuses();
13236 cx.spawn(async move |lsp_store, cx| {
13237 while let Some((server_name, binary_status)) = server_statuses.next().await {
13238 if lsp_store
13239 .update(cx, |_, cx| {
13240 let mut message = None;
13241 let binary_status = match binary_status {
13242 BinaryStatus::None => proto::ServerBinaryStatus::None,
13243 BinaryStatus::CheckingForUpdate => {
13244 proto::ServerBinaryStatus::CheckingForUpdate
13245 }
13246 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13247 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13248 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13249 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13250 BinaryStatus::Failed { error } => {
13251 message = Some(error);
13252 proto::ServerBinaryStatus::Failed
13253 }
13254 };
13255 cx.emit(LspStoreEvent::LanguageServerUpdate {
13256 // Binary updates are about the binary that might not have any language server id at that point.
13257 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13258 language_server_id: LanguageServerId(0),
13259 name: Some(server_name),
13260 message: proto::update_language_server::Variant::StatusUpdate(
13261 proto::StatusUpdate {
13262 message,
13263 status: Some(proto::status_update::Status::Binary(
13264 binary_status as i32,
13265 )),
13266 },
13267 ),
13268 });
13269 })
13270 .is_err()
13271 {
13272 break;
13273 }
13274 }
13275 })
13276}
13277
13278fn lsp_workspace_diagnostics_refresh(
13279 registration_id: Option<String>,
13280 options: DiagnosticServerCapabilities,
13281 server: Arc<LanguageServer>,
13282 cx: &mut Context<'_, LspStore>,
13283) -> Option<WorkspaceRefreshTask> {
13284 let identifier = workspace_diagnostic_identifier(&options)?;
13285 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13286
13287 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13288 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13289 refresh_tx.try_send(()).ok();
13290
13291 let request_timeout = ProjectSettings::get_global(cx)
13292 .global_lsp_settings
13293 .get_request_timeout();
13294
13295 // 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.
13296 // This allows users to increase the duration if need be
13297 let timeout = if request_timeout != Duration::ZERO {
13298 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13299 } else {
13300 request_timeout
13301 };
13302
13303 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13304 let mut attempts = 0;
13305 let max_attempts = 50;
13306 let mut requests = 0;
13307
13308 loop {
13309 let Some(()) = refresh_rx.recv().await else {
13310 return;
13311 };
13312
13313 'request: loop {
13314 requests += 1;
13315 if attempts > max_attempts {
13316 log::error!(
13317 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13318 );
13319 return;
13320 }
13321 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13322 cx.background_executor()
13323 .timer(Duration::from_millis(backoff_millis))
13324 .await;
13325 attempts += 1;
13326
13327 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13328 lsp_store
13329 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13330 .into_iter()
13331 .filter_map(|(abs_path, result_id)| {
13332 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13333 Some(lsp::PreviousResultId {
13334 uri,
13335 value: result_id.to_string(),
13336 })
13337 })
13338 .collect()
13339 }) else {
13340 return;
13341 };
13342
13343 let token = if let Some(registration_id) = ®istration_id {
13344 format!(
13345 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13346 server.server_id(),
13347 )
13348 } else {
13349 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13350 };
13351
13352 progress_rx.try_recv().ok();
13353 let timer = server.request_timer(timeout).fuse();
13354 let progress = pin!(progress_rx.recv().fuse());
13355 let response_result = server
13356 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13357 lsp::WorkspaceDiagnosticParams {
13358 previous_result_ids,
13359 identifier: identifier.clone(),
13360 work_done_progress_params: Default::default(),
13361 partial_result_params: lsp::PartialResultParams {
13362 partial_result_token: Some(lsp::ProgressToken::String(token)),
13363 },
13364 },
13365 select(timer, progress).then(|either| match either {
13366 Either::Left((message, ..)) => ready(message).left_future(),
13367 Either::Right(..) => pending::<String>().right_future(),
13368 }),
13369 )
13370 .await;
13371
13372 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13373 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13374 match response_result {
13375 ConnectionResult::Timeout => {
13376 log::error!("Timeout during workspace diagnostics pull");
13377 continue 'request;
13378 }
13379 ConnectionResult::ConnectionReset => {
13380 log::error!("Server closed a workspace diagnostics pull request");
13381 continue 'request;
13382 }
13383 ConnectionResult::Result(Err(e)) => {
13384 log::error!("Error during workspace diagnostics pull: {e:#}");
13385 break 'request;
13386 }
13387 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13388 attempts = 0;
13389 if lsp_store
13390 .update(cx, |lsp_store, cx| {
13391 lsp_store.apply_workspace_diagnostic_report(
13392 server.server_id(),
13393 pulled_diagnostics,
13394 registration_id_shared.clone(),
13395 cx,
13396 )
13397 })
13398 .is_err()
13399 {
13400 return;
13401 }
13402 break 'request;
13403 }
13404 }
13405 }
13406 }
13407 });
13408
13409 Some(WorkspaceRefreshTask {
13410 refresh_tx,
13411 progress_tx,
13412 task: workspace_query_language_server,
13413 })
13414}
13415
13416fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13417 match &options {
13418 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13419 .identifier
13420 .as_deref()
13421 .map(SharedString::new),
13422 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13423 let diagnostic_options = ®istration_options.diagnostic_options;
13424 diagnostic_options
13425 .identifier
13426 .as_deref()
13427 .map(SharedString::new)
13428 }
13429 }
13430}
13431
13432fn workspace_diagnostic_identifier(
13433 options: &DiagnosticServerCapabilities,
13434) -> Option<Option<String>> {
13435 match &options {
13436 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13437 if !diagnostic_options.workspace_diagnostics {
13438 return None;
13439 }
13440 Some(diagnostic_options.identifier.clone())
13441 }
13442 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13443 let diagnostic_options = ®istration_options.diagnostic_options;
13444 if !diagnostic_options.workspace_diagnostics {
13445 return None;
13446 }
13447 Some(diagnostic_options.identifier.clone())
13448 }
13449 }
13450}
13451
13452fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13453 let CompletionSource::BufferWord {
13454 word_range,
13455 resolved,
13456 } = &mut completion.source
13457 else {
13458 return;
13459 };
13460 if *resolved {
13461 return;
13462 }
13463
13464 if completion.new_text
13465 != snapshot
13466 .text_for_range(word_range.clone())
13467 .collect::<String>()
13468 {
13469 return;
13470 }
13471
13472 let mut offset = 0;
13473 for chunk in snapshot.chunks(word_range.clone(), true) {
13474 let end_offset = offset + chunk.text.len();
13475 if let Some(highlight_id) = chunk.syntax_highlight_id {
13476 completion
13477 .label
13478 .runs
13479 .push((offset..end_offset, highlight_id));
13480 }
13481 offset = end_offset;
13482 }
13483 *resolved = true;
13484}
13485
13486impl EventEmitter<LspStoreEvent> for LspStore {}
13487
13488fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13489 hover
13490 .contents
13491 .retain(|hover_block| !hover_block.text.trim().is_empty());
13492 if hover.contents.is_empty() {
13493 None
13494 } else {
13495 Some(hover)
13496 }
13497}
13498
13499async fn populate_labels_for_completions(
13500 new_completions: Vec<CoreCompletion>,
13501 language: Option<Arc<Language>>,
13502 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13503) -> Vec<Completion> {
13504 let lsp_completions = new_completions
13505 .iter()
13506 .filter_map(|new_completion| {
13507 new_completion
13508 .source
13509 .lsp_completion(true)
13510 .map(|lsp_completion| lsp_completion.into_owned())
13511 })
13512 .collect::<Vec<_>>();
13513
13514 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13515 lsp_adapter
13516 .labels_for_completions(&lsp_completions, language)
13517 .await
13518 .log_err()
13519 .unwrap_or_default()
13520 } else {
13521 Vec::new()
13522 }
13523 .into_iter()
13524 .fuse();
13525
13526 let mut completions = Vec::new();
13527 for completion in new_completions {
13528 match completion.source.lsp_completion(true) {
13529 Some(lsp_completion) => {
13530 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13531
13532 let mut label = labels.next().flatten().unwrap_or_else(|| {
13533 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13534 });
13535 ensure_uniform_list_compatible_label(&mut label);
13536 completions.push(Completion {
13537 label,
13538 documentation,
13539 replace_range: completion.replace_range,
13540 new_text: completion.new_text,
13541 insert_text_mode: lsp_completion.insert_text_mode,
13542 source: completion.source,
13543 icon_path: None,
13544 confirm: None,
13545 match_start: None,
13546 snippet_deduplication_key: None,
13547 });
13548 }
13549 None => {
13550 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13551 ensure_uniform_list_compatible_label(&mut label);
13552 completions.push(Completion {
13553 label,
13554 documentation: None,
13555 replace_range: completion.replace_range,
13556 new_text: completion.new_text,
13557 source: completion.source,
13558 insert_text_mode: None,
13559 icon_path: None,
13560 confirm: None,
13561 match_start: None,
13562 snippet_deduplication_key: None,
13563 });
13564 }
13565 }
13566 }
13567 completions
13568}
13569
13570#[derive(Debug)]
13571pub enum LanguageServerToQuery {
13572 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13573 FirstCapable,
13574 /// Query a specific language server.
13575 Other(LanguageServerId),
13576}
13577
13578#[derive(Default)]
13579struct RenamePathsWatchedForServer {
13580 did_rename: Vec<RenameActionPredicate>,
13581 will_rename: Vec<RenameActionPredicate>,
13582}
13583
13584impl RenamePathsWatchedForServer {
13585 fn with_did_rename_patterns(
13586 mut self,
13587 did_rename: Option<&FileOperationRegistrationOptions>,
13588 ) -> Self {
13589 if let Some(did_rename) = did_rename {
13590 self.did_rename = did_rename
13591 .filters
13592 .iter()
13593 .filter_map(|filter| filter.try_into().log_err())
13594 .collect();
13595 }
13596 self
13597 }
13598 fn with_will_rename_patterns(
13599 mut self,
13600 will_rename: Option<&FileOperationRegistrationOptions>,
13601 ) -> Self {
13602 if let Some(will_rename) = will_rename {
13603 self.will_rename = will_rename
13604 .filters
13605 .iter()
13606 .filter_map(|filter| filter.try_into().log_err())
13607 .collect();
13608 }
13609 self
13610 }
13611
13612 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13613 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13614 }
13615 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13616 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13617 }
13618}
13619
13620impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13621 type Error = globset::Error;
13622 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13623 Ok(Self {
13624 kind: ops.pattern.matches.clone(),
13625 glob: GlobBuilder::new(&ops.pattern.glob)
13626 .case_insensitive(
13627 ops.pattern
13628 .options
13629 .as_ref()
13630 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13631 )
13632 .build()?
13633 .compile_matcher(),
13634 })
13635 }
13636}
13637struct RenameActionPredicate {
13638 glob: GlobMatcher,
13639 kind: Option<FileOperationPatternKind>,
13640}
13641
13642impl RenameActionPredicate {
13643 // Returns true if language server should be notified
13644 fn eval(&self, path: &str, is_dir: bool) -> bool {
13645 self.kind.as_ref().is_none_or(|kind| {
13646 let expected_kind = if is_dir {
13647 FileOperationPatternKind::Folder
13648 } else {
13649 FileOperationPatternKind::File
13650 };
13651 kind == &expected_kind
13652 }) && self.glob.is_match(path)
13653 }
13654}
13655
13656#[derive(Default)]
13657struct LanguageServerWatchedPaths {
13658 worktree_paths: HashMap<WorktreeId, GlobSet>,
13659 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13660}
13661
13662#[derive(Default)]
13663struct LanguageServerWatchedPathsBuilder {
13664 worktree_paths: HashMap<WorktreeId, GlobSet>,
13665 abs_paths: HashMap<Arc<Path>, GlobSet>,
13666}
13667
13668impl LanguageServerWatchedPathsBuilder {
13669 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13670 self.worktree_paths.insert(worktree_id, glob_set);
13671 }
13672 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13673 self.abs_paths.insert(path, glob_set);
13674 }
13675 fn build(
13676 self,
13677 fs: Arc<dyn Fs>,
13678 language_server_id: LanguageServerId,
13679 cx: &mut Context<LspStore>,
13680 ) -> LanguageServerWatchedPaths {
13681 let lsp_store = cx.weak_entity();
13682
13683 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13684 let abs_paths = self
13685 .abs_paths
13686 .into_iter()
13687 .map(|(abs_path, globset)| {
13688 let task = cx.spawn({
13689 let abs_path = abs_path.clone();
13690 let fs = fs.clone();
13691
13692 let lsp_store = lsp_store.clone();
13693 async move |_, cx| {
13694 maybe!(async move {
13695 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13696 while let Some(update) = push_updates.0.next().await {
13697 let action = lsp_store
13698 .update(cx, |this, _| {
13699 let Some(local) = this.as_local() else {
13700 return ControlFlow::Break(());
13701 };
13702 let Some(watcher) = local
13703 .language_server_watched_paths
13704 .get(&language_server_id)
13705 else {
13706 return ControlFlow::Break(());
13707 };
13708 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13709 "Watched abs path is not registered with a watcher",
13710 );
13711 let matching_entries = update
13712 .into_iter()
13713 .filter(|event| globs.is_match(&event.path))
13714 .collect::<Vec<_>>();
13715 this.lsp_notify_abs_paths_changed(
13716 language_server_id,
13717 matching_entries,
13718 );
13719 ControlFlow::Continue(())
13720 })
13721 .ok()?;
13722
13723 if action.is_break() {
13724 break;
13725 }
13726 }
13727 Some(())
13728 })
13729 .await;
13730 }
13731 });
13732 (abs_path, (globset, task))
13733 })
13734 .collect();
13735 LanguageServerWatchedPaths {
13736 worktree_paths: self.worktree_paths,
13737 abs_paths,
13738 }
13739 }
13740}
13741
13742struct LspBufferSnapshot {
13743 version: i32,
13744 snapshot: TextBufferSnapshot,
13745}
13746
13747/// A prompt requested by LSP server.
13748#[derive(Clone, Debug)]
13749pub struct LanguageServerPromptRequest {
13750 pub id: usize,
13751 pub level: PromptLevel,
13752 pub message: String,
13753 pub actions: Vec<MessageActionItem>,
13754 pub lsp_name: String,
13755 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13756}
13757
13758impl LanguageServerPromptRequest {
13759 pub fn new(
13760 level: PromptLevel,
13761 message: String,
13762 actions: Vec<MessageActionItem>,
13763 lsp_name: String,
13764 response_channel: smol::channel::Sender<MessageActionItem>,
13765 ) -> Self {
13766 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13767 LanguageServerPromptRequest {
13768 id,
13769 level,
13770 message,
13771 actions,
13772 lsp_name,
13773 response_channel,
13774 }
13775 }
13776 pub async fn respond(self, index: usize) -> Option<()> {
13777 if let Some(response) = self.actions.into_iter().nth(index) {
13778 self.response_channel.send(response).await.ok()
13779 } else {
13780 None
13781 }
13782 }
13783
13784 #[cfg(any(test, feature = "test-support"))]
13785 pub fn test(
13786 level: PromptLevel,
13787 message: String,
13788 actions: Vec<MessageActionItem>,
13789 lsp_name: String,
13790 ) -> Self {
13791 let (tx, _rx) = smol::channel::unbounded();
13792 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13793 }
13794}
13795impl PartialEq for LanguageServerPromptRequest {
13796 fn eq(&self, other: &Self) -> bool {
13797 self.message == other.message && self.actions == other.actions
13798 }
13799}
13800
13801#[derive(Clone, Debug, PartialEq)]
13802pub enum LanguageServerLogType {
13803 Log(MessageType),
13804 Trace { verbose_info: Option<String> },
13805 Rpc { received: bool },
13806}
13807
13808impl LanguageServerLogType {
13809 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13810 match self {
13811 Self::Log(log_type) => {
13812 use proto::log_message::LogLevel;
13813 let level = match *log_type {
13814 MessageType::ERROR => LogLevel::Error,
13815 MessageType::WARNING => LogLevel::Warning,
13816 MessageType::INFO => LogLevel::Info,
13817 MessageType::LOG => LogLevel::Log,
13818 other => {
13819 log::warn!("Unknown lsp log message type: {other:?}");
13820 LogLevel::Log
13821 }
13822 };
13823 proto::language_server_log::LogType::Log(proto::LogMessage {
13824 level: level as i32,
13825 })
13826 }
13827 Self::Trace { verbose_info } => {
13828 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13829 verbose_info: verbose_info.to_owned(),
13830 })
13831 }
13832 Self::Rpc { received } => {
13833 let kind = if *received {
13834 proto::rpc_message::Kind::Received
13835 } else {
13836 proto::rpc_message::Kind::Sent
13837 };
13838 let kind = kind as i32;
13839 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13840 }
13841 }
13842 }
13843
13844 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13845 use proto::log_message::LogLevel;
13846 use proto::rpc_message;
13847 match log_type {
13848 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13849 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13850 LogLevel::Error => MessageType::ERROR,
13851 LogLevel::Warning => MessageType::WARNING,
13852 LogLevel::Info => MessageType::INFO,
13853 LogLevel::Log => MessageType::LOG,
13854 },
13855 ),
13856 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13857 verbose_info: trace_message.verbose_info,
13858 },
13859 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13860 received: match rpc_message::Kind::from_i32(message.kind)
13861 .unwrap_or(rpc_message::Kind::Received)
13862 {
13863 rpc_message::Kind::Received => true,
13864 rpc_message::Kind::Sent => false,
13865 },
13866 },
13867 }
13868 }
13869}
13870
13871pub struct WorkspaceRefreshTask {
13872 refresh_tx: mpsc::Sender<()>,
13873 progress_tx: mpsc::Sender<()>,
13874 #[allow(dead_code)]
13875 task: Task<()>,
13876}
13877
13878pub enum LanguageServerState {
13879 Starting {
13880 startup: Task<Option<Arc<LanguageServer>>>,
13881 /// List of language servers that will be added to the workspace once it's initialization completes.
13882 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13883 },
13884
13885 Running {
13886 adapter: Arc<CachedLspAdapter>,
13887 server: Arc<LanguageServer>,
13888 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13889 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13890 },
13891}
13892
13893impl LanguageServerState {
13894 fn add_workspace_folder(&self, uri: Uri) {
13895 match self {
13896 LanguageServerState::Starting {
13897 pending_workspace_folders,
13898 ..
13899 } => {
13900 pending_workspace_folders.lock().insert(uri);
13901 }
13902 LanguageServerState::Running { server, .. } => {
13903 server.add_workspace_folder(uri);
13904 }
13905 }
13906 }
13907 fn _remove_workspace_folder(&self, uri: Uri) {
13908 match self {
13909 LanguageServerState::Starting {
13910 pending_workspace_folders,
13911 ..
13912 } => {
13913 pending_workspace_folders.lock().remove(&uri);
13914 }
13915 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13916 }
13917 }
13918}
13919
13920impl std::fmt::Debug for LanguageServerState {
13921 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13922 match self {
13923 LanguageServerState::Starting { .. } => {
13924 f.debug_struct("LanguageServerState::Starting").finish()
13925 }
13926 LanguageServerState::Running { .. } => {
13927 f.debug_struct("LanguageServerState::Running").finish()
13928 }
13929 }
13930 }
13931}
13932
13933#[derive(Clone, Debug, Serialize)]
13934pub struct LanguageServerProgress {
13935 pub is_disk_based_diagnostics_progress: bool,
13936 pub is_cancellable: bool,
13937 pub title: Option<String>,
13938 pub message: Option<String>,
13939 pub percentage: Option<usize>,
13940 #[serde(skip_serializing)]
13941 pub last_update_at: Instant,
13942}
13943
13944#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13945pub struct DiagnosticSummary {
13946 pub error_count: usize,
13947 pub warning_count: usize,
13948}
13949
13950impl DiagnosticSummary {
13951 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13952 let mut this = Self {
13953 error_count: 0,
13954 warning_count: 0,
13955 };
13956
13957 for entry in diagnostics {
13958 if entry.diagnostic.is_primary {
13959 match entry.diagnostic.severity {
13960 DiagnosticSeverity::ERROR => this.error_count += 1,
13961 DiagnosticSeverity::WARNING => this.warning_count += 1,
13962 _ => {}
13963 }
13964 }
13965 }
13966
13967 this
13968 }
13969
13970 pub fn is_empty(&self) -> bool {
13971 self.error_count == 0 && self.warning_count == 0
13972 }
13973
13974 pub fn to_proto(
13975 self,
13976 language_server_id: LanguageServerId,
13977 path: &RelPath,
13978 ) -> proto::DiagnosticSummary {
13979 proto::DiagnosticSummary {
13980 path: path.to_proto(),
13981 language_server_id: language_server_id.0 as u64,
13982 error_count: self.error_count as u32,
13983 warning_count: self.warning_count as u32,
13984 }
13985 }
13986}
13987
13988#[derive(Clone, Debug)]
13989pub enum CompletionDocumentation {
13990 /// There is no documentation for this completion.
13991 Undocumented,
13992 /// A single line of documentation.
13993 SingleLine(SharedString),
13994 /// Multiple lines of plain text documentation.
13995 MultiLinePlainText(SharedString),
13996 /// Markdown documentation.
13997 MultiLineMarkdown(SharedString),
13998 /// Both single line and multiple lines of plain text documentation.
13999 SingleLineAndMultiLinePlainText {
14000 single_line: SharedString,
14001 plain_text: Option<SharedString>,
14002 },
14003}
14004
14005impl CompletionDocumentation {
14006 #[cfg(any(test, feature = "test-support"))]
14007 pub fn text(&self) -> SharedString {
14008 match self {
14009 CompletionDocumentation::Undocumented => "".into(),
14010 CompletionDocumentation::SingleLine(s) => s.clone(),
14011 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14012 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14013 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14014 single_line.clone()
14015 }
14016 }
14017 }
14018}
14019
14020impl From<lsp::Documentation> for CompletionDocumentation {
14021 fn from(docs: lsp::Documentation) -> Self {
14022 match docs {
14023 lsp::Documentation::String(text) => {
14024 if text.lines().count() <= 1 {
14025 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14026 } else {
14027 CompletionDocumentation::MultiLinePlainText(text.into())
14028 }
14029 }
14030
14031 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14032 lsp::MarkupKind::PlainText => {
14033 if value.lines().count() <= 1 {
14034 CompletionDocumentation::SingleLine(value.into())
14035 } else {
14036 CompletionDocumentation::MultiLinePlainText(value.into())
14037 }
14038 }
14039
14040 lsp::MarkupKind::Markdown => {
14041 CompletionDocumentation::MultiLineMarkdown(value.into())
14042 }
14043 },
14044 }
14045 }
14046}
14047
14048pub enum ResolvedHint {
14049 Resolved(InlayHint),
14050 Resolving(Shared<Task<()>>),
14051}
14052
14053pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14054 glob.components()
14055 .take_while(|component| match component {
14056 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14057 _ => true,
14058 })
14059 .collect()
14060}
14061
14062pub struct SshLspAdapter {
14063 name: LanguageServerName,
14064 binary: LanguageServerBinary,
14065 initialization_options: Option<String>,
14066 code_action_kinds: Option<Vec<CodeActionKind>>,
14067}
14068
14069impl SshLspAdapter {
14070 pub fn new(
14071 name: LanguageServerName,
14072 binary: LanguageServerBinary,
14073 initialization_options: Option<String>,
14074 code_action_kinds: Option<String>,
14075 ) -> Self {
14076 Self {
14077 name,
14078 binary,
14079 initialization_options,
14080 code_action_kinds: code_action_kinds
14081 .as_ref()
14082 .and_then(|c| serde_json::from_str(c).ok()),
14083 }
14084 }
14085}
14086
14087impl LspInstaller for SshLspAdapter {
14088 type BinaryVersion = ();
14089 async fn check_if_user_installed(
14090 &self,
14091 _: &dyn LspAdapterDelegate,
14092 _: Option<Toolchain>,
14093 _: &AsyncApp,
14094 ) -> Option<LanguageServerBinary> {
14095 Some(self.binary.clone())
14096 }
14097
14098 async fn cached_server_binary(
14099 &self,
14100 _: PathBuf,
14101 _: &dyn LspAdapterDelegate,
14102 ) -> Option<LanguageServerBinary> {
14103 None
14104 }
14105
14106 async fn fetch_latest_server_version(
14107 &self,
14108 _: &dyn LspAdapterDelegate,
14109 _: bool,
14110 _: &mut AsyncApp,
14111 ) -> Result<()> {
14112 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14113 }
14114
14115 async fn fetch_server_binary(
14116 &self,
14117 _: (),
14118 _: PathBuf,
14119 _: &dyn LspAdapterDelegate,
14120 ) -> Result<LanguageServerBinary> {
14121 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14122 }
14123}
14124
14125#[async_trait(?Send)]
14126impl LspAdapter for SshLspAdapter {
14127 fn name(&self) -> LanguageServerName {
14128 self.name.clone()
14129 }
14130
14131 async fn initialization_options(
14132 self: Arc<Self>,
14133 _: &Arc<dyn LspAdapterDelegate>,
14134 _: &mut AsyncApp,
14135 ) -> Result<Option<serde_json::Value>> {
14136 let Some(options) = &self.initialization_options else {
14137 return Ok(None);
14138 };
14139 let result = serde_json::from_str(options)?;
14140 Ok(result)
14141 }
14142
14143 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14144 self.code_action_kinds.clone()
14145 }
14146}
14147
14148pub fn language_server_settings<'a>(
14149 delegate: &'a dyn LspAdapterDelegate,
14150 language: &LanguageServerName,
14151 cx: &'a App,
14152) -> Option<&'a LspSettings> {
14153 language_server_settings_for(
14154 SettingsLocation {
14155 worktree_id: delegate.worktree_id(),
14156 path: RelPath::empty(),
14157 },
14158 language,
14159 cx,
14160 )
14161}
14162
14163pub fn language_server_settings_for<'a>(
14164 location: SettingsLocation<'a>,
14165 language: &LanguageServerName,
14166 cx: &'a App,
14167) -> Option<&'a LspSettings> {
14168 ProjectSettings::get(Some(location), cx).lsp.get(language)
14169}
14170
14171pub struct LocalLspAdapterDelegate {
14172 lsp_store: WeakEntity<LspStore>,
14173 worktree: worktree::Snapshot,
14174 fs: Arc<dyn Fs>,
14175 http_client: Arc<dyn HttpClient>,
14176 language_registry: Arc<LanguageRegistry>,
14177 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14178}
14179
14180impl LocalLspAdapterDelegate {
14181 pub fn new(
14182 language_registry: Arc<LanguageRegistry>,
14183 environment: &Entity<ProjectEnvironment>,
14184 lsp_store: WeakEntity<LspStore>,
14185 worktree: &Entity<Worktree>,
14186 http_client: Arc<dyn HttpClient>,
14187 fs: Arc<dyn Fs>,
14188 cx: &mut App,
14189 ) -> Arc<Self> {
14190 let load_shell_env_task =
14191 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14192
14193 Arc::new(Self {
14194 lsp_store,
14195 worktree: worktree.read(cx).snapshot(),
14196 fs,
14197 http_client,
14198 language_registry,
14199 load_shell_env_task,
14200 })
14201 }
14202
14203 pub fn from_local_lsp(
14204 local: &LocalLspStore,
14205 worktree: &Entity<Worktree>,
14206 cx: &mut App,
14207 ) -> Arc<Self> {
14208 Self::new(
14209 local.languages.clone(),
14210 &local.environment,
14211 local.weak.clone(),
14212 worktree,
14213 local.http_client.clone(),
14214 local.fs.clone(),
14215 cx,
14216 )
14217 }
14218}
14219
14220#[async_trait]
14221impl LspAdapterDelegate for LocalLspAdapterDelegate {
14222 fn show_notification(&self, message: &str, cx: &mut App) {
14223 self.lsp_store
14224 .update(cx, |_, cx| {
14225 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14226 })
14227 .ok();
14228 }
14229
14230 fn http_client(&self) -> Arc<dyn HttpClient> {
14231 self.http_client.clone()
14232 }
14233
14234 fn worktree_id(&self) -> WorktreeId {
14235 self.worktree.id()
14236 }
14237
14238 fn worktree_root_path(&self) -> &Path {
14239 self.worktree.abs_path().as_ref()
14240 }
14241
14242 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14243 self.worktree.resolve_relative_path(path)
14244 }
14245
14246 async fn shell_env(&self) -> HashMap<String, String> {
14247 let task = self.load_shell_env_task.clone();
14248 task.await.unwrap_or_default()
14249 }
14250
14251 async fn npm_package_installed_version(
14252 &self,
14253 package_name: &str,
14254 ) -> Result<Option<(PathBuf, Version)>> {
14255 let local_package_directory = self.worktree_root_path();
14256 let node_modules_directory = local_package_directory.join("node_modules");
14257
14258 if let Some(version) =
14259 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14260 {
14261 return Ok(Some((node_modules_directory, version)));
14262 }
14263 let Some(npm) = self.which("npm".as_ref()).await else {
14264 log::warn!(
14265 "Failed to find npm executable for {:?}",
14266 local_package_directory
14267 );
14268 return Ok(None);
14269 };
14270
14271 let env = self.shell_env().await;
14272 let output = util::command::new_command(&npm)
14273 .args(["root", "-g"])
14274 .envs(env)
14275 .current_dir(local_package_directory)
14276 .output()
14277 .await?;
14278 let global_node_modules =
14279 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14280
14281 if let Some(version) =
14282 read_package_installed_version(global_node_modules.clone(), package_name).await?
14283 {
14284 return Ok(Some((global_node_modules, version)));
14285 }
14286 return Ok(None);
14287 }
14288
14289 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14290 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14291 if self.fs.is_file(&worktree_abs_path).await {
14292 worktree_abs_path.pop();
14293 }
14294
14295 let env = self.shell_env().await;
14296
14297 let shell_path = env.get("PATH").cloned();
14298
14299 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14300 }
14301
14302 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14303 let mut working_dir = self.worktree_root_path().to_path_buf();
14304 if self.fs.is_file(&working_dir).await {
14305 working_dir.pop();
14306 }
14307 let output = util::command::new_command(&command.path)
14308 .args(command.arguments)
14309 .envs(command.env.clone().unwrap_or_default())
14310 .current_dir(working_dir)
14311 .output()
14312 .await?;
14313
14314 anyhow::ensure!(
14315 output.status.success(),
14316 "{}, stdout: {:?}, stderr: {:?}",
14317 output.status,
14318 String::from_utf8_lossy(&output.stdout),
14319 String::from_utf8_lossy(&output.stderr)
14320 );
14321 Ok(())
14322 }
14323
14324 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14325 self.language_registry
14326 .update_lsp_binary_status(server_name, status);
14327 }
14328
14329 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14330 self.language_registry
14331 .all_lsp_adapters()
14332 .into_iter()
14333 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14334 .collect()
14335 }
14336
14337 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14338 let dir = self.language_registry.language_server_download_dir(name)?;
14339
14340 if !dir.exists() {
14341 smol::fs::create_dir_all(&dir)
14342 .await
14343 .context("failed to create container directory")
14344 .log_err()?;
14345 }
14346
14347 Some(dir)
14348 }
14349
14350 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14351 let entry = self
14352 .worktree
14353 .entry_for_path(path)
14354 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14355 let abs_path = self.worktree.absolutize(&entry.path);
14356 self.fs.load(&abs_path).await
14357 }
14358}
14359
14360async fn populate_labels_for_symbols(
14361 symbols: Vec<CoreSymbol>,
14362 language_registry: &Arc<LanguageRegistry>,
14363 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14364 output: &mut Vec<Symbol>,
14365) {
14366 #[allow(clippy::mutable_key_type)]
14367 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14368
14369 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14370 for symbol in symbols {
14371 let Some(file_name) = symbol.path.file_name() else {
14372 continue;
14373 };
14374 let language = language_registry
14375 .load_language_for_file_path(Path::new(file_name))
14376 .await
14377 .ok()
14378 .or_else(|| {
14379 unknown_paths.insert(file_name.into());
14380 None
14381 });
14382 symbols_by_language
14383 .entry(language)
14384 .or_default()
14385 .push(symbol);
14386 }
14387
14388 for unknown_path in unknown_paths {
14389 log::info!("no language found for symbol in file {unknown_path:?}");
14390 }
14391
14392 let mut label_params = Vec::new();
14393 for (language, mut symbols) in symbols_by_language {
14394 label_params.clear();
14395 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14396 name: mem::take(&mut symbol.name),
14397 kind: symbol.kind,
14398 container_name: symbol.container_name.take(),
14399 }));
14400
14401 let mut labels = Vec::new();
14402 if let Some(language) = language {
14403 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14404 language_registry
14405 .lsp_adapters(&language.name())
14406 .first()
14407 .cloned()
14408 });
14409 if let Some(lsp_adapter) = lsp_adapter {
14410 labels = lsp_adapter
14411 .labels_for_symbols(&label_params, &language)
14412 .await
14413 .log_err()
14414 .unwrap_or_default();
14415 }
14416 }
14417
14418 for (
14419 (
14420 symbol,
14421 language::Symbol {
14422 name,
14423 container_name,
14424 ..
14425 },
14426 ),
14427 label,
14428 ) in symbols
14429 .into_iter()
14430 .zip(label_params.drain(..))
14431 .zip(labels.into_iter().chain(iter::repeat(None)))
14432 {
14433 output.push(Symbol {
14434 language_server_name: symbol.language_server_name,
14435 source_worktree_id: symbol.source_worktree_id,
14436 source_language_server_id: symbol.source_language_server_id,
14437 path: symbol.path,
14438 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14439 name,
14440 kind: symbol.kind,
14441 range: symbol.range,
14442 container_name,
14443 });
14444 }
14445 }
14446}
14447
14448pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14449 text.lines()
14450 .map(|line| line.trim())
14451 .filter(|line| !line.is_empty())
14452 .join(separator)
14453}
14454
14455fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14456 match server.capabilities().text_document_sync.as_ref()? {
14457 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14458 // Server wants didSave but didn't specify includeText.
14459 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14460 // Server doesn't want didSave at all.
14461 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14462 // Server provided SaveOptions.
14463 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14464 Some(save_options.include_text.unwrap_or(false))
14465 }
14466 },
14467 // We do not have any save info. Kind affects didChange only.
14468 lsp::TextDocumentSyncCapability::Kind(_) => None,
14469 }
14470}
14471
14472/// Completion items are displayed in a `UniformList`.
14473/// Usually, those items are single-line strings, but in LSP responses,
14474/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14475/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14476/// 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,
14477/// breaking the completions menu presentation.
14478///
14479/// 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.
14480pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14481 let mut new_text = String::with_capacity(label.text.len());
14482 let mut offset_map = vec![0; label.text.len() + 1];
14483 let mut last_char_was_space = false;
14484 let mut new_idx = 0;
14485 let chars = label.text.char_indices().fuse();
14486 let mut newlines_removed = false;
14487
14488 for (idx, c) in chars {
14489 offset_map[idx] = new_idx;
14490
14491 match c {
14492 '\n' if last_char_was_space => {
14493 newlines_removed = true;
14494 }
14495 '\t' | ' ' if last_char_was_space => {}
14496 '\n' if !last_char_was_space => {
14497 new_text.push(' ');
14498 new_idx += 1;
14499 last_char_was_space = true;
14500 newlines_removed = true;
14501 }
14502 ' ' | '\t' => {
14503 new_text.push(' ');
14504 new_idx += 1;
14505 last_char_was_space = true;
14506 }
14507 _ => {
14508 new_text.push(c);
14509 new_idx += c.len_utf8();
14510 last_char_was_space = false;
14511 }
14512 }
14513 }
14514 offset_map[label.text.len()] = new_idx;
14515
14516 // Only modify the label if newlines were removed.
14517 if !newlines_removed {
14518 return;
14519 }
14520
14521 let last_index = new_idx;
14522 let mut run_ranges_errors = Vec::new();
14523 label.runs.retain_mut(|(range, _)| {
14524 match offset_map.get(range.start) {
14525 Some(&start) => range.start = start,
14526 None => {
14527 run_ranges_errors.push(range.clone());
14528 return false;
14529 }
14530 }
14531
14532 match offset_map.get(range.end) {
14533 Some(&end) => range.end = end,
14534 None => {
14535 run_ranges_errors.push(range.clone());
14536 range.end = last_index;
14537 }
14538 }
14539 true
14540 });
14541 if !run_ranges_errors.is_empty() {
14542 log::error!(
14543 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14544 label.text
14545 );
14546 }
14547
14548 let mut wrong_filter_range = None;
14549 if label.filter_range == (0..label.text.len()) {
14550 label.filter_range = 0..new_text.len();
14551 } else {
14552 let mut original_filter_range = Some(label.filter_range.clone());
14553 match offset_map.get(label.filter_range.start) {
14554 Some(&start) => label.filter_range.start = start,
14555 None => {
14556 wrong_filter_range = original_filter_range.take();
14557 label.filter_range.start = last_index;
14558 }
14559 }
14560
14561 match offset_map.get(label.filter_range.end) {
14562 Some(&end) => label.filter_range.end = end,
14563 None => {
14564 wrong_filter_range = original_filter_range.take();
14565 label.filter_range.end = last_index;
14566 }
14567 }
14568 }
14569 if let Some(wrong_filter_range) = wrong_filter_range {
14570 log::error!(
14571 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14572 label.text
14573 );
14574 }
14575
14576 label.text = new_text;
14577}
14578
14579/// Apply edits to the buffer that will become part of the formatting transaction.
14580/// Fails if the buffer has been edited since the start of that transaction.
14581fn extend_formatting_transaction(
14582 buffer: &FormattableBuffer,
14583 formatting_transaction_id: text::TransactionId,
14584 cx: &mut AsyncApp,
14585 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14586) -> anyhow::Result<()> {
14587 buffer.handle.update(cx, |buffer, cx| {
14588 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14589 if last_transaction_id != Some(formatting_transaction_id) {
14590 anyhow::bail!("Buffer edited while formatting. Aborting")
14591 }
14592 buffer.start_transaction();
14593 operation(buffer, cx);
14594 if let Some(transaction_id) = buffer.end_transaction(cx) {
14595 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14596 }
14597 Ok(())
14598 })
14599}