1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, ModelineSettings, Patch, PointUtf16, TextBufferSnapshot,
77 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 {
826 let buffer = params
827 .uri
828 .to_file_path()
829 .map(|file_path| this.get_buffer(&file_path, cx))
830 .ok()
831 .flatten();
832 adapter.process_diagnostics(&mut params, server_id, buffer);
833 }
834
835 this.merge_lsp_diagnostics(
836 DiagnosticSourceKind::Pushed,
837 vec![DocumentDiagnosticsUpdate {
838 server_id,
839 diagnostics: params,
840 result_id: None,
841 disk_based_sources: Cow::Borrowed(
842 &adapter.disk_based_diagnostic_sources,
843 ),
844 registration_id: None,
845 }],
846 |_, diagnostic, cx| match diagnostic.source_kind {
847 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
848 adapter.retain_old_diagnostic(diagnostic, cx)
849 }
850 DiagnosticSourceKind::Pulled => true,
851 },
852 cx,
853 )
854 .log_err();
855 });
856 }
857 }
858 })
859 .detach();
860 language_server
861 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
862 let adapter = adapter.adapter.clone();
863 let delegate = delegate.clone();
864 let this = lsp_store.clone();
865 move |params, cx| {
866 let adapter = adapter.clone();
867 let delegate = delegate.clone();
868 let this = this.clone();
869 let mut cx = cx.clone();
870 async move {
871 let toolchain_for_id = this
872 .update(&mut cx, |this, _| {
873 this.as_local()?.language_server_ids.iter().find_map(
874 |(seed, value)| {
875 (value.id == server_id).then(|| seed.toolchain.clone())
876 },
877 )
878 })?
879 .context("Expected the LSP store to be in a local mode")?;
880
881 let mut scope_uri_to_workspace_config = BTreeMap::new();
882 for item in ¶ms.items {
883 let scope_uri = item.scope_uri.clone();
884 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
885 scope_uri_to_workspace_config.entry(scope_uri.clone())
886 else {
887 // We've already queried workspace configuration of this URI.
888 continue;
889 };
890 let workspace_config = Self::workspace_configuration_for_adapter(
891 adapter.clone(),
892 &delegate,
893 toolchain_for_id.clone(),
894 scope_uri,
895 &mut cx,
896 )
897 .await?;
898 new_scope_uri.insert(workspace_config);
899 }
900
901 Ok(params
902 .items
903 .into_iter()
904 .filter_map(|item| {
905 let workspace_config =
906 scope_uri_to_workspace_config.get(&item.scope_uri)?;
907 if let Some(section) = &item.section {
908 Some(
909 workspace_config
910 .get(section)
911 .cloned()
912 .unwrap_or(serde_json::Value::Null),
913 )
914 } else {
915 Some(workspace_config.clone())
916 }
917 })
918 .collect())
919 }
920 }
921 })
922 .detach();
923
924 language_server
925 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
926 let this = lsp_store.clone();
927 move |_, cx| {
928 let this = this.clone();
929 let cx = cx.clone();
930 async move {
931 let Some(server) =
932 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
933 else {
934 return Ok(None);
935 };
936 let root = server.workspace_folders();
937 Ok(Some(
938 root.into_iter()
939 .map(|uri| WorkspaceFolder {
940 uri,
941 name: Default::default(),
942 })
943 .collect(),
944 ))
945 }
946 }
947 })
948 .detach();
949 // Even though we don't have handling for these requests, respond to them to
950 // avoid stalling any language server like `gopls` which waits for a response
951 // to these requests when initializing.
952 language_server
953 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
954 let this = lsp_store.clone();
955 move |params, cx| {
956 let this = this.clone();
957 let mut cx = cx.clone();
958 async move {
959 this.update(&mut cx, |this, _| {
960 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
961 {
962 status
963 .progress_tokens
964 .insert(ProgressToken::from_lsp(params.token));
965 }
966 })?;
967
968 Ok(())
969 }
970 }
971 })
972 .detach();
973
974 language_server
975 .on_request::<lsp::request::RegisterCapability, _, _>({
976 let lsp_store = lsp_store.clone();
977 move |params, cx| {
978 let lsp_store = lsp_store.clone();
979 let mut cx = cx.clone();
980 async move {
981 lsp_store
982 .update(&mut cx, |lsp_store, cx| {
983 if lsp_store.as_local().is_some() {
984 match lsp_store
985 .register_server_capabilities(server_id, params, cx)
986 {
987 Ok(()) => {}
988 Err(e) => {
989 log::error!(
990 "Failed to register server capabilities: {e:#}"
991 );
992 }
993 };
994 }
995 })
996 .ok();
997 Ok(())
998 }
999 }
1000 })
1001 .detach();
1002
1003 language_server
1004 .on_request::<lsp::request::UnregisterCapability, _, _>({
1005 let lsp_store = lsp_store.clone();
1006 move |params, cx| {
1007 let lsp_store = lsp_store.clone();
1008 let mut cx = cx.clone();
1009 async move {
1010 lsp_store
1011 .update(&mut cx, |lsp_store, cx| {
1012 if lsp_store.as_local().is_some() {
1013 match lsp_store
1014 .unregister_server_capabilities(server_id, params, cx)
1015 {
1016 Ok(()) => {}
1017 Err(e) => {
1018 log::error!(
1019 "Failed to unregister server capabilities: {e:#}"
1020 );
1021 }
1022 }
1023 }
1024 })
1025 .ok();
1026 Ok(())
1027 }
1028 }
1029 })
1030 .detach();
1031
1032 language_server
1033 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1034 let this = lsp_store.clone();
1035 move |params, cx| {
1036 let mut cx = cx.clone();
1037 let this = this.clone();
1038 async move {
1039 LocalLspStore::on_lsp_workspace_edit(
1040 this.clone(),
1041 params,
1042 server_id,
1043 &mut cx,
1044 )
1045 .await
1046 }
1047 }
1048 })
1049 .detach();
1050
1051 language_server
1052 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1053 let lsp_store = lsp_store.clone();
1054 let request_id = Arc::new(AtomicUsize::new(0));
1055 move |(), cx| {
1056 let lsp_store = lsp_store.clone();
1057 let request_id = request_id.clone();
1058 let mut cx = cx.clone();
1059 async move {
1060 lsp_store
1061 .update(&mut cx, |lsp_store, cx| {
1062 let request_id =
1063 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1064 cx.emit(LspStoreEvent::RefreshInlayHints {
1065 server_id,
1066 request_id,
1067 });
1068 lsp_store
1069 .downstream_client
1070 .as_ref()
1071 .map(|(client, project_id)| {
1072 client.send(proto::RefreshInlayHints {
1073 project_id: *project_id,
1074 server_id: server_id.to_proto(),
1075 request_id: request_id.map(|id| id as u64),
1076 })
1077 })
1078 })?
1079 .transpose()?;
1080 Ok(())
1081 }
1082 }
1083 })
1084 .detach();
1085
1086 language_server
1087 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1088 let this = lsp_store.clone();
1089 move |(), cx| {
1090 let this = this.clone();
1091 let mut cx = cx.clone();
1092 async move {
1093 this.update(&mut cx, |this, cx| {
1094 cx.emit(LspStoreEvent::RefreshCodeLens);
1095 this.downstream_client.as_ref().map(|(client, project_id)| {
1096 client.send(proto::RefreshCodeLens {
1097 project_id: *project_id,
1098 })
1099 })
1100 })?
1101 .transpose()?;
1102 Ok(())
1103 }
1104 }
1105 })
1106 .detach();
1107
1108 language_server
1109 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1110 let lsp_store = lsp_store.clone();
1111 let request_id = Arc::new(AtomicUsize::new(0));
1112 move |(), cx| {
1113 let lsp_store = lsp_store.clone();
1114 let request_id = request_id.clone();
1115 let mut cx = cx.clone();
1116 async move {
1117 lsp_store
1118 .update(&mut cx, |lsp_store, cx| {
1119 let request_id =
1120 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1121 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1122 server_id,
1123 request_id,
1124 });
1125 lsp_store
1126 .downstream_client
1127 .as_ref()
1128 .map(|(client, project_id)| {
1129 client.send(proto::RefreshSemanticTokens {
1130 project_id: *project_id,
1131 server_id: server_id.to_proto(),
1132 request_id: request_id.map(|id| id as u64),
1133 })
1134 })
1135 })?
1136 .transpose()?;
1137 Ok(())
1138 }
1139 }
1140 })
1141 .detach();
1142
1143 language_server
1144 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1145 let this = lsp_store.clone();
1146 move |(), cx| {
1147 let this = this.clone();
1148 let mut cx = cx.clone();
1149 async move {
1150 this.update(&mut cx, |lsp_store, cx| {
1151 lsp_store.pull_workspace_diagnostics(server_id);
1152 lsp_store
1153 .downstream_client
1154 .as_ref()
1155 .map(|(client, project_id)| {
1156 client.send(proto::PullWorkspaceDiagnostics {
1157 project_id: *project_id,
1158 server_id: server_id.to_proto(),
1159 })
1160 })
1161 .transpose()?;
1162 anyhow::Ok(
1163 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1164 )
1165 })??
1166 .await;
1167 Ok(())
1168 }
1169 }
1170 })
1171 .detach();
1172
1173 language_server
1174 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1175 let this = lsp_store.clone();
1176 let name = name.to_string();
1177 let adapter = adapter.clone();
1178 move |params, cx| {
1179 let this = this.clone();
1180 let name = name.to_string();
1181 let adapter = adapter.clone();
1182 let mut cx = cx.clone();
1183 async move {
1184 let actions = params.actions.unwrap_or_default();
1185 let message = params.message.clone();
1186 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1187 let level = match params.typ {
1188 lsp::MessageType::ERROR => PromptLevel::Critical,
1189 lsp::MessageType::WARNING => PromptLevel::Warning,
1190 _ => PromptLevel::Info,
1191 };
1192 let request = LanguageServerPromptRequest::new(
1193 level,
1194 params.message,
1195 actions,
1196 name.clone(),
1197 tx,
1198 );
1199
1200 let did_update = this
1201 .update(&mut cx, |_, cx| {
1202 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1203 })
1204 .is_ok();
1205 if did_update {
1206 let response = rx.recv().await.ok();
1207 if let Some(ref selected_action) = response {
1208 let context = language::PromptResponseContext {
1209 message,
1210 selected_action: selected_action.clone(),
1211 };
1212 adapter.process_prompt_response(&context, &mut cx)
1213 }
1214
1215 Ok(response)
1216 } else {
1217 Ok(None)
1218 }
1219 }
1220 }
1221 })
1222 .detach();
1223 language_server
1224 .on_notification::<lsp::notification::ShowMessage, _>({
1225 let this = lsp_store.clone();
1226 let name = name.to_string();
1227 move |params, cx| {
1228 let this = this.clone();
1229 let name = name.to_string();
1230 let mut cx = cx.clone();
1231
1232 let (tx, _) = smol::channel::bounded(1);
1233 let level = match params.typ {
1234 lsp::MessageType::ERROR => PromptLevel::Critical,
1235 lsp::MessageType::WARNING => PromptLevel::Warning,
1236 _ => PromptLevel::Info,
1237 };
1238 let request =
1239 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1240
1241 let _ = this.update(&mut cx, |_, cx| {
1242 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1243 });
1244 }
1245 })
1246 .detach();
1247
1248 let disk_based_diagnostics_progress_token =
1249 adapter.disk_based_diagnostics_progress_token.clone();
1250
1251 language_server
1252 .on_notification::<lsp::notification::Progress, _>({
1253 let this = lsp_store.clone();
1254 move |params, cx| {
1255 if let Some(this) = this.upgrade() {
1256 this.update(cx, |this, cx| {
1257 this.on_lsp_progress(
1258 params,
1259 server_id,
1260 disk_based_diagnostics_progress_token.clone(),
1261 cx,
1262 );
1263 });
1264 }
1265 }
1266 })
1267 .detach();
1268
1269 language_server
1270 .on_notification::<lsp::notification::LogMessage, _>({
1271 let this = lsp_store.clone();
1272 move |params, cx| {
1273 if let Some(this) = this.upgrade() {
1274 this.update(cx, |_, cx| {
1275 cx.emit(LspStoreEvent::LanguageServerLog(
1276 server_id,
1277 LanguageServerLogType::Log(params.typ),
1278 params.message,
1279 ));
1280 });
1281 }
1282 }
1283 })
1284 .detach();
1285
1286 language_server
1287 .on_notification::<lsp::notification::LogTrace, _>({
1288 let this = lsp_store.clone();
1289 move |params, cx| {
1290 let mut cx = cx.clone();
1291 if let Some(this) = this.upgrade() {
1292 this.update(&mut cx, |_, cx| {
1293 cx.emit(LspStoreEvent::LanguageServerLog(
1294 server_id,
1295 LanguageServerLogType::Trace {
1296 verbose_info: params.verbose,
1297 },
1298 params.message,
1299 ));
1300 });
1301 }
1302 }
1303 })
1304 .detach();
1305
1306 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1307 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1309 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1310 }
1311
1312 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1313 let shutdown_futures = self
1314 .language_servers
1315 .drain()
1316 .map(|(_, server_state)| Self::shutdown_server(server_state))
1317 .collect::<Vec<_>>();
1318
1319 async move {
1320 join_all(shutdown_futures).await;
1321 }
1322 }
1323
1324 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1325 match server_state {
1326 LanguageServerState::Running { server, .. } => {
1327 if let Some(shutdown) = server.shutdown() {
1328 shutdown.await;
1329 }
1330 }
1331 LanguageServerState::Starting { startup, .. } => {
1332 if let Some(server) = startup.await
1333 && let Some(shutdown) = server.shutdown()
1334 {
1335 shutdown.await;
1336 }
1337 }
1338 }
1339 Ok(())
1340 }
1341
1342 fn language_servers_for_worktree(
1343 &self,
1344 worktree_id: WorktreeId,
1345 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1346 self.language_server_ids
1347 .iter()
1348 .filter_map(move |(seed, state)| {
1349 if seed.worktree_id != worktree_id {
1350 return None;
1351 }
1352
1353 if let Some(LanguageServerState::Running { server, .. }) =
1354 self.language_servers.get(&state.id)
1355 {
1356 Some(server)
1357 } else {
1358 None
1359 }
1360 })
1361 }
1362
1363 fn language_server_ids_for_project_path(
1364 &self,
1365 project_path: ProjectPath,
1366 language: &Language,
1367 cx: &mut App,
1368 ) -> Vec<LanguageServerId> {
1369 let Some(worktree) = self
1370 .worktree_store
1371 .read(cx)
1372 .worktree_for_id(project_path.worktree_id, cx)
1373 else {
1374 return Vec::new();
1375 };
1376 let delegate: Arc<dyn ManifestDelegate> =
1377 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1378
1379 self.lsp_tree
1380 .get(
1381 project_path,
1382 language.name(),
1383 language.manifest(),
1384 &delegate,
1385 cx,
1386 )
1387 .collect::<Vec<_>>()
1388 }
1389
1390 fn language_server_ids_for_buffer(
1391 &self,
1392 buffer: &Buffer,
1393 cx: &mut App,
1394 ) -> Vec<LanguageServerId> {
1395 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1396 let worktree_id = file.worktree_id(cx);
1397
1398 let path: Arc<RelPath> = file
1399 .path()
1400 .parent()
1401 .map(Arc::from)
1402 .unwrap_or_else(|| file.path().clone());
1403 let worktree_path = ProjectPath { worktree_id, path };
1404 self.language_server_ids_for_project_path(worktree_path, language, cx)
1405 } else {
1406 Vec::new()
1407 }
1408 }
1409
1410 fn language_servers_for_buffer<'a>(
1411 &'a self,
1412 buffer: &'a Buffer,
1413 cx: &'a mut App,
1414 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1415 self.language_server_ids_for_buffer(buffer, cx)
1416 .into_iter()
1417 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1418 LanguageServerState::Running {
1419 adapter, server, ..
1420 } => Some((adapter, server)),
1421 _ => None,
1422 })
1423 }
1424
1425 async fn execute_code_action_kind_locally(
1426 lsp_store: WeakEntity<LspStore>,
1427 mut buffers: Vec<Entity<Buffer>>,
1428 kind: CodeActionKind,
1429 push_to_history: bool,
1430 cx: &mut AsyncApp,
1431 ) -> anyhow::Result<ProjectTransaction> {
1432 // Do not allow multiple concurrent code actions requests for the
1433 // same buffer.
1434 lsp_store.update(cx, |this, cx| {
1435 let this = this.as_local_mut().unwrap();
1436 buffers.retain(|buffer| {
1437 this.buffers_being_formatted
1438 .insert(buffer.read(cx).remote_id())
1439 });
1440 })?;
1441 let _cleanup = defer({
1442 let this = lsp_store.clone();
1443 let mut cx = cx.clone();
1444 let buffers = &buffers;
1445 move || {
1446 this.update(&mut cx, |this, cx| {
1447 let this = this.as_local_mut().unwrap();
1448 for buffer in buffers {
1449 this.buffers_being_formatted
1450 .remove(&buffer.read(cx).remote_id());
1451 }
1452 })
1453 .ok();
1454 }
1455 });
1456 let mut project_transaction = ProjectTransaction::default();
1457
1458 for buffer in &buffers {
1459 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1460 buffer.update(cx, |buffer, cx| {
1461 lsp_store
1462 .as_local()
1463 .unwrap()
1464 .language_servers_for_buffer(buffer, cx)
1465 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1466 .collect::<Vec<_>>()
1467 })
1468 })?;
1469 for (_, language_server) in adapters_and_servers.iter() {
1470 let actions = Self::get_server_code_actions_from_action_kinds(
1471 &lsp_store,
1472 language_server.server_id(),
1473 vec![kind.clone()],
1474 buffer,
1475 cx,
1476 )
1477 .await?;
1478 Self::execute_code_actions_on_server(
1479 &lsp_store,
1480 language_server,
1481 actions,
1482 push_to_history,
1483 &mut project_transaction,
1484 cx,
1485 )
1486 .await?;
1487 }
1488 }
1489 Ok(project_transaction)
1490 }
1491
1492 async fn format_locally(
1493 lsp_store: WeakEntity<LspStore>,
1494 mut buffers: Vec<FormattableBuffer>,
1495 push_to_history: bool,
1496 trigger: FormatTrigger,
1497 logger: zlog::Logger,
1498 cx: &mut AsyncApp,
1499 ) -> anyhow::Result<ProjectTransaction> {
1500 // Do not allow multiple concurrent formatting requests for the
1501 // same buffer.
1502 lsp_store.update(cx, |this, cx| {
1503 let this = this.as_local_mut().unwrap();
1504 buffers.retain(|buffer| {
1505 this.buffers_being_formatted
1506 .insert(buffer.handle.read(cx).remote_id())
1507 });
1508 })?;
1509
1510 let _cleanup = defer({
1511 let this = lsp_store.clone();
1512 let mut cx = cx.clone();
1513 let buffers = &buffers;
1514 move || {
1515 this.update(&mut cx, |this, cx| {
1516 let this = this.as_local_mut().unwrap();
1517 for buffer in buffers {
1518 this.buffers_being_formatted
1519 .remove(&buffer.handle.read(cx).remote_id());
1520 }
1521 })
1522 .ok();
1523 }
1524 });
1525
1526 let mut project_transaction = ProjectTransaction::default();
1527
1528 for buffer in &buffers {
1529 zlog::debug!(
1530 logger =>
1531 "formatting buffer '{:?}'",
1532 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1533 );
1534 // Create an empty transaction to hold all of the formatting edits.
1535 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1536 // ensure no transactions created while formatting are
1537 // grouped with the previous transaction in the history
1538 // based on the transaction group interval
1539 buffer.finalize_last_transaction();
1540 buffer
1541 .start_transaction()
1542 .context("transaction already open")?;
1543 buffer.end_transaction(cx);
1544 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1545 buffer.finalize_last_transaction();
1546 anyhow::Ok(transaction_id)
1547 })?;
1548
1549 let result = Self::format_buffer_locally(
1550 lsp_store.clone(),
1551 buffer,
1552 formatting_transaction_id,
1553 trigger,
1554 logger,
1555 cx,
1556 )
1557 .await;
1558
1559 buffer.handle.update(cx, |buffer, cx| {
1560 let Some(formatting_transaction) =
1561 buffer.get_transaction(formatting_transaction_id).cloned()
1562 else {
1563 zlog::warn!(logger => "no formatting transaction");
1564 return;
1565 };
1566 if formatting_transaction.edit_ids.is_empty() {
1567 zlog::debug!(logger => "no changes made while formatting");
1568 buffer.forget_transaction(formatting_transaction_id);
1569 return;
1570 }
1571 if !push_to_history {
1572 zlog::trace!(logger => "forgetting format transaction");
1573 buffer.forget_transaction(formatting_transaction.id);
1574 }
1575 project_transaction
1576 .0
1577 .insert(cx.entity(), formatting_transaction);
1578 });
1579
1580 result?;
1581 }
1582
1583 Ok(project_transaction)
1584 }
1585
1586 async fn format_buffer_locally(
1587 lsp_store: WeakEntity<LspStore>,
1588 buffer: &FormattableBuffer,
1589 formatting_transaction_id: clock::Lamport,
1590 trigger: FormatTrigger,
1591 logger: zlog::Logger,
1592 cx: &mut AsyncApp,
1593 ) -> Result<()> {
1594 let (adapters_and_servers, settings, request_timeout) =
1595 lsp_store.update(cx, |lsp_store, cx| {
1596 buffer.handle.update(cx, |buffer, cx| {
1597 let adapters_and_servers = lsp_store
1598 .as_local()
1599 .unwrap()
1600 .language_servers_for_buffer(buffer, cx)
1601 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1602 .collect::<Vec<_>>();
1603 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1604 let request_timeout = ProjectSettings::get_global(cx)
1605 .global_lsp_settings
1606 .get_request_timeout();
1607 (adapters_and_servers, settings, request_timeout)
1608 })
1609 })?;
1610
1611 // handle whitespace formatting
1612 if settings.remove_trailing_whitespace_on_save {
1613 zlog::trace!(logger => "removing trailing whitespace");
1614 let diff = buffer
1615 .handle
1616 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1617 .await;
1618 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1619 buffer.apply_diff(diff, cx);
1620 })?;
1621 }
1622
1623 if settings.ensure_final_newline_on_save {
1624 zlog::trace!(logger => "ensuring final newline");
1625 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1626 buffer.ensure_final_newline(cx);
1627 })?;
1628 }
1629
1630 // Formatter for `code_actions_on_format` that runs before
1631 // the rest of the formatters
1632 let mut code_actions_on_format_formatters = None;
1633 let should_run_code_actions_on_format = !matches!(
1634 (trigger, &settings.format_on_save),
1635 (FormatTrigger::Save, &FormatOnSave::Off)
1636 );
1637 if should_run_code_actions_on_format {
1638 let have_code_actions_to_run_on_format = settings
1639 .code_actions_on_format
1640 .values()
1641 .any(|enabled| *enabled);
1642 if have_code_actions_to_run_on_format {
1643 zlog::trace!(logger => "going to run code actions on format");
1644 code_actions_on_format_formatters = Some(
1645 settings
1646 .code_actions_on_format
1647 .iter()
1648 .filter_map(|(action, enabled)| enabled.then_some(action))
1649 .cloned()
1650 .map(Formatter::CodeAction)
1651 .collect::<Vec<_>>(),
1652 );
1653 }
1654 }
1655
1656 let formatters = match (trigger, &settings.format_on_save) {
1657 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1658 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1659 settings.formatter.as_ref()
1660 }
1661 };
1662
1663 let formatters = code_actions_on_format_formatters
1664 .iter()
1665 .flatten()
1666 .chain(formatters);
1667
1668 for formatter in formatters {
1669 let formatter = if formatter == &Formatter::Auto {
1670 if settings.prettier.allowed {
1671 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1672 &Formatter::Prettier
1673 } else {
1674 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1675 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1676 }
1677 } else {
1678 formatter
1679 };
1680 if let Err(err) = Self::apply_formatter(
1681 formatter,
1682 &lsp_store,
1683 buffer,
1684 formatting_transaction_id,
1685 &adapters_and_servers,
1686 &settings,
1687 request_timeout,
1688 logger,
1689 cx,
1690 )
1691 .await
1692 {
1693 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1694 }
1695 }
1696
1697 Ok(())
1698 }
1699
1700 async fn apply_formatter(
1701 formatter: &Formatter,
1702 lsp_store: &WeakEntity<LspStore>,
1703 buffer: &FormattableBuffer,
1704 formatting_transaction_id: clock::Lamport,
1705 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1706 settings: &LanguageSettings,
1707 request_timeout: Duration,
1708 logger: zlog::Logger,
1709 cx: &mut AsyncApp,
1710 ) -> anyhow::Result<()> {
1711 match formatter {
1712 Formatter::None => {
1713 zlog::trace!(logger => "skipping formatter 'none'");
1714 return Ok(());
1715 }
1716 Formatter::Auto => {
1717 debug_panic!("Auto resolved above");
1718 return Ok(());
1719 }
1720 Formatter::Prettier => {
1721 let logger = zlog::scoped!(logger => "prettier");
1722 zlog::trace!(logger => "formatting");
1723 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1724
1725 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1726 lsp_store.prettier_store().unwrap().downgrade()
1727 })?;
1728 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1729 .await
1730 .transpose()?;
1731 let Some(diff) = diff else {
1732 zlog::trace!(logger => "No changes");
1733 return Ok(());
1734 };
1735
1736 extend_formatting_transaction(
1737 buffer,
1738 formatting_transaction_id,
1739 cx,
1740 |buffer, cx| {
1741 buffer.apply_diff(diff, cx);
1742 },
1743 )?;
1744 }
1745 Formatter::External { command, arguments } => {
1746 let logger = zlog::scoped!(logger => "command");
1747 zlog::trace!(logger => "formatting");
1748 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1749
1750 let diff =
1751 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1752 .await
1753 .with_context(|| {
1754 format!("Failed to format buffer via external command: {}", command)
1755 })?;
1756 let Some(diff) = diff else {
1757 zlog::trace!(logger => "No changes");
1758 return Ok(());
1759 };
1760
1761 extend_formatting_transaction(
1762 buffer,
1763 formatting_transaction_id,
1764 cx,
1765 |buffer, cx| {
1766 buffer.apply_diff(diff, cx);
1767 },
1768 )?;
1769 }
1770 Formatter::LanguageServer(specifier) => {
1771 let logger = zlog::scoped!(logger => "language-server");
1772 zlog::trace!(logger => "formatting");
1773 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1774
1775 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1776 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1777 return Ok(());
1778 };
1779
1780 let language_server = match specifier {
1781 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1782 adapters_and_servers.iter().find_map(|(adapter, server)| {
1783 if adapter.name.0.as_ref() == name {
1784 Some(server.clone())
1785 } else {
1786 None
1787 }
1788 })
1789 }
1790 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1791 .iter()
1792 .find(|(_, server)| Self::server_supports_formatting(server))
1793 .map(|(_, server)| server.clone()),
1794 };
1795
1796 let Some(language_server) = language_server else {
1797 log::debug!(
1798 "No language server found to format buffer '{:?}'. Skipping",
1799 buffer_path_abs.as_path().to_string_lossy()
1800 );
1801 return Ok(());
1802 };
1803
1804 zlog::trace!(
1805 logger =>
1806 "Formatting buffer '{:?}' using language server '{:?}'",
1807 buffer_path_abs.as_path().to_string_lossy(),
1808 language_server.name()
1809 );
1810
1811 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1812 zlog::trace!(logger => "formatting ranges");
1813 Self::format_ranges_via_lsp(
1814 &lsp_store,
1815 &buffer.handle,
1816 ranges,
1817 buffer_path_abs,
1818 &language_server,
1819 &settings,
1820 cx,
1821 )
1822 .await
1823 .context("Failed to format ranges via language server")?
1824 } else {
1825 zlog::trace!(logger => "formatting full");
1826 Self::format_via_lsp(
1827 &lsp_store,
1828 &buffer.handle,
1829 buffer_path_abs,
1830 &language_server,
1831 &settings,
1832 cx,
1833 )
1834 .await
1835 .context("failed to format via language server")?
1836 };
1837
1838 if edits.is_empty() {
1839 zlog::trace!(logger => "No changes");
1840 return Ok(());
1841 }
1842 extend_formatting_transaction(
1843 buffer,
1844 formatting_transaction_id,
1845 cx,
1846 |buffer, cx| {
1847 buffer.edit(edits, None, cx);
1848 },
1849 )?;
1850 }
1851 Formatter::CodeAction(code_action_name) => {
1852 let logger = zlog::scoped!(logger => "code-actions");
1853 zlog::trace!(logger => "formatting");
1854 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1855
1856 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1857 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1858 return Ok(());
1859 };
1860
1861 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1862 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1863
1864 let mut actions_and_servers = Vec::new();
1865
1866 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1867 let actions_result = Self::get_server_code_actions_from_action_kinds(
1868 &lsp_store,
1869 language_server.server_id(),
1870 vec![code_action_kind.clone()],
1871 &buffer.handle,
1872 cx,
1873 )
1874 .await
1875 .with_context(|| {
1876 format!(
1877 "Failed to resolve code action {:?} with language server {}",
1878 code_action_kind,
1879 language_server.name()
1880 )
1881 });
1882 let Ok(actions) = actions_result else {
1883 // note: it may be better to set result to the error and break formatters here
1884 // but for now we try to execute the actions that we can resolve and skip the rest
1885 zlog::error!(
1886 logger =>
1887 "Failed to resolve code action {:?} with language server {}",
1888 code_action_kind,
1889 language_server.name()
1890 );
1891 continue;
1892 };
1893 for action in actions {
1894 actions_and_servers.push((action, index));
1895 }
1896 }
1897
1898 if actions_and_servers.is_empty() {
1899 zlog::warn!(logger => "No code actions were resolved, continuing");
1900 return Ok(());
1901 }
1902
1903 'actions: for (mut action, server_index) in actions_and_servers {
1904 let server = &adapters_and_servers[server_index].1;
1905
1906 let describe_code_action = |action: &CodeAction| {
1907 format!(
1908 "code action '{}' with title \"{}\" on server {}",
1909 action
1910 .lsp_action
1911 .action_kind()
1912 .unwrap_or("unknown".into())
1913 .as_str(),
1914 action.lsp_action.title(),
1915 server.name(),
1916 )
1917 };
1918
1919 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1920
1921 if let Err(err) =
1922 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1923 {
1924 zlog::error!(
1925 logger =>
1926 "Failed to resolve {}. Error: {}",
1927 describe_code_action(&action),
1928 err
1929 );
1930 continue;
1931 }
1932
1933 if let Some(edit) = action.lsp_action.edit().cloned() {
1934 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1935 // but filters out and logs warnings for code actions that require unreasonably
1936 // difficult handling on our part, such as:
1937 // - applying edits that call commands
1938 // which can result in arbitrary workspace edits being sent from the server that
1939 // have no way of being tied back to the command that initiated them (i.e. we
1940 // can't know which edits are part of the format request, or if the server is done sending
1941 // actions in response to the command)
1942 // - actions that create/delete/modify/rename files other than the one we are formatting
1943 // as we then would need to handle such changes correctly in the local history as well
1944 // as the remote history through the ProjectTransaction
1945 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1946 // Supporting these actions is not impossible, but not supported as of yet.
1947 if edit.changes.is_none() && edit.document_changes.is_none() {
1948 zlog::trace!(
1949 logger =>
1950 "No changes for code action. Skipping {}",
1951 describe_code_action(&action),
1952 );
1953 continue;
1954 }
1955
1956 let mut operations = Vec::new();
1957 if let Some(document_changes) = edit.document_changes {
1958 match document_changes {
1959 lsp::DocumentChanges::Edits(edits) => operations.extend(
1960 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1961 ),
1962 lsp::DocumentChanges::Operations(ops) => operations = ops,
1963 }
1964 } else if let Some(changes) = edit.changes {
1965 operations.extend(changes.into_iter().map(|(uri, edits)| {
1966 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1967 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
1968 uri,
1969 version: None,
1970 },
1971 edits: edits.into_iter().map(Edit::Plain).collect(),
1972 })
1973 }));
1974 }
1975
1976 let mut edits = Vec::with_capacity(operations.len());
1977
1978 if operations.is_empty() {
1979 zlog::trace!(
1980 logger =>
1981 "No changes for code action. Skipping {}",
1982 describe_code_action(&action),
1983 );
1984 continue;
1985 }
1986 for operation in operations {
1987 let op = match operation {
1988 lsp::DocumentChangeOperation::Edit(op) => op,
1989 lsp::DocumentChangeOperation::Op(_) => {
1990 zlog::warn!(
1991 logger =>
1992 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1993 describe_code_action(&action),
1994 );
1995 continue 'actions;
1996 }
1997 };
1998 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1999 zlog::warn!(
2000 logger =>
2001 "Failed to convert URI '{:?}' to file path. Skipping {}",
2002 &op.text_document.uri,
2003 describe_code_action(&action),
2004 );
2005 continue 'actions;
2006 };
2007 if &file_path != buffer_path_abs {
2008 zlog::warn!(
2009 logger =>
2010 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2011 file_path,
2012 buffer_path_abs,
2013 describe_code_action(&action),
2014 );
2015 continue 'actions;
2016 }
2017
2018 let mut lsp_edits = Vec::new();
2019 for edit in op.edits {
2020 match edit {
2021 Edit::Plain(edit) => {
2022 if !lsp_edits.contains(&edit) {
2023 lsp_edits.push(edit);
2024 }
2025 }
2026 Edit::Annotated(edit) => {
2027 if !lsp_edits.contains(&edit.text_edit) {
2028 lsp_edits.push(edit.text_edit);
2029 }
2030 }
2031 Edit::Snippet(_) => {
2032 zlog::warn!(
2033 logger =>
2034 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2035 describe_code_action(&action),
2036 );
2037 continue 'actions;
2038 }
2039 }
2040 }
2041 let edits_result = lsp_store
2042 .update(cx, |lsp_store, cx| {
2043 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2044 &buffer.handle,
2045 lsp_edits,
2046 server.server_id(),
2047 op.text_document.version,
2048 cx,
2049 )
2050 })?
2051 .await;
2052 let Ok(resolved_edits) = edits_result else {
2053 zlog::warn!(
2054 logger =>
2055 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2056 buffer_path_abs.as_path(),
2057 describe_code_action(&action),
2058 );
2059 continue 'actions;
2060 };
2061 edits.extend(resolved_edits);
2062 }
2063
2064 if edits.is_empty() {
2065 zlog::warn!(logger => "No edits resolved from LSP");
2066 continue;
2067 }
2068
2069 extend_formatting_transaction(
2070 buffer,
2071 formatting_transaction_id,
2072 cx,
2073 |buffer, cx| {
2074 zlog::info!(
2075 "Applying edits {edits:?}. Content: {:?}",
2076 buffer.text()
2077 );
2078 buffer.edit(edits, None, cx);
2079 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2080 },
2081 )?;
2082 }
2083
2084 let Some(command) = action.lsp_action.command() else {
2085 continue;
2086 };
2087
2088 zlog::warn!(
2089 logger =>
2090 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2091 &command.command,
2092 );
2093
2094 let server_capabilities = server.capabilities();
2095 let available_commands = server_capabilities
2096 .execute_command_provider
2097 .as_ref()
2098 .map(|options| options.commands.as_slice())
2099 .unwrap_or_default();
2100 if !available_commands.contains(&command.command) {
2101 zlog::warn!(
2102 logger =>
2103 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2104 command.command,
2105 server.name(),
2106 );
2107 continue;
2108 }
2109
2110 extend_formatting_transaction(
2111 buffer,
2112 formatting_transaction_id,
2113 cx,
2114 |_, _| {},
2115 )?;
2116 zlog::info!(logger => "Executing command {}", &command.command);
2117
2118 lsp_store.update(cx, |this, _| {
2119 this.as_local_mut()
2120 .unwrap()
2121 .last_workspace_edits_by_language_server
2122 .remove(&server.server_id());
2123 })?;
2124
2125 let execute_command_result = server
2126 .request::<lsp::request::ExecuteCommand>(
2127 lsp::ExecuteCommandParams {
2128 command: command.command.clone(),
2129 arguments: command.arguments.clone().unwrap_or_default(),
2130 ..Default::default()
2131 },
2132 request_timeout,
2133 )
2134 .await
2135 .into_response();
2136
2137 if execute_command_result.is_err() {
2138 zlog::error!(
2139 logger =>
2140 "Failed to execute command '{}' as part of {}",
2141 &command.command,
2142 describe_code_action(&action),
2143 );
2144 continue 'actions;
2145 }
2146
2147 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2148 this.as_local_mut()
2149 .unwrap()
2150 .last_workspace_edits_by_language_server
2151 .remove(&server.server_id())
2152 .unwrap_or_default()
2153 })?;
2154
2155 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2156 {
2157 zlog::trace!(
2158 logger =>
2159 "Successfully captured {} edits that resulted from command {}",
2160 transaction.edit_ids.len(),
2161 &command.command,
2162 );
2163 let transaction_id_project_transaction = transaction.id;
2164 buffer.handle.update(cx, |buffer, _| {
2165 // it may have been removed from history if push_to_history was
2166 // false in deserialize_workspace_edit. If so push it so we
2167 // can merge it with the format transaction
2168 // and pop the combined transaction off the history stack
2169 // later if push_to_history is false
2170 if buffer.get_transaction(transaction.id).is_none() {
2171 buffer.push_transaction(transaction, Instant::now());
2172 }
2173 buffer.merge_transactions(
2174 transaction_id_project_transaction,
2175 formatting_transaction_id,
2176 );
2177 });
2178 }
2179
2180 if project_transaction_command.0.is_empty() {
2181 continue;
2182 }
2183
2184 let mut extra_buffers = String::new();
2185 for buffer in project_transaction_command.0.keys() {
2186 buffer.read_with(cx, |b, cx| {
2187 let Some(path) = b.project_path(cx) else {
2188 return;
2189 };
2190
2191 if !extra_buffers.is_empty() {
2192 extra_buffers.push_str(", ");
2193 }
2194 extra_buffers.push_str(path.path.as_unix_str());
2195 });
2196 }
2197 zlog::warn!(
2198 logger =>
2199 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2200 &command.command,
2201 extra_buffers,
2202 );
2203 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2204 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2205 // add it so it's included, and merge it into the format transaction when its created later
2206 }
2207 }
2208 }
2209
2210 Ok(())
2211 }
2212
2213 pub async fn format_ranges_via_lsp(
2214 this: &WeakEntity<LspStore>,
2215 buffer_handle: &Entity<Buffer>,
2216 ranges: &[Range<Anchor>],
2217 abs_path: &Path,
2218 language_server: &Arc<LanguageServer>,
2219 settings: &LanguageSettings,
2220 cx: &mut AsyncApp,
2221 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2222 let capabilities = &language_server.capabilities();
2223 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2224 if range_formatting_provider == Some(&OneOf::Left(false)) {
2225 anyhow::bail!(
2226 "{} language server does not support range formatting",
2227 language_server.name()
2228 );
2229 }
2230
2231 let uri = file_path_to_lsp_url(abs_path)?;
2232 let text_document = lsp::TextDocumentIdentifier::new(uri);
2233
2234 let request_timeout = cx.update(|app| {
2235 ProjectSettings::get_global(app)
2236 .global_lsp_settings
2237 .get_request_timeout()
2238 });
2239 let lsp_edits = {
2240 let mut lsp_ranges = Vec::new();
2241 this.update(cx, |_this, cx| {
2242 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2243 // not have been sent to the language server. This seems like a fairly systemic
2244 // issue, though, the resolution probably is not specific to formatting.
2245 //
2246 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2247 // LSP.
2248 let snapshot = buffer_handle.read(cx).snapshot();
2249 for range in ranges {
2250 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2251 }
2252 anyhow::Ok(())
2253 })??;
2254
2255 let mut edits = None;
2256 for range in lsp_ranges {
2257 if let Some(mut edit) = language_server
2258 .request::<lsp::request::RangeFormatting>(
2259 lsp::DocumentRangeFormattingParams {
2260 text_document: text_document.clone(),
2261 range,
2262 options: lsp_command::lsp_formatting_options(settings),
2263 work_done_progress_params: Default::default(),
2264 },
2265 request_timeout,
2266 )
2267 .await
2268 .into_response()?
2269 {
2270 edits.get_or_insert_with(Vec::new).append(&mut edit);
2271 }
2272 }
2273 edits
2274 };
2275
2276 if let Some(lsp_edits) = lsp_edits {
2277 this.update(cx, |this, cx| {
2278 this.as_local_mut().unwrap().edits_from_lsp(
2279 buffer_handle,
2280 lsp_edits,
2281 language_server.server_id(),
2282 None,
2283 cx,
2284 )
2285 })?
2286 .await
2287 } else {
2288 Ok(Vec::with_capacity(0))
2289 }
2290 }
2291
2292 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2293 let capabilities = server.capabilities();
2294 let formatting = capabilities.document_formatting_provider.as_ref();
2295 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2296 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2297 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2298 }
2299
2300 async fn format_via_lsp(
2301 this: &WeakEntity<LspStore>,
2302 buffer: &Entity<Buffer>,
2303 abs_path: &Path,
2304 language_server: &Arc<LanguageServer>,
2305 settings: &LanguageSettings,
2306 cx: &mut AsyncApp,
2307 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2308 let logger = zlog::scoped!("lsp_format");
2309 zlog::debug!(logger => "Formatting via LSP");
2310
2311 let uri = file_path_to_lsp_url(abs_path)?;
2312 let text_document = lsp::TextDocumentIdentifier::new(uri);
2313 let capabilities = &language_server.capabilities();
2314
2315 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2316 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2317
2318 let request_timeout = cx.update(|app| {
2319 ProjectSettings::get_global(app)
2320 .global_lsp_settings
2321 .get_request_timeout()
2322 });
2323
2324 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2325 let _timer = zlog::time!(logger => "format-full");
2326 language_server
2327 .request::<lsp::request::Formatting>(
2328 lsp::DocumentFormattingParams {
2329 text_document,
2330 options: lsp_command::lsp_formatting_options(settings),
2331 work_done_progress_params: Default::default(),
2332 },
2333 request_timeout,
2334 )
2335 .await
2336 .into_response()?
2337 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2338 let _timer = zlog::time!(logger => "format-range");
2339 let buffer_start = lsp::Position::new(0, 0);
2340 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2341 language_server
2342 .request::<lsp::request::RangeFormatting>(
2343 lsp::DocumentRangeFormattingParams {
2344 text_document: text_document.clone(),
2345 range: lsp::Range::new(buffer_start, buffer_end),
2346 options: lsp_command::lsp_formatting_options(settings),
2347 work_done_progress_params: Default::default(),
2348 },
2349 request_timeout,
2350 )
2351 .await
2352 .into_response()?
2353 } else {
2354 None
2355 };
2356
2357 if let Some(lsp_edits) = lsp_edits {
2358 this.update(cx, |this, cx| {
2359 this.as_local_mut().unwrap().edits_from_lsp(
2360 buffer,
2361 lsp_edits,
2362 language_server.server_id(),
2363 None,
2364 cx,
2365 )
2366 })?
2367 .await
2368 } else {
2369 Ok(Vec::with_capacity(0))
2370 }
2371 }
2372
2373 async fn format_via_external_command(
2374 buffer: &FormattableBuffer,
2375 command: &str,
2376 arguments: Option<&[String]>,
2377 cx: &mut AsyncApp,
2378 ) -> Result<Option<Diff>> {
2379 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2380 let file = File::from_dyn(buffer.file())?;
2381 let worktree = file.worktree.read(cx);
2382 let mut worktree_path = worktree.abs_path().to_path_buf();
2383 if worktree.root_entry()?.is_file() {
2384 worktree_path.pop();
2385 }
2386 Some(worktree_path)
2387 });
2388
2389 use util::command::Stdio;
2390 let mut child = util::command::new_command(command);
2391
2392 if let Some(buffer_env) = buffer.env.as_ref() {
2393 child.envs(buffer_env);
2394 }
2395
2396 if let Some(working_dir_path) = working_dir_path {
2397 child.current_dir(working_dir_path);
2398 }
2399
2400 if let Some(arguments) = arguments {
2401 child.args(arguments.iter().map(|arg| {
2402 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2403 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2404 } else {
2405 arg.replace("{buffer_path}", "Untitled")
2406 }
2407 }));
2408 }
2409
2410 let mut child = child
2411 .stdin(Stdio::piped())
2412 .stdout(Stdio::piped())
2413 .stderr(Stdio::piped())
2414 .spawn()?;
2415
2416 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2417 let text = buffer
2418 .handle
2419 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2420 for chunk in text.chunks() {
2421 stdin.write_all(chunk.as_bytes()).await?;
2422 }
2423 stdin.flush().await?;
2424
2425 let output = child.output().await?;
2426 anyhow::ensure!(
2427 output.status.success(),
2428 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2429 output.status.code(),
2430 String::from_utf8_lossy(&output.stdout),
2431 String::from_utf8_lossy(&output.stderr),
2432 );
2433
2434 let stdout = String::from_utf8(output.stdout)?;
2435 Ok(Some(
2436 buffer
2437 .handle
2438 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2439 .await,
2440 ))
2441 }
2442
2443 async fn try_resolve_code_action(
2444 lang_server: &LanguageServer,
2445 action: &mut CodeAction,
2446 request_timeout: Duration,
2447 ) -> anyhow::Result<()> {
2448 match &mut action.lsp_action {
2449 LspAction::Action(lsp_action) => {
2450 if !action.resolved
2451 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2452 && lsp_action.data.is_some()
2453 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2454 {
2455 **lsp_action = lang_server
2456 .request::<lsp::request::CodeActionResolveRequest>(
2457 *lsp_action.clone(),
2458 request_timeout,
2459 )
2460 .await
2461 .into_response()?;
2462 }
2463 }
2464 LspAction::CodeLens(lens) => {
2465 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2466 *lens = lang_server
2467 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2468 .await
2469 .into_response()?;
2470 }
2471 }
2472 LspAction::Command(_) => {}
2473 }
2474
2475 action.resolved = true;
2476 anyhow::Ok(())
2477 }
2478
2479 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2480 let buffer = buffer_handle.read(cx);
2481
2482 let file = buffer.file().cloned();
2483
2484 let Some(file) = File::from_dyn(file.as_ref()) else {
2485 return;
2486 };
2487 if !file.is_local() {
2488 return;
2489 }
2490 let path = ProjectPath::from_file(file, cx);
2491 let worktree_id = file.worktree_id(cx);
2492 let language = buffer.language().cloned();
2493
2494 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2495 for (server_id, diagnostics) in
2496 diagnostics.get(file.path()).cloned().unwrap_or_default()
2497 {
2498 self.update_buffer_diagnostics(
2499 buffer_handle,
2500 server_id,
2501 None,
2502 None,
2503 None,
2504 Vec::new(),
2505 diagnostics,
2506 cx,
2507 )
2508 .log_err();
2509 }
2510 }
2511 let Some(language) = language else {
2512 return;
2513 };
2514 let Some(snapshot) = self
2515 .worktree_store
2516 .read(cx)
2517 .worktree_for_id(worktree_id, cx)
2518 .map(|worktree| worktree.read(cx).snapshot())
2519 else {
2520 return;
2521 };
2522 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2523
2524 for server_id in
2525 self.lsp_tree
2526 .get(path, language.name(), language.manifest(), &delegate, cx)
2527 {
2528 let server = self
2529 .language_servers
2530 .get(&server_id)
2531 .and_then(|server_state| {
2532 if let LanguageServerState::Running { server, .. } = server_state {
2533 Some(server.clone())
2534 } else {
2535 None
2536 }
2537 });
2538 let server = match server {
2539 Some(server) => server,
2540 None => continue,
2541 };
2542
2543 buffer_handle.update(cx, |buffer, cx| {
2544 buffer.set_completion_triggers(
2545 server.server_id(),
2546 server
2547 .capabilities()
2548 .completion_provider
2549 .as_ref()
2550 .and_then(|provider| {
2551 provider
2552 .trigger_characters
2553 .as_ref()
2554 .map(|characters| characters.iter().cloned().collect())
2555 })
2556 .unwrap_or_default(),
2557 cx,
2558 );
2559 });
2560 }
2561 }
2562
2563 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2564 buffer.update(cx, |buffer, cx| {
2565 let Some(language) = buffer.language() else {
2566 return;
2567 };
2568 let path = ProjectPath {
2569 worktree_id: old_file.worktree_id(cx),
2570 path: old_file.path.clone(),
2571 };
2572 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2573 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2574 buffer.set_completion_triggers(server_id, Default::default(), cx);
2575 }
2576 });
2577 }
2578
2579 fn update_buffer_diagnostics(
2580 &mut self,
2581 buffer: &Entity<Buffer>,
2582 server_id: LanguageServerId,
2583 registration_id: Option<Option<SharedString>>,
2584 result_id: Option<SharedString>,
2585 version: Option<i32>,
2586 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2587 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2588 cx: &mut Context<LspStore>,
2589 ) -> Result<()> {
2590 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2591 Ordering::Equal
2592 .then_with(|| b.is_primary.cmp(&a.is_primary))
2593 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2594 .then_with(|| a.severity.cmp(&b.severity))
2595 .then_with(|| a.message.cmp(&b.message))
2596 }
2597
2598 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2599 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2600 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2601
2602 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2603 Ordering::Equal
2604 .then_with(|| a.range.start.cmp(&b.range.start))
2605 .then_with(|| b.range.end.cmp(&a.range.end))
2606 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2607 });
2608
2609 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2610
2611 let edits_since_save = std::cell::LazyCell::new(|| {
2612 let saved_version = buffer.read(cx).saved_version();
2613 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2614 });
2615
2616 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2617
2618 for (new_diagnostic, entry) in diagnostics {
2619 let start;
2620 let end;
2621 if new_diagnostic && entry.diagnostic.is_disk_based {
2622 // Some diagnostics are based on files on disk instead of buffers'
2623 // current contents. Adjust these diagnostics' ranges to reflect
2624 // any unsaved edits.
2625 // Do not alter the reused ones though, as their coordinates were stored as anchors
2626 // and were properly adjusted on reuse.
2627 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2628 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2629 } else {
2630 start = entry.range.start;
2631 end = entry.range.end;
2632 }
2633
2634 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2635 ..snapshot.clip_point_utf16(end, Bias::Right);
2636
2637 // Expand empty ranges by one codepoint
2638 if range.start == range.end {
2639 // This will be go to the next boundary when being clipped
2640 range.end.column += 1;
2641 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2642 if range.start == range.end && range.end.column > 0 {
2643 range.start.column -= 1;
2644 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2645 }
2646 }
2647
2648 sanitized_diagnostics.push(DiagnosticEntry {
2649 range,
2650 diagnostic: entry.diagnostic,
2651 });
2652 }
2653 drop(edits_since_save);
2654
2655 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2656 buffer.update(cx, |buffer, cx| {
2657 if let Some(registration_id) = registration_id {
2658 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2659 self.buffer_pull_diagnostics_result_ids
2660 .entry(server_id)
2661 .or_default()
2662 .entry(registration_id)
2663 .or_default()
2664 .insert(abs_path, result_id);
2665 }
2666 }
2667
2668 buffer.update_diagnostics(server_id, set, cx)
2669 });
2670
2671 Ok(())
2672 }
2673
2674 fn register_language_server_for_invisible_worktree(
2675 &mut self,
2676 worktree: &Entity<Worktree>,
2677 language_server_id: LanguageServerId,
2678 cx: &mut App,
2679 ) {
2680 let worktree = worktree.read(cx);
2681 let worktree_id = worktree.id();
2682 debug_assert!(!worktree.is_visible());
2683 let Some(mut origin_seed) = self
2684 .language_server_ids
2685 .iter()
2686 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2687 else {
2688 return;
2689 };
2690 origin_seed.worktree_id = worktree_id;
2691 self.language_server_ids
2692 .entry(origin_seed)
2693 .or_insert_with(|| UnifiedLanguageServer {
2694 id: language_server_id,
2695 project_roots: Default::default(),
2696 });
2697 }
2698
2699 fn register_buffer_with_language_servers(
2700 &mut self,
2701 buffer_handle: &Entity<Buffer>,
2702 only_register_servers: HashSet<LanguageServerSelector>,
2703 cx: &mut Context<LspStore>,
2704 ) {
2705 let buffer = buffer_handle.read(cx);
2706 let buffer_id = buffer.remote_id();
2707
2708 let Some(file) = File::from_dyn(buffer.file()) else {
2709 return;
2710 };
2711 if !file.is_local() {
2712 return;
2713 }
2714
2715 let abs_path = file.abs_path(cx);
2716 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2717 return;
2718 };
2719 let initial_snapshot = buffer.text_snapshot();
2720 let worktree_id = file.worktree_id(cx);
2721
2722 let Some(language) = buffer.language().cloned() else {
2723 return;
2724 };
2725 let path: Arc<RelPath> = file
2726 .path()
2727 .parent()
2728 .map(Arc::from)
2729 .unwrap_or_else(|| file.path().clone());
2730 let Some(worktree) = self
2731 .worktree_store
2732 .read(cx)
2733 .worktree_for_id(worktree_id, cx)
2734 else {
2735 return;
2736 };
2737 let language_name = language.name();
2738 let (reused, delegate, servers) = self
2739 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2740 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2741 .unwrap_or_else(|| {
2742 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2743 let delegate: Arc<dyn ManifestDelegate> =
2744 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2745
2746 let servers = self
2747 .lsp_tree
2748 .walk(
2749 ProjectPath { worktree_id, path },
2750 language.name(),
2751 language.manifest(),
2752 &delegate,
2753 cx,
2754 )
2755 .collect::<Vec<_>>();
2756 (false, lsp_delegate, servers)
2757 });
2758 let servers_and_adapters = servers
2759 .into_iter()
2760 .filter_map(|server_node| {
2761 if reused && server_node.server_id().is_none() {
2762 return None;
2763 }
2764 if !only_register_servers.is_empty() {
2765 if let Some(server_id) = server_node.server_id()
2766 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2767 {
2768 return None;
2769 }
2770 if let Some(name) = server_node.name()
2771 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2772 {
2773 return None;
2774 }
2775 }
2776
2777 let server_id = server_node.server_id_or_init(|disposition| {
2778 let path = &disposition.path;
2779
2780 {
2781 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2782
2783 let server_id = self.get_or_insert_language_server(
2784 &worktree,
2785 delegate.clone(),
2786 disposition,
2787 &language_name,
2788 cx,
2789 );
2790
2791 if let Some(state) = self.language_servers.get(&server_id)
2792 && let Ok(uri) = uri
2793 {
2794 state.add_workspace_folder(uri);
2795 };
2796 server_id
2797 }
2798 })?;
2799 let server_state = self.language_servers.get(&server_id)?;
2800 if let LanguageServerState::Running {
2801 server, adapter, ..
2802 } = server_state
2803 {
2804 Some((server.clone(), adapter.clone()))
2805 } else {
2806 None
2807 }
2808 })
2809 .collect::<Vec<_>>();
2810 for (server, adapter) in servers_and_adapters {
2811 buffer_handle.update(cx, |buffer, cx| {
2812 buffer.set_completion_triggers(
2813 server.server_id(),
2814 server
2815 .capabilities()
2816 .completion_provider
2817 .as_ref()
2818 .and_then(|provider| {
2819 provider
2820 .trigger_characters
2821 .as_ref()
2822 .map(|characters| characters.iter().cloned().collect())
2823 })
2824 .unwrap_or_default(),
2825 cx,
2826 );
2827 });
2828
2829 let snapshot = LspBufferSnapshot {
2830 version: 0,
2831 snapshot: initial_snapshot.clone(),
2832 };
2833
2834 let mut registered = false;
2835 self.buffer_snapshots
2836 .entry(buffer_id)
2837 .or_default()
2838 .entry(server.server_id())
2839 .or_insert_with(|| {
2840 registered = true;
2841 server.register_buffer(
2842 uri.clone(),
2843 adapter.language_id(&language.name()),
2844 0,
2845 initial_snapshot.text(),
2846 );
2847
2848 vec![snapshot]
2849 });
2850
2851 self.buffers_opened_in_servers
2852 .entry(buffer_id)
2853 .or_default()
2854 .insert(server.server_id());
2855 if registered {
2856 cx.emit(LspStoreEvent::LanguageServerUpdate {
2857 language_server_id: server.server_id(),
2858 name: None,
2859 message: proto::update_language_server::Variant::RegisteredForBuffer(
2860 proto::RegisteredForBuffer {
2861 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2862 buffer_id: buffer_id.to_proto(),
2863 },
2864 ),
2865 });
2866 }
2867 }
2868 }
2869
2870 fn reuse_existing_language_server<'lang_name>(
2871 &self,
2872 server_tree: &LanguageServerTree,
2873 worktree: &Entity<Worktree>,
2874 language_name: &'lang_name LanguageName,
2875 cx: &mut App,
2876 ) -> Option<(
2877 Arc<LocalLspAdapterDelegate>,
2878 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2879 )> {
2880 if worktree.read(cx).is_visible() {
2881 return None;
2882 }
2883
2884 let worktree_store = self.worktree_store.read(cx);
2885 let servers = server_tree
2886 .instances
2887 .iter()
2888 .filter(|(worktree_id, _)| {
2889 worktree_store
2890 .worktree_for_id(**worktree_id, cx)
2891 .is_some_and(|worktree| worktree.read(cx).is_visible())
2892 })
2893 .flat_map(|(worktree_id, servers)| {
2894 servers
2895 .roots
2896 .iter()
2897 .flat_map(|(_, language_servers)| language_servers)
2898 .map(move |(_, (server_node, server_languages))| {
2899 (worktree_id, server_node, server_languages)
2900 })
2901 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2902 .map(|(worktree_id, server_node, _)| {
2903 (
2904 *worktree_id,
2905 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2906 )
2907 })
2908 })
2909 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2910 acc.entry(worktree_id)
2911 .or_insert_with(Vec::new)
2912 .push(server_node);
2913 acc
2914 })
2915 .into_values()
2916 .max_by_key(|servers| servers.len())?;
2917
2918 let worktree_id = worktree.read(cx).id();
2919 let apply = move |tree: &mut LanguageServerTree| {
2920 for server_node in &servers {
2921 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2922 }
2923 servers
2924 };
2925
2926 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2927 Some((delegate, apply))
2928 }
2929
2930 pub(crate) fn unregister_old_buffer_from_language_servers(
2931 &mut self,
2932 buffer: &Entity<Buffer>,
2933 old_file: &File,
2934 cx: &mut App,
2935 ) {
2936 let old_path = match old_file.as_local() {
2937 Some(local) => local.abs_path(cx),
2938 None => return,
2939 };
2940
2941 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2942 debug_panic!("{old_path:?} is not parseable as an URI");
2943 return;
2944 };
2945 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2946 }
2947
2948 pub(crate) fn unregister_buffer_from_language_servers(
2949 &mut self,
2950 buffer: &Entity<Buffer>,
2951 file_url: &lsp::Uri,
2952 cx: &mut App,
2953 ) {
2954 buffer.update(cx, |buffer, cx| {
2955 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2956
2957 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2958 if snapshots
2959 .as_mut()
2960 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2961 {
2962 language_server.unregister_buffer(file_url.clone());
2963 }
2964 }
2965 });
2966 }
2967
2968 fn buffer_snapshot_for_lsp_version(
2969 &mut self,
2970 buffer: &Entity<Buffer>,
2971 server_id: LanguageServerId,
2972 version: Option<i32>,
2973 cx: &App,
2974 ) -> Result<TextBufferSnapshot> {
2975 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2976
2977 if let Some(version) = version {
2978 let buffer_id = buffer.read(cx).remote_id();
2979 let snapshots = if let Some(snapshots) = self
2980 .buffer_snapshots
2981 .get_mut(&buffer_id)
2982 .and_then(|m| m.get_mut(&server_id))
2983 {
2984 snapshots
2985 } else if version == 0 {
2986 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2987 // We detect this case and treat it as if the version was `None`.
2988 return Ok(buffer.read(cx).text_snapshot());
2989 } else {
2990 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2991 };
2992
2993 let found_snapshot = snapshots
2994 .binary_search_by_key(&version, |e| e.version)
2995 .map(|ix| snapshots[ix].snapshot.clone())
2996 .map_err(|_| {
2997 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2998 })?;
2999
3000 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3001 Ok(found_snapshot)
3002 } else {
3003 Ok((buffer.read(cx)).text_snapshot())
3004 }
3005 }
3006
3007 async fn get_server_code_actions_from_action_kinds(
3008 lsp_store: &WeakEntity<LspStore>,
3009 language_server_id: LanguageServerId,
3010 code_action_kinds: Vec<lsp::CodeActionKind>,
3011 buffer: &Entity<Buffer>,
3012 cx: &mut AsyncApp,
3013 ) -> Result<Vec<CodeAction>> {
3014 let actions = lsp_store
3015 .update(cx, move |this, cx| {
3016 let request = GetCodeActions {
3017 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3018 kinds: Some(code_action_kinds),
3019 };
3020 let server = LanguageServerToQuery::Other(language_server_id);
3021 this.request_lsp(buffer.clone(), server, request, cx)
3022 })?
3023 .await?;
3024 Ok(actions)
3025 }
3026
3027 pub async fn execute_code_actions_on_server(
3028 lsp_store: &WeakEntity<LspStore>,
3029 language_server: &Arc<LanguageServer>,
3030 actions: Vec<CodeAction>,
3031 push_to_history: bool,
3032 project_transaction: &mut ProjectTransaction,
3033 cx: &mut AsyncApp,
3034 ) -> anyhow::Result<()> {
3035 let request_timeout = cx.update(|app| {
3036 ProjectSettings::get_global(app)
3037 .global_lsp_settings
3038 .get_request_timeout()
3039 });
3040
3041 for mut action in actions {
3042 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3043 .await
3044 .context("resolving a formatting code action")?;
3045
3046 if let Some(edit) = action.lsp_action.edit() {
3047 if edit.changes.is_none() && edit.document_changes.is_none() {
3048 continue;
3049 }
3050
3051 let new = Self::deserialize_workspace_edit(
3052 lsp_store.upgrade().context("project dropped")?,
3053 edit.clone(),
3054 push_to_history,
3055 language_server.clone(),
3056 cx,
3057 )
3058 .await?;
3059 project_transaction.0.extend(new.0);
3060 }
3061
3062 let Some(command) = action.lsp_action.command() else {
3063 continue;
3064 };
3065
3066 let server_capabilities = language_server.capabilities();
3067 let available_commands = server_capabilities
3068 .execute_command_provider
3069 .as_ref()
3070 .map(|options| options.commands.as_slice())
3071 .unwrap_or_default();
3072 if !available_commands.contains(&command.command) {
3073 log::warn!(
3074 "Cannot execute a command {} not listed in the language server capabilities",
3075 command.command
3076 );
3077 continue;
3078 }
3079
3080 lsp_store.update(cx, |lsp_store, _| {
3081 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3082 mode.last_workspace_edits_by_language_server
3083 .remove(&language_server.server_id());
3084 }
3085 })?;
3086
3087 language_server
3088 .request::<lsp::request::ExecuteCommand>(
3089 lsp::ExecuteCommandParams {
3090 command: command.command.clone(),
3091 arguments: command.arguments.clone().unwrap_or_default(),
3092 ..Default::default()
3093 },
3094 request_timeout,
3095 )
3096 .await
3097 .into_response()
3098 .context("execute command")?;
3099
3100 lsp_store.update(cx, |this, _| {
3101 if let LspStoreMode::Local(mode) = &mut this.mode {
3102 project_transaction.0.extend(
3103 mode.last_workspace_edits_by_language_server
3104 .remove(&language_server.server_id())
3105 .unwrap_or_default()
3106 .0,
3107 )
3108 }
3109 })?;
3110 }
3111 Ok(())
3112 }
3113
3114 pub async fn deserialize_text_edits(
3115 this: Entity<LspStore>,
3116 buffer_to_edit: Entity<Buffer>,
3117 edits: Vec<lsp::TextEdit>,
3118 push_to_history: bool,
3119 _: Arc<CachedLspAdapter>,
3120 language_server: Arc<LanguageServer>,
3121 cx: &mut AsyncApp,
3122 ) -> Result<Option<Transaction>> {
3123 let edits = this
3124 .update(cx, |this, cx| {
3125 this.as_local_mut().unwrap().edits_from_lsp(
3126 &buffer_to_edit,
3127 edits,
3128 language_server.server_id(),
3129 None,
3130 cx,
3131 )
3132 })
3133 .await?;
3134
3135 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3136 buffer.finalize_last_transaction();
3137 buffer.start_transaction();
3138 for (range, text) in edits {
3139 buffer.edit([(range, text)], None, cx);
3140 }
3141
3142 if buffer.end_transaction(cx).is_some() {
3143 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3144 if !push_to_history {
3145 buffer.forget_transaction(transaction.id);
3146 }
3147 Some(transaction)
3148 } else {
3149 None
3150 }
3151 });
3152
3153 Ok(transaction)
3154 }
3155
3156 #[allow(clippy::type_complexity)]
3157 pub fn edits_from_lsp(
3158 &mut self,
3159 buffer: &Entity<Buffer>,
3160 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3161 server_id: LanguageServerId,
3162 version: Option<i32>,
3163 cx: &mut Context<LspStore>,
3164 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3165 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3166 cx.background_spawn(async move {
3167 let snapshot = snapshot?;
3168 let mut lsp_edits = lsp_edits
3169 .into_iter()
3170 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3171 .collect::<Vec<_>>();
3172
3173 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3174
3175 let mut lsp_edits = lsp_edits.into_iter().peekable();
3176 let mut edits = Vec::new();
3177 while let Some((range, mut new_text)) = lsp_edits.next() {
3178 // Clip invalid ranges provided by the language server.
3179 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3180 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3181
3182 // Combine any LSP edits that are adjacent.
3183 //
3184 // Also, combine LSP edits that are separated from each other by only
3185 // a newline. This is important because for some code actions,
3186 // Rust-analyzer rewrites the entire buffer via a series of edits that
3187 // are separated by unchanged newline characters.
3188 //
3189 // In order for the diffing logic below to work properly, any edits that
3190 // cancel each other out must be combined into one.
3191 while let Some((next_range, next_text)) = lsp_edits.peek() {
3192 if next_range.start.0 > range.end {
3193 if next_range.start.0.row > range.end.row + 1
3194 || next_range.start.0.column > 0
3195 || snapshot.clip_point_utf16(
3196 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3197 Bias::Left,
3198 ) > range.end
3199 {
3200 break;
3201 }
3202 new_text.push('\n');
3203 }
3204 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3205 new_text.push_str(next_text);
3206 lsp_edits.next();
3207 }
3208
3209 // For multiline edits, perform a diff of the old and new text so that
3210 // we can identify the changes more precisely, preserving the locations
3211 // of any anchors positioned in the unchanged regions.
3212 if range.end.row > range.start.row {
3213 let offset = range.start.to_offset(&snapshot);
3214 let old_text = snapshot.text_for_range(range).collect::<String>();
3215 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3216 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3217 (
3218 snapshot.anchor_after(offset + range.start)
3219 ..snapshot.anchor_before(offset + range.end),
3220 replacement,
3221 )
3222 }));
3223 } else if range.end == range.start {
3224 let anchor = snapshot.anchor_after(range.start);
3225 edits.push((anchor..anchor, new_text.into()));
3226 } else {
3227 let edit_start = snapshot.anchor_after(range.start);
3228 let edit_end = snapshot.anchor_before(range.end);
3229 edits.push((edit_start..edit_end, new_text.into()));
3230 }
3231 }
3232
3233 Ok(edits)
3234 })
3235 }
3236
3237 pub(crate) async fn deserialize_workspace_edit(
3238 this: Entity<LspStore>,
3239 edit: lsp::WorkspaceEdit,
3240 push_to_history: bool,
3241 language_server: Arc<LanguageServer>,
3242 cx: &mut AsyncApp,
3243 ) -> Result<ProjectTransaction> {
3244 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3245
3246 let mut operations = Vec::new();
3247 if let Some(document_changes) = edit.document_changes {
3248 match document_changes {
3249 lsp::DocumentChanges::Edits(edits) => {
3250 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3251 }
3252 lsp::DocumentChanges::Operations(ops) => operations = ops,
3253 }
3254 } else if let Some(changes) = edit.changes {
3255 operations.extend(changes.into_iter().map(|(uri, edits)| {
3256 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3257 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3258 uri,
3259 version: None,
3260 },
3261 edits: edits.into_iter().map(Edit::Plain).collect(),
3262 })
3263 }));
3264 }
3265
3266 let mut project_transaction = ProjectTransaction::default();
3267 for operation in operations {
3268 match operation {
3269 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3270 let abs_path = op
3271 .uri
3272 .to_file_path()
3273 .map_err(|()| anyhow!("can't convert URI to path"))?;
3274
3275 if let Some(parent_path) = abs_path.parent() {
3276 fs.create_dir(parent_path).await?;
3277 }
3278 if abs_path.ends_with("/") {
3279 fs.create_dir(&abs_path).await?;
3280 } else {
3281 fs.create_file(
3282 &abs_path,
3283 op.options
3284 .map(|options| fs::CreateOptions {
3285 overwrite: options.overwrite.unwrap_or(false),
3286 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3287 })
3288 .unwrap_or_default(),
3289 )
3290 .await?;
3291 }
3292 }
3293
3294 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3295 let source_abs_path = op
3296 .old_uri
3297 .to_file_path()
3298 .map_err(|()| anyhow!("can't convert URI to path"))?;
3299 let target_abs_path = op
3300 .new_uri
3301 .to_file_path()
3302 .map_err(|()| anyhow!("can't convert URI to path"))?;
3303
3304 let options = fs::RenameOptions {
3305 overwrite: op
3306 .options
3307 .as_ref()
3308 .and_then(|options| options.overwrite)
3309 .unwrap_or(false),
3310 ignore_if_exists: op
3311 .options
3312 .as_ref()
3313 .and_then(|options| options.ignore_if_exists)
3314 .unwrap_or(false),
3315 create_parents: true,
3316 };
3317
3318 fs.rename(&source_abs_path, &target_abs_path, options)
3319 .await?;
3320 }
3321
3322 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3323 let abs_path = op
3324 .uri
3325 .to_file_path()
3326 .map_err(|()| anyhow!("can't convert URI to path"))?;
3327 let options = op
3328 .options
3329 .map(|options| fs::RemoveOptions {
3330 recursive: options.recursive.unwrap_or(false),
3331 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3332 })
3333 .unwrap_or_default();
3334 if abs_path.ends_with("/") {
3335 fs.remove_dir(&abs_path, options).await?;
3336 } else {
3337 fs.remove_file(&abs_path, options).await?;
3338 }
3339 }
3340
3341 lsp::DocumentChangeOperation::Edit(op) => {
3342 let buffer_to_edit = this
3343 .update(cx, |this, cx| {
3344 this.open_local_buffer_via_lsp(
3345 op.text_document.uri.clone(),
3346 language_server.server_id(),
3347 cx,
3348 )
3349 })
3350 .await?;
3351
3352 let edits = this
3353 .update(cx, |this, cx| {
3354 let path = buffer_to_edit.read(cx).project_path(cx);
3355 let active_entry = this.active_entry;
3356 let is_active_entry = path.is_some_and(|project_path| {
3357 this.worktree_store
3358 .read(cx)
3359 .entry_for_path(&project_path, cx)
3360 .is_some_and(|entry| Some(entry.id) == active_entry)
3361 });
3362 let local = this.as_local_mut().unwrap();
3363
3364 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3365 for edit in op.edits {
3366 match edit {
3367 Edit::Plain(edit) => {
3368 if !edits.contains(&edit) {
3369 edits.push(edit)
3370 }
3371 }
3372 Edit::Annotated(edit) => {
3373 if !edits.contains(&edit.text_edit) {
3374 edits.push(edit.text_edit)
3375 }
3376 }
3377 Edit::Snippet(edit) => {
3378 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3379 else {
3380 continue;
3381 };
3382
3383 if is_active_entry {
3384 snippet_edits.push((edit.range, snippet));
3385 } else {
3386 // Since this buffer is not focused, apply a normal edit.
3387 let new_edit = TextEdit {
3388 range: edit.range,
3389 new_text: snippet.text,
3390 };
3391 if !edits.contains(&new_edit) {
3392 edits.push(new_edit);
3393 }
3394 }
3395 }
3396 }
3397 }
3398 if !snippet_edits.is_empty() {
3399 let buffer_id = buffer_to_edit.read(cx).remote_id();
3400 let version = if let Some(buffer_version) = op.text_document.version
3401 {
3402 local
3403 .buffer_snapshot_for_lsp_version(
3404 &buffer_to_edit,
3405 language_server.server_id(),
3406 Some(buffer_version),
3407 cx,
3408 )
3409 .ok()
3410 .map(|snapshot| snapshot.version)
3411 } else {
3412 Some(buffer_to_edit.read(cx).saved_version().clone())
3413 };
3414
3415 let most_recent_edit =
3416 version.and_then(|version| version.most_recent());
3417 // Check if the edit that triggered that edit has been made by this participant.
3418
3419 if let Some(most_recent_edit) = most_recent_edit {
3420 cx.emit(LspStoreEvent::SnippetEdit {
3421 buffer_id,
3422 edits: snippet_edits,
3423 most_recent_edit,
3424 });
3425 }
3426 }
3427
3428 local.edits_from_lsp(
3429 &buffer_to_edit,
3430 edits,
3431 language_server.server_id(),
3432 op.text_document.version,
3433 cx,
3434 )
3435 })
3436 .await?;
3437
3438 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3439 buffer.finalize_last_transaction();
3440 buffer.start_transaction();
3441 for (range, text) in edits {
3442 buffer.edit([(range, text)], None, cx);
3443 }
3444
3445 buffer.end_transaction(cx).and_then(|transaction_id| {
3446 if push_to_history {
3447 buffer.finalize_last_transaction();
3448 buffer.get_transaction(transaction_id).cloned()
3449 } else {
3450 buffer.forget_transaction(transaction_id)
3451 }
3452 })
3453 });
3454 if let Some(transaction) = transaction {
3455 project_transaction.0.insert(buffer_to_edit, transaction);
3456 }
3457 }
3458 }
3459 }
3460
3461 Ok(project_transaction)
3462 }
3463
3464 async fn on_lsp_workspace_edit(
3465 this: WeakEntity<LspStore>,
3466 params: lsp::ApplyWorkspaceEditParams,
3467 server_id: LanguageServerId,
3468 cx: &mut AsyncApp,
3469 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3470 let this = this.upgrade().context("project project closed")?;
3471 let language_server = this
3472 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3473 .context("language server not found")?;
3474 let transaction = Self::deserialize_workspace_edit(
3475 this.clone(),
3476 params.edit,
3477 true,
3478 language_server.clone(),
3479 cx,
3480 )
3481 .await
3482 .log_err();
3483 this.update(cx, |this, cx| {
3484 if let Some(transaction) = transaction {
3485 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3486
3487 this.as_local_mut()
3488 .unwrap()
3489 .last_workspace_edits_by_language_server
3490 .insert(server_id, transaction);
3491 }
3492 });
3493 Ok(lsp::ApplyWorkspaceEditResponse {
3494 applied: true,
3495 failed_change: None,
3496 failure_reason: None,
3497 })
3498 }
3499
3500 fn remove_worktree(
3501 &mut self,
3502 id_to_remove: WorktreeId,
3503 cx: &mut Context<LspStore>,
3504 ) -> Vec<LanguageServerId> {
3505 self.restricted_worktrees_tasks.remove(&id_to_remove);
3506 self.diagnostics.remove(&id_to_remove);
3507 self.prettier_store.update(cx, |prettier_store, cx| {
3508 prettier_store.remove_worktree(id_to_remove, cx);
3509 });
3510
3511 let mut servers_to_remove = BTreeSet::default();
3512 let mut servers_to_preserve = HashSet::default();
3513 for (seed, state) in &self.language_server_ids {
3514 if seed.worktree_id == id_to_remove {
3515 servers_to_remove.insert(state.id);
3516 } else {
3517 servers_to_preserve.insert(state.id);
3518 }
3519 }
3520 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3521 self.language_server_ids
3522 .retain(|_, state| !servers_to_remove.contains(&state.id));
3523 for server_id_to_remove in &servers_to_remove {
3524 self.language_server_watched_paths
3525 .remove(server_id_to_remove);
3526 self.language_server_paths_watched_for_rename
3527 .remove(server_id_to_remove);
3528 self.last_workspace_edits_by_language_server
3529 .remove(server_id_to_remove);
3530 self.language_servers.remove(server_id_to_remove);
3531 self.buffer_pull_diagnostics_result_ids
3532 .remove(server_id_to_remove);
3533 self.workspace_pull_diagnostics_result_ids
3534 .remove(server_id_to_remove);
3535 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3536 buffer_servers.remove(server_id_to_remove);
3537 }
3538 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3539 }
3540 servers_to_remove.into_iter().collect()
3541 }
3542
3543 fn rebuild_watched_paths_inner<'a>(
3544 &'a self,
3545 language_server_id: LanguageServerId,
3546 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3547 cx: &mut Context<LspStore>,
3548 ) -> LanguageServerWatchedPathsBuilder {
3549 let worktrees = self
3550 .worktree_store
3551 .read(cx)
3552 .worktrees()
3553 .filter_map(|worktree| {
3554 self.language_servers_for_worktree(worktree.read(cx).id())
3555 .find(|server| server.server_id() == language_server_id)
3556 .map(|_| worktree)
3557 })
3558 .collect::<Vec<_>>();
3559
3560 let mut worktree_globs = HashMap::default();
3561 let mut abs_globs = HashMap::default();
3562 log::trace!(
3563 "Processing new watcher paths for language server with id {}",
3564 language_server_id
3565 );
3566
3567 for watcher in watchers {
3568 if let Some((worktree, literal_prefix, pattern)) =
3569 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3570 {
3571 worktree.update(cx, |worktree, _| {
3572 if let Some((tree, glob)) =
3573 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3574 {
3575 tree.add_path_prefix_to_scan(literal_prefix);
3576 worktree_globs
3577 .entry(tree.id())
3578 .or_insert_with(GlobSetBuilder::new)
3579 .add(glob);
3580 }
3581 });
3582 } else {
3583 let (path, pattern) = match &watcher.glob_pattern {
3584 lsp::GlobPattern::String(s) => {
3585 let watcher_path = SanitizedPath::new(s);
3586 let path = glob_literal_prefix(watcher_path.as_path());
3587 let pattern = watcher_path
3588 .as_path()
3589 .strip_prefix(&path)
3590 .map(|p| p.to_string_lossy().into_owned())
3591 .unwrap_or_else(|e| {
3592 debug_panic!(
3593 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3594 s,
3595 path.display(),
3596 e
3597 );
3598 watcher_path.as_path().to_string_lossy().into_owned()
3599 });
3600 (path, pattern)
3601 }
3602 lsp::GlobPattern::Relative(rp) => {
3603 let Ok(mut base_uri) = match &rp.base_uri {
3604 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3605 lsp::OneOf::Right(base_uri) => base_uri,
3606 }
3607 .to_file_path() else {
3608 continue;
3609 };
3610
3611 let path = glob_literal_prefix(Path::new(&rp.pattern));
3612 let pattern = Path::new(&rp.pattern)
3613 .strip_prefix(&path)
3614 .map(|p| p.to_string_lossy().into_owned())
3615 .unwrap_or_else(|e| {
3616 debug_panic!(
3617 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3618 rp.pattern,
3619 path.display(),
3620 e
3621 );
3622 rp.pattern.clone()
3623 });
3624 base_uri.push(path);
3625 (base_uri, pattern)
3626 }
3627 };
3628
3629 if let Some(glob) = Glob::new(&pattern).log_err() {
3630 if !path
3631 .components()
3632 .any(|c| matches!(c, path::Component::Normal(_)))
3633 {
3634 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3635 // rather than adding a new watcher for `/`.
3636 for worktree in &worktrees {
3637 worktree_globs
3638 .entry(worktree.read(cx).id())
3639 .or_insert_with(GlobSetBuilder::new)
3640 .add(glob.clone());
3641 }
3642 } else {
3643 abs_globs
3644 .entry(path.into())
3645 .or_insert_with(GlobSetBuilder::new)
3646 .add(glob);
3647 }
3648 }
3649 }
3650 }
3651
3652 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3653 for (worktree_id, builder) in worktree_globs {
3654 if let Ok(globset) = builder.build() {
3655 watch_builder.watch_worktree(worktree_id, globset);
3656 }
3657 }
3658 for (abs_path, builder) in abs_globs {
3659 if let Ok(globset) = builder.build() {
3660 watch_builder.watch_abs_path(abs_path, globset);
3661 }
3662 }
3663 watch_builder
3664 }
3665
3666 fn worktree_and_path_for_file_watcher(
3667 worktrees: &[Entity<Worktree>],
3668 watcher: &FileSystemWatcher,
3669 cx: &App,
3670 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3671 worktrees.iter().find_map(|worktree| {
3672 let tree = worktree.read(cx);
3673 let worktree_root_path = tree.abs_path();
3674 let path_style = tree.path_style();
3675 match &watcher.glob_pattern {
3676 lsp::GlobPattern::String(s) => {
3677 let watcher_path = SanitizedPath::new(s);
3678 let relative = watcher_path
3679 .as_path()
3680 .strip_prefix(&worktree_root_path)
3681 .ok()?;
3682 let literal_prefix = glob_literal_prefix(relative);
3683 Some((
3684 worktree.clone(),
3685 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3686 relative.to_string_lossy().into_owned(),
3687 ))
3688 }
3689 lsp::GlobPattern::Relative(rp) => {
3690 let base_uri = match &rp.base_uri {
3691 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3692 lsp::OneOf::Right(base_uri) => base_uri,
3693 }
3694 .to_file_path()
3695 .ok()?;
3696 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3697 let mut literal_prefix = relative.to_owned();
3698 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3699 Some((
3700 worktree.clone(),
3701 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3702 rp.pattern.clone(),
3703 ))
3704 }
3705 }
3706 })
3707 }
3708
3709 fn rebuild_watched_paths(
3710 &mut self,
3711 language_server_id: LanguageServerId,
3712 cx: &mut Context<LspStore>,
3713 ) {
3714 let Some(registrations) = self
3715 .language_server_dynamic_registrations
3716 .get(&language_server_id)
3717 else {
3718 return;
3719 };
3720
3721 let watch_builder = self.rebuild_watched_paths_inner(
3722 language_server_id,
3723 registrations.did_change_watched_files.values().flatten(),
3724 cx,
3725 );
3726 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3727 self.language_server_watched_paths
3728 .insert(language_server_id, watcher);
3729
3730 cx.notify();
3731 }
3732
3733 fn on_lsp_did_change_watched_files(
3734 &mut self,
3735 language_server_id: LanguageServerId,
3736 registration_id: &str,
3737 params: DidChangeWatchedFilesRegistrationOptions,
3738 cx: &mut Context<LspStore>,
3739 ) {
3740 let registrations = self
3741 .language_server_dynamic_registrations
3742 .entry(language_server_id)
3743 .or_default();
3744
3745 registrations
3746 .did_change_watched_files
3747 .insert(registration_id.to_string(), params.watchers);
3748
3749 self.rebuild_watched_paths(language_server_id, cx);
3750 }
3751
3752 fn on_lsp_unregister_did_change_watched_files(
3753 &mut self,
3754 language_server_id: LanguageServerId,
3755 registration_id: &str,
3756 cx: &mut Context<LspStore>,
3757 ) {
3758 let registrations = self
3759 .language_server_dynamic_registrations
3760 .entry(language_server_id)
3761 .or_default();
3762
3763 if registrations
3764 .did_change_watched_files
3765 .remove(registration_id)
3766 .is_some()
3767 {
3768 log::info!(
3769 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3770 language_server_id,
3771 registration_id
3772 );
3773 } else {
3774 log::warn!(
3775 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3776 language_server_id,
3777 registration_id
3778 );
3779 }
3780
3781 self.rebuild_watched_paths(language_server_id, cx);
3782 }
3783
3784 async fn initialization_options_for_adapter(
3785 adapter: Arc<dyn LspAdapter>,
3786 delegate: &Arc<dyn LspAdapterDelegate>,
3787 cx: &mut AsyncApp,
3788 ) -> Result<Option<serde_json::Value>> {
3789 let Some(mut initialization_config) =
3790 adapter.clone().initialization_options(delegate, cx).await?
3791 else {
3792 return Ok(None);
3793 };
3794
3795 for other_adapter in delegate.registered_lsp_adapters() {
3796 if other_adapter.name() == adapter.name() {
3797 continue;
3798 }
3799 if let Ok(Some(target_config)) = other_adapter
3800 .clone()
3801 .additional_initialization_options(adapter.name(), delegate)
3802 .await
3803 {
3804 merge_json_value_into(target_config.clone(), &mut initialization_config);
3805 }
3806 }
3807
3808 Ok(Some(initialization_config))
3809 }
3810
3811 async fn workspace_configuration_for_adapter(
3812 adapter: Arc<dyn LspAdapter>,
3813 delegate: &Arc<dyn LspAdapterDelegate>,
3814 toolchain: Option<Toolchain>,
3815 requested_uri: Option<Uri>,
3816 cx: &mut AsyncApp,
3817 ) -> Result<serde_json::Value> {
3818 let mut workspace_config = adapter
3819 .clone()
3820 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3821 .await?;
3822
3823 for other_adapter in delegate.registered_lsp_adapters() {
3824 if other_adapter.name() == adapter.name() {
3825 continue;
3826 }
3827 if let Ok(Some(target_config)) = other_adapter
3828 .clone()
3829 .additional_workspace_configuration(adapter.name(), delegate, cx)
3830 .await
3831 {
3832 merge_json_value_into(target_config.clone(), &mut workspace_config);
3833 }
3834 }
3835
3836 Ok(workspace_config)
3837 }
3838
3839 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3840 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3841 Some(server.clone())
3842 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3843 Some(Arc::clone(server))
3844 } else {
3845 None
3846 }
3847 }
3848}
3849
3850fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3851 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3852 cx.emit(LspStoreEvent::LanguageServerUpdate {
3853 language_server_id: server.server_id(),
3854 name: Some(server.name()),
3855 message: proto::update_language_server::Variant::MetadataUpdated(
3856 proto::ServerMetadataUpdated {
3857 capabilities: Some(capabilities),
3858 binary: Some(proto::LanguageServerBinaryInfo {
3859 path: server.binary().path.to_string_lossy().into_owned(),
3860 arguments: server
3861 .binary()
3862 .arguments
3863 .iter()
3864 .map(|arg| arg.to_string_lossy().into_owned())
3865 .collect(),
3866 }),
3867 configuration: serde_json::to_string(server.configuration()).ok(),
3868 workspace_folders: server
3869 .workspace_folders()
3870 .iter()
3871 .map(|uri| uri.to_string())
3872 .collect(),
3873 },
3874 ),
3875 });
3876 }
3877}
3878
3879#[derive(Debug)]
3880pub struct FormattableBuffer {
3881 handle: Entity<Buffer>,
3882 abs_path: Option<PathBuf>,
3883 env: Option<HashMap<String, String>>,
3884 ranges: Option<Vec<Range<Anchor>>>,
3885}
3886
3887pub struct RemoteLspStore {
3888 upstream_client: Option<AnyProtoClient>,
3889 upstream_project_id: u64,
3890}
3891
3892pub(crate) enum LspStoreMode {
3893 Local(LocalLspStore), // ssh host and collab host
3894 Remote(RemoteLspStore), // collab guest
3895}
3896
3897impl LspStoreMode {
3898 fn is_local(&self) -> bool {
3899 matches!(self, LspStoreMode::Local(_))
3900 }
3901}
3902
3903pub struct LspStore {
3904 mode: LspStoreMode,
3905 last_formatting_failure: Option<String>,
3906 downstream_client: Option<(AnyProtoClient, u64)>,
3907 nonce: u128,
3908 buffer_store: Entity<BufferStore>,
3909 worktree_store: Entity<WorktreeStore>,
3910 pub languages: Arc<LanguageRegistry>,
3911 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3912 active_entry: Option<ProjectEntryId>,
3913 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3914 _maintain_buffer_languages: Task<()>,
3915 diagnostic_summaries:
3916 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3917 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3918 semantic_token_config: SemanticTokenConfig,
3919 lsp_data: HashMap<BufferId, BufferLspData>,
3920 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3921 next_hint_id: Arc<AtomicUsize>,
3922}
3923
3924#[derive(Debug)]
3925pub struct BufferLspData {
3926 buffer_version: Global,
3927 document_colors: Option<DocumentColorData>,
3928 code_lens: Option<CodeLensData>,
3929 semantic_tokens: Option<SemanticTokensData>,
3930 folding_ranges: Option<FoldingRangeData>,
3931 document_symbols: Option<DocumentSymbolsData>,
3932 inlay_hints: BufferInlayHints,
3933 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3934 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3935}
3936
3937#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3938struct LspKey {
3939 request_type: TypeId,
3940 server_queried: Option<LanguageServerId>,
3941}
3942
3943impl BufferLspData {
3944 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3945 Self {
3946 buffer_version: buffer.read(cx).version(),
3947 document_colors: None,
3948 code_lens: None,
3949 semantic_tokens: None,
3950 folding_ranges: None,
3951 document_symbols: None,
3952 inlay_hints: BufferInlayHints::new(buffer, cx),
3953 lsp_requests: HashMap::default(),
3954 chunk_lsp_requests: HashMap::default(),
3955 }
3956 }
3957
3958 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3959 if let Some(document_colors) = &mut self.document_colors {
3960 document_colors.remove_server_data(for_server);
3961 }
3962
3963 if let Some(code_lens) = &mut self.code_lens {
3964 code_lens.remove_server_data(for_server);
3965 }
3966
3967 self.inlay_hints.remove_server_data(for_server);
3968
3969 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3970 semantic_tokens.remove_server_data(for_server);
3971 }
3972
3973 if let Some(folding_ranges) = &mut self.folding_ranges {
3974 folding_ranges.ranges.remove(&for_server);
3975 }
3976
3977 if let Some(document_symbols) = &mut self.document_symbols {
3978 document_symbols.remove_server_data(for_server);
3979 }
3980 }
3981
3982 #[cfg(any(test, feature = "test-support"))]
3983 pub fn inlay_hints(&self) -> &BufferInlayHints {
3984 &self.inlay_hints
3985 }
3986}
3987
3988#[derive(Debug)]
3989pub enum LspStoreEvent {
3990 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3991 LanguageServerRemoved(LanguageServerId),
3992 LanguageServerUpdate {
3993 language_server_id: LanguageServerId,
3994 name: Option<LanguageServerName>,
3995 message: proto::update_language_server::Variant,
3996 },
3997 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3998 LanguageServerPrompt(LanguageServerPromptRequest),
3999 LanguageDetected {
4000 buffer: Entity<Buffer>,
4001 new_language: Option<Arc<Language>>,
4002 },
4003 Notification(String),
4004 RefreshInlayHints {
4005 server_id: LanguageServerId,
4006 request_id: Option<usize>,
4007 },
4008 RefreshSemanticTokens {
4009 server_id: LanguageServerId,
4010 request_id: Option<usize>,
4011 },
4012 RefreshCodeLens,
4013 DiagnosticsUpdated {
4014 server_id: LanguageServerId,
4015 paths: Vec<ProjectPath>,
4016 },
4017 DiskBasedDiagnosticsStarted {
4018 language_server_id: LanguageServerId,
4019 },
4020 DiskBasedDiagnosticsFinished {
4021 language_server_id: LanguageServerId,
4022 },
4023 SnippetEdit {
4024 buffer_id: BufferId,
4025 edits: Vec<(lsp::Range, Snippet)>,
4026 most_recent_edit: clock::Lamport,
4027 },
4028 WorkspaceEditApplied(ProjectTransaction),
4029}
4030
4031#[derive(Clone, Debug, Serialize)]
4032pub struct LanguageServerStatus {
4033 pub name: LanguageServerName,
4034 pub server_version: Option<SharedString>,
4035 pub server_readable_version: Option<SharedString>,
4036 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4037 pub has_pending_diagnostic_updates: bool,
4038 pub progress_tokens: HashSet<ProgressToken>,
4039 pub worktree: Option<WorktreeId>,
4040 pub binary: Option<LanguageServerBinary>,
4041 pub configuration: Option<Value>,
4042 pub workspace_folders: BTreeSet<Uri>,
4043 pub process_id: Option<u32>,
4044}
4045
4046#[derive(Clone, Debug)]
4047struct CoreSymbol {
4048 pub language_server_name: LanguageServerName,
4049 pub source_worktree_id: WorktreeId,
4050 pub source_language_server_id: LanguageServerId,
4051 pub path: SymbolLocation,
4052 pub name: String,
4053 pub kind: lsp::SymbolKind,
4054 pub range: Range<Unclipped<PointUtf16>>,
4055 pub container_name: Option<String>,
4056}
4057
4058#[derive(Clone, Debug, PartialEq, Eq)]
4059pub enum SymbolLocation {
4060 InProject(ProjectPath),
4061 OutsideProject {
4062 abs_path: Arc<Path>,
4063 signature: [u8; 32],
4064 },
4065}
4066
4067impl SymbolLocation {
4068 fn file_name(&self) -> Option<&str> {
4069 match self {
4070 Self::InProject(path) => path.path.file_name(),
4071 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4072 }
4073 }
4074}
4075
4076impl LspStore {
4077 pub fn init(client: &AnyProtoClient) {
4078 client.add_entity_request_handler(Self::handle_lsp_query);
4079 client.add_entity_message_handler(Self::handle_lsp_query_response);
4080 client.add_entity_request_handler(Self::handle_restart_language_servers);
4081 client.add_entity_request_handler(Self::handle_stop_language_servers);
4082 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4083 client.add_entity_message_handler(Self::handle_start_language_server);
4084 client.add_entity_message_handler(Self::handle_update_language_server);
4085 client.add_entity_message_handler(Self::handle_language_server_log);
4086 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4087 client.add_entity_request_handler(Self::handle_format_buffers);
4088 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4089 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4090 client.add_entity_request_handler(Self::handle_apply_code_action);
4091 client.add_entity_request_handler(Self::handle_get_project_symbols);
4092 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4093 client.add_entity_request_handler(Self::handle_get_color_presentation);
4094 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4095 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4096 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4097 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4098 client.add_entity_request_handler(Self::handle_on_type_formatting);
4099 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4100 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4101 client.add_entity_request_handler(Self::handle_rename_project_entry);
4102 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4103 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4104 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4105 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4106 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4107 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4109
4110 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4111 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4112 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4113 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4114 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4115 client.add_entity_request_handler(
4116 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4117 );
4118 client.add_entity_request_handler(
4119 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4120 );
4121 client.add_entity_request_handler(
4122 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4123 );
4124 }
4125
4126 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4127 match &self.mode {
4128 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4129 _ => None,
4130 }
4131 }
4132
4133 pub fn as_local(&self) -> Option<&LocalLspStore> {
4134 match &self.mode {
4135 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4136 _ => None,
4137 }
4138 }
4139
4140 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4141 match &mut self.mode {
4142 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4143 _ => None,
4144 }
4145 }
4146
4147 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4148 match &self.mode {
4149 LspStoreMode::Remote(RemoteLspStore {
4150 upstream_client: Some(upstream_client),
4151 upstream_project_id,
4152 ..
4153 }) => Some((upstream_client.clone(), *upstream_project_id)),
4154
4155 LspStoreMode::Remote(RemoteLspStore {
4156 upstream_client: None,
4157 ..
4158 }) => None,
4159 LspStoreMode::Local(_) => None,
4160 }
4161 }
4162
4163 pub fn new_local(
4164 buffer_store: Entity<BufferStore>,
4165 worktree_store: Entity<WorktreeStore>,
4166 prettier_store: Entity<PrettierStore>,
4167 toolchain_store: Entity<LocalToolchainStore>,
4168 environment: Entity<ProjectEnvironment>,
4169 manifest_tree: Entity<ManifestTree>,
4170 languages: Arc<LanguageRegistry>,
4171 http_client: Arc<dyn HttpClient>,
4172 fs: Arc<dyn Fs>,
4173 cx: &mut Context<Self>,
4174 ) -> Self {
4175 let yarn = YarnPathStore::new(fs.clone(), cx);
4176 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4177 .detach();
4178 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4179 .detach();
4180 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4181 .detach();
4182 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4183 .detach();
4184 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4185 .detach();
4186 subscribe_to_binary_statuses(&languages, cx).detach();
4187
4188 let _maintain_workspace_config = {
4189 let (sender, receiver) = watch::channel();
4190 (Self::maintain_workspace_config(receiver, cx), sender)
4191 };
4192
4193 Self {
4194 mode: LspStoreMode::Local(LocalLspStore {
4195 weak: cx.weak_entity(),
4196 worktree_store: worktree_store.clone(),
4197
4198 supplementary_language_servers: Default::default(),
4199 languages: languages.clone(),
4200 language_server_ids: Default::default(),
4201 language_servers: Default::default(),
4202 last_workspace_edits_by_language_server: Default::default(),
4203 language_server_watched_paths: Default::default(),
4204 language_server_paths_watched_for_rename: Default::default(),
4205 language_server_dynamic_registrations: Default::default(),
4206 buffers_being_formatted: Default::default(),
4207 buffers_to_refresh_hash_set: HashSet::default(),
4208 buffers_to_refresh_queue: VecDeque::new(),
4209 _background_diagnostics_worker: Task::ready(()).shared(),
4210 buffer_snapshots: Default::default(),
4211 prettier_store,
4212 environment,
4213 http_client,
4214 fs,
4215 yarn,
4216 next_diagnostic_group_id: Default::default(),
4217 diagnostics: Default::default(),
4218 _subscription: cx.on_app_quit(|this, _| {
4219 this.as_local_mut()
4220 .unwrap()
4221 .shutdown_language_servers_on_quit()
4222 }),
4223 lsp_tree: LanguageServerTree::new(
4224 manifest_tree,
4225 languages.clone(),
4226 toolchain_store.clone(),
4227 ),
4228 toolchain_store,
4229 registered_buffers: HashMap::default(),
4230 buffers_opened_in_servers: HashMap::default(),
4231 buffer_pull_diagnostics_result_ids: HashMap::default(),
4232 workspace_pull_diagnostics_result_ids: HashMap::default(),
4233 restricted_worktrees_tasks: HashMap::default(),
4234 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4235 .manifest_file_names(),
4236 }),
4237 last_formatting_failure: None,
4238 downstream_client: None,
4239 buffer_store,
4240 worktree_store,
4241 languages: languages.clone(),
4242 language_server_statuses: Default::default(),
4243 nonce: StdRng::from_os_rng().random(),
4244 diagnostic_summaries: HashMap::default(),
4245 lsp_server_capabilities: HashMap::default(),
4246 semantic_token_config: SemanticTokenConfig::new(cx),
4247 lsp_data: HashMap::default(),
4248 buffer_reload_tasks: HashMap::default(),
4249 next_hint_id: Arc::default(),
4250 active_entry: None,
4251 _maintain_workspace_config,
4252 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4253 }
4254 }
4255
4256 fn send_lsp_proto_request<R: LspCommand>(
4257 &self,
4258 buffer: Entity<Buffer>,
4259 client: AnyProtoClient,
4260 upstream_project_id: u64,
4261 request: R,
4262 cx: &mut Context<LspStore>,
4263 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4264 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4265 return Task::ready(Ok(R::Response::default()));
4266 }
4267 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4268 cx.spawn(async move |this, cx| {
4269 let response = client.request(message).await?;
4270 let this = this.upgrade().context("project dropped")?;
4271 request
4272 .response_from_proto(response, this, buffer, cx.clone())
4273 .await
4274 })
4275 }
4276
4277 pub(super) fn new_remote(
4278 buffer_store: Entity<BufferStore>,
4279 worktree_store: Entity<WorktreeStore>,
4280 languages: Arc<LanguageRegistry>,
4281 upstream_client: AnyProtoClient,
4282 project_id: u64,
4283 cx: &mut Context<Self>,
4284 ) -> Self {
4285 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4286 .detach();
4287 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4288 .detach();
4289 subscribe_to_binary_statuses(&languages, cx).detach();
4290 let _maintain_workspace_config = {
4291 let (sender, receiver) = watch::channel();
4292 (Self::maintain_workspace_config(receiver, cx), sender)
4293 };
4294 Self {
4295 mode: LspStoreMode::Remote(RemoteLspStore {
4296 upstream_client: Some(upstream_client),
4297 upstream_project_id: project_id,
4298 }),
4299 downstream_client: None,
4300 last_formatting_failure: None,
4301 buffer_store,
4302 worktree_store,
4303 languages: languages.clone(),
4304 language_server_statuses: Default::default(),
4305 nonce: StdRng::from_os_rng().random(),
4306 diagnostic_summaries: HashMap::default(),
4307 lsp_server_capabilities: HashMap::default(),
4308 semantic_token_config: SemanticTokenConfig::new(cx),
4309 next_hint_id: Arc::default(),
4310 lsp_data: HashMap::default(),
4311 buffer_reload_tasks: HashMap::default(),
4312 active_entry: None,
4313
4314 _maintain_workspace_config,
4315 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4316 }
4317 }
4318
4319 fn on_buffer_store_event(
4320 &mut self,
4321 _: Entity<BufferStore>,
4322 event: &BufferStoreEvent,
4323 cx: &mut Context<Self>,
4324 ) {
4325 match event {
4326 BufferStoreEvent::BufferAdded(buffer) => {
4327 self.on_buffer_added(buffer, cx).log_err();
4328 }
4329 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4330 let buffer_id = buffer.read(cx).remote_id();
4331 if let Some(local) = self.as_local_mut()
4332 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4333 {
4334 local.reset_buffer(buffer, old_file, cx);
4335
4336 if local.registered_buffers.contains_key(&buffer_id) {
4337 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4338 }
4339 }
4340
4341 self.detect_language_for_buffer(buffer, cx);
4342 if let Some(local) = self.as_local_mut() {
4343 local.initialize_buffer(buffer, cx);
4344 if local.registered_buffers.contains_key(&buffer_id) {
4345 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4346 }
4347 }
4348 }
4349 _ => {}
4350 }
4351 }
4352
4353 fn on_worktree_store_event(
4354 &mut self,
4355 _: Entity<WorktreeStore>,
4356 event: &WorktreeStoreEvent,
4357 cx: &mut Context<Self>,
4358 ) {
4359 match event {
4360 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4361 if !worktree.read(cx).is_local() {
4362 return;
4363 }
4364 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4365 worktree::Event::UpdatedEntries(changes) => {
4366 this.update_local_worktree_language_servers(&worktree, changes, cx);
4367 }
4368 worktree::Event::UpdatedGitRepositories(_)
4369 | worktree::Event::DeletedEntry(_) => {}
4370 })
4371 .detach()
4372 }
4373 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4374 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4375 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4376 }
4377 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4378 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4379 }
4380 WorktreeStoreEvent::WorktreeReleased(..)
4381 | WorktreeStoreEvent::WorktreeOrderChanged
4382 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4383 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4384 }
4385 }
4386
4387 fn on_prettier_store_event(
4388 &mut self,
4389 _: Entity<PrettierStore>,
4390 event: &PrettierStoreEvent,
4391 cx: &mut Context<Self>,
4392 ) {
4393 match event {
4394 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4395 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4396 }
4397 PrettierStoreEvent::LanguageServerAdded {
4398 new_server_id,
4399 name,
4400 prettier_server,
4401 } => {
4402 self.register_supplementary_language_server(
4403 *new_server_id,
4404 name.clone(),
4405 prettier_server.clone(),
4406 cx,
4407 );
4408 }
4409 }
4410 }
4411
4412 fn on_toolchain_store_event(
4413 &mut self,
4414 _: Entity<LocalToolchainStore>,
4415 event: &ToolchainStoreEvent,
4416 _: &mut Context<Self>,
4417 ) {
4418 if let ToolchainStoreEvent::ToolchainActivated = event {
4419 self.request_workspace_config_refresh()
4420 }
4421 }
4422
4423 fn request_workspace_config_refresh(&mut self) {
4424 *self._maintain_workspace_config.1.borrow_mut() = ();
4425 }
4426
4427 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4428 self.as_local().map(|local| local.prettier_store.clone())
4429 }
4430
4431 fn on_buffer_event(
4432 &mut self,
4433 buffer: Entity<Buffer>,
4434 event: &language::BufferEvent,
4435 cx: &mut Context<Self>,
4436 ) {
4437 match event {
4438 language::BufferEvent::Edited { .. } => {
4439 self.on_buffer_edited(buffer, cx);
4440 }
4441
4442 language::BufferEvent::Saved => {
4443 self.on_buffer_saved(buffer, cx);
4444 }
4445
4446 language::BufferEvent::Reloaded => {
4447 self.on_buffer_reloaded(buffer, cx);
4448 }
4449
4450 _ => {}
4451 }
4452 }
4453
4454 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4455 buffer
4456 .read(cx)
4457 .set_language_registry(self.languages.clone());
4458
4459 cx.subscribe(buffer, |this, buffer, event, cx| {
4460 this.on_buffer_event(buffer, event, cx);
4461 })
4462 .detach();
4463
4464 self.parse_modeline(buffer, cx);
4465 self.detect_language_for_buffer(buffer, cx);
4466 if let Some(local) = self.as_local_mut() {
4467 local.initialize_buffer(buffer, cx);
4468 }
4469
4470 Ok(())
4471 }
4472
4473 pub fn refresh_background_diagnostics_for_buffers(
4474 &mut self,
4475 buffers: HashSet<BufferId>,
4476 cx: &mut Context<Self>,
4477 ) -> Shared<Task<()>> {
4478 let Some(local) = self.as_local_mut() else {
4479 return Task::ready(()).shared();
4480 };
4481 for buffer in buffers {
4482 if local.buffers_to_refresh_hash_set.insert(buffer) {
4483 local.buffers_to_refresh_queue.push_back(buffer);
4484 if local.buffers_to_refresh_queue.len() == 1 {
4485 local._background_diagnostics_worker =
4486 Self::background_diagnostics_worker(cx).shared();
4487 }
4488 }
4489 }
4490
4491 local._background_diagnostics_worker.clone()
4492 }
4493
4494 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4495 let buffer_store = self.buffer_store.clone();
4496 let local = self.as_local_mut()?;
4497 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4498 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4499 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4500 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4501 }
4502 }
4503 None
4504 }
4505
4506 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4507 cx.spawn(async move |this, cx| {
4508 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4509 task.await.log_err();
4510 }
4511 })
4512 }
4513
4514 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4515 if self.parse_modeline(&buffer, cx) {
4516 self.detect_language_for_buffer(&buffer, cx);
4517 }
4518
4519 let buffer_id = buffer.read(cx).remote_id();
4520 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4521 self.buffer_reload_tasks.insert(buffer_id, task);
4522 }
4523
4524 pub(crate) fn register_buffer_with_language_servers(
4525 &mut self,
4526 buffer: &Entity<Buffer>,
4527 only_register_servers: HashSet<LanguageServerSelector>,
4528 ignore_refcounts: bool,
4529 cx: &mut Context<Self>,
4530 ) -> OpenLspBufferHandle {
4531 let buffer_id = buffer.read(cx).remote_id();
4532 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4533 if let Some(local) = self.as_local_mut() {
4534 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4535 if !ignore_refcounts {
4536 *refcount += 1;
4537 }
4538
4539 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4540 // 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
4541 // 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
4542 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4543 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4544 return handle;
4545 };
4546 if !file.is_local() {
4547 return handle;
4548 }
4549
4550 if ignore_refcounts || *refcount == 1 {
4551 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4552 }
4553 if !ignore_refcounts {
4554 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4555 let refcount = {
4556 let local = lsp_store.as_local_mut().unwrap();
4557 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4558 debug_panic!("bad refcounting");
4559 return;
4560 };
4561
4562 *refcount -= 1;
4563 *refcount
4564 };
4565 if refcount == 0 {
4566 lsp_store.lsp_data.remove(&buffer_id);
4567 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4568 let local = lsp_store.as_local_mut().unwrap();
4569 local.registered_buffers.remove(&buffer_id);
4570
4571 local.buffers_opened_in_servers.remove(&buffer_id);
4572 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4573 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4574
4575 let buffer_abs_path = file.abs_path(cx);
4576 for (_, buffer_pull_diagnostics_result_ids) in
4577 &mut local.buffer_pull_diagnostics_result_ids
4578 {
4579 buffer_pull_diagnostics_result_ids.retain(
4580 |_, buffer_result_ids| {
4581 buffer_result_ids.remove(&buffer_abs_path);
4582 !buffer_result_ids.is_empty()
4583 },
4584 );
4585 }
4586
4587 let diagnostic_updates = local
4588 .language_servers
4589 .keys()
4590 .cloned()
4591 .map(|server_id| DocumentDiagnosticsUpdate {
4592 diagnostics: DocumentDiagnostics {
4593 document_abs_path: buffer_abs_path.clone(),
4594 version: None,
4595 diagnostics: Vec::new(),
4596 },
4597 result_id: None,
4598 registration_id: None,
4599 server_id,
4600 disk_based_sources: Cow::Borrowed(&[]),
4601 })
4602 .collect::<Vec<_>>();
4603
4604 lsp_store
4605 .merge_diagnostic_entries(
4606 diagnostic_updates,
4607 |_, diagnostic, _| {
4608 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4609 },
4610 cx,
4611 )
4612 .context("Clearing diagnostics for the closed buffer")
4613 .log_err();
4614 }
4615 }
4616 })
4617 .detach();
4618 }
4619 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4620 let buffer_id = buffer.read(cx).remote_id().to_proto();
4621 cx.background_spawn(async move {
4622 upstream_client
4623 .request(proto::RegisterBufferWithLanguageServers {
4624 project_id: upstream_project_id,
4625 buffer_id,
4626 only_servers: only_register_servers
4627 .into_iter()
4628 .map(|selector| {
4629 let selector = match selector {
4630 LanguageServerSelector::Id(language_server_id) => {
4631 proto::language_server_selector::Selector::ServerId(
4632 language_server_id.to_proto(),
4633 )
4634 }
4635 LanguageServerSelector::Name(language_server_name) => {
4636 proto::language_server_selector::Selector::Name(
4637 language_server_name.to_string(),
4638 )
4639 }
4640 };
4641 proto::LanguageServerSelector {
4642 selector: Some(selector),
4643 }
4644 })
4645 .collect(),
4646 })
4647 .await
4648 })
4649 .detach();
4650 } else {
4651 // Our remote connection got closed
4652 }
4653 handle
4654 }
4655
4656 fn maintain_buffer_languages(
4657 languages: Arc<LanguageRegistry>,
4658 cx: &mut Context<Self>,
4659 ) -> Task<()> {
4660 let mut subscription = languages.subscribe();
4661 let mut prev_reload_count = languages.reload_count();
4662 cx.spawn(async move |this, cx| {
4663 while let Some(()) = subscription.next().await {
4664 if let Some(this) = this.upgrade() {
4665 // If the language registry has been reloaded, then remove and
4666 // re-assign the languages on all open buffers.
4667 let reload_count = languages.reload_count();
4668 if reload_count > prev_reload_count {
4669 prev_reload_count = reload_count;
4670 this.update(cx, |this, cx| {
4671 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4672 for buffer in buffer_store.buffers() {
4673 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4674 {
4675 buffer.update(cx, |buffer, cx| {
4676 buffer.set_language_async(None, cx)
4677 });
4678 if let Some(local) = this.as_local_mut() {
4679 local.reset_buffer(&buffer, &f, cx);
4680
4681 if local
4682 .registered_buffers
4683 .contains_key(&buffer.read(cx).remote_id())
4684 && let Some(file_url) =
4685 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4686 {
4687 local.unregister_buffer_from_language_servers(
4688 &buffer, &file_url, cx,
4689 );
4690 }
4691 }
4692 }
4693 }
4694 });
4695 });
4696 }
4697
4698 this.update(cx, |this, cx| {
4699 let mut plain_text_buffers = Vec::new();
4700 let mut buffers_with_unknown_injections = Vec::new();
4701 for handle in this.buffer_store.read(cx).buffers() {
4702 let buffer = handle.read(cx);
4703 if buffer.language().is_none()
4704 || buffer.language() == Some(&*language::PLAIN_TEXT)
4705 {
4706 plain_text_buffers.push(handle);
4707 } else if buffer.contains_unknown_injections() {
4708 buffers_with_unknown_injections.push(handle);
4709 }
4710 }
4711
4712 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4713 // and reused later in the invisible worktrees.
4714 plain_text_buffers.sort_by_key(|buffer| {
4715 Reverse(
4716 File::from_dyn(buffer.read(cx).file())
4717 .map(|file| file.worktree.read(cx).is_visible()),
4718 )
4719 });
4720
4721 for buffer in plain_text_buffers {
4722 this.detect_language_for_buffer(&buffer, cx);
4723 if let Some(local) = this.as_local_mut() {
4724 local.initialize_buffer(&buffer, cx);
4725 if local
4726 .registered_buffers
4727 .contains_key(&buffer.read(cx).remote_id())
4728 {
4729 local.register_buffer_with_language_servers(
4730 &buffer,
4731 HashSet::default(),
4732 cx,
4733 );
4734 }
4735 }
4736 }
4737
4738 for buffer in buffers_with_unknown_injections {
4739 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4740 }
4741 });
4742 }
4743 }
4744 })
4745 }
4746
4747 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4748 let buffer = buffer_handle.read(cx);
4749 let content = buffer.as_rope();
4750
4751 let modeline_settings = {
4752 let settings_store = cx.global::<SettingsStore>();
4753 let modeline_lines = settings_store
4754 .raw_user_settings()
4755 .and_then(|s| s.content.modeline_lines)
4756 .or(settings_store.raw_default_settings().modeline_lines)
4757 .unwrap_or(5);
4758
4759 const MAX_MODELINE_BYTES: usize = 1024;
4760
4761 let first_bytes =
4762 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4763 let mut first_lines = Vec::new();
4764 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4765 for _ in 0..modeline_lines {
4766 if let Some(line) = lines.next() {
4767 first_lines.push(line.to_string());
4768 } else {
4769 break;
4770 }
4771 }
4772 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4773
4774 let last_start =
4775 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4776 let mut last_lines = Vec::new();
4777 let mut lines = content
4778 .reversed_chunks_in_range(last_start..content.len())
4779 .lines();
4780 for _ in 0..modeline_lines {
4781 if let Some(line) = lines.next() {
4782 last_lines.push(line.to_string());
4783 } else {
4784 break;
4785 }
4786 }
4787 let last_lines_ref: Vec<_> =
4788 last_lines.iter().rev().map(|line| line.as_str()).collect();
4789 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4790 };
4791
4792 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4793
4794 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4795 }
4796
4797 fn detect_language_for_buffer(
4798 &mut self,
4799 buffer_handle: &Entity<Buffer>,
4800 cx: &mut Context<Self>,
4801 ) -> Option<language::AvailableLanguage> {
4802 // If the buffer has a language, set it and start the language server if we haven't already.
4803 let buffer = buffer_handle.read(cx);
4804 let file = buffer.file()?;
4805 let content = buffer.as_rope();
4806 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4807
4808 let available_language = if let Some(ModelineSettings {
4809 mode: Some(mode_name),
4810 ..
4811 }) = modeline_settings
4812 {
4813 self.languages
4814 .available_language_for_modeline_name(mode_name)
4815 } else {
4816 self.languages.language_for_file(file, Some(content), cx)
4817 };
4818 if let Some(available_language) = &available_language {
4819 if let Some(Ok(Ok(new_language))) = self
4820 .languages
4821 .load_language(available_language)
4822 .now_or_never()
4823 {
4824 self.set_language_for_buffer(buffer_handle, new_language, cx);
4825 }
4826 } else {
4827 cx.emit(LspStoreEvent::LanguageDetected {
4828 buffer: buffer_handle.clone(),
4829 new_language: None,
4830 });
4831 }
4832
4833 available_language
4834 }
4835
4836 pub(crate) fn set_language_for_buffer(
4837 &mut self,
4838 buffer_entity: &Entity<Buffer>,
4839 new_language: Arc<Language>,
4840 cx: &mut Context<Self>,
4841 ) {
4842 let buffer = buffer_entity.read(cx);
4843 let buffer_file = buffer.file().cloned();
4844 let buffer_id = buffer.remote_id();
4845 if let Some(local_store) = self.as_local_mut()
4846 && local_store.registered_buffers.contains_key(&buffer_id)
4847 && let Some(abs_path) =
4848 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4849 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4850 {
4851 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4852 }
4853 buffer_entity.update(cx, |buffer, cx| {
4854 if buffer
4855 .language()
4856 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4857 {
4858 buffer.set_language_async(Some(new_language.clone()), cx);
4859 }
4860 });
4861
4862 let settings = LanguageSettings::resolve(
4863 Some(&buffer_entity.read(cx)),
4864 Some(&new_language.name()),
4865 cx,
4866 )
4867 .into_owned();
4868 let buffer_file = File::from_dyn(buffer_file.as_ref());
4869
4870 let worktree_id = if let Some(file) = buffer_file {
4871 let worktree = file.worktree.clone();
4872
4873 if let Some(local) = self.as_local_mut()
4874 && local.registered_buffers.contains_key(&buffer_id)
4875 {
4876 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4877 }
4878 Some(worktree.read(cx).id())
4879 } else {
4880 None
4881 };
4882
4883 if settings.prettier.allowed
4884 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4885 {
4886 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4887 if let Some(prettier_store) = prettier_store {
4888 prettier_store.update(cx, |prettier_store, cx| {
4889 prettier_store.install_default_prettier(
4890 worktree_id,
4891 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4892 cx,
4893 )
4894 })
4895 }
4896 }
4897
4898 cx.emit(LspStoreEvent::LanguageDetected {
4899 buffer: buffer_entity.clone(),
4900 new_language: Some(new_language),
4901 })
4902 }
4903
4904 pub fn buffer_store(&self) -> Entity<BufferStore> {
4905 self.buffer_store.clone()
4906 }
4907
4908 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4909 self.active_entry = active_entry;
4910 }
4911
4912 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4913 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4914 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4915 {
4916 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4917 summaries
4918 .iter()
4919 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4920 });
4921 if let Some(summary) = summaries.next() {
4922 client
4923 .send(proto::UpdateDiagnosticSummary {
4924 project_id: downstream_project_id,
4925 worktree_id: worktree.id().to_proto(),
4926 summary: Some(summary),
4927 more_summaries: summaries.collect(),
4928 })
4929 .log_err();
4930 }
4931 }
4932 }
4933
4934 fn is_capable_for_proto_request<R>(
4935 &self,
4936 buffer: &Entity<Buffer>,
4937 request: &R,
4938 cx: &App,
4939 ) -> bool
4940 where
4941 R: LspCommand,
4942 {
4943 self.check_if_capable_for_proto_request(
4944 buffer,
4945 |capabilities| {
4946 request.check_capabilities(AdapterServerCapabilities {
4947 server_capabilities: capabilities.clone(),
4948 code_action_kinds: None,
4949 })
4950 },
4951 cx,
4952 )
4953 }
4954
4955 fn check_if_capable_for_proto_request<F>(
4956 &self,
4957 buffer: &Entity<Buffer>,
4958 check: F,
4959 cx: &App,
4960 ) -> bool
4961 where
4962 F: FnMut(&lsp::ServerCapabilities) -> bool,
4963 {
4964 let Some(language) = buffer.read(cx).language().cloned() else {
4965 return false;
4966 };
4967 let registered_language_servers = self
4968 .languages
4969 .lsp_adapters(&language.name())
4970 .into_iter()
4971 .map(|lsp_adapter| lsp_adapter.name())
4972 .collect::<HashSet<_>>();
4973 self.language_server_statuses
4974 .iter()
4975 .filter_map(|(server_id, server_status)| {
4976 // Include servers that are either registered for this language OR
4977 // available to be loaded (for SSH remote mode where adapters like
4978 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4979 // but only loaded on the server side)
4980 let is_relevant = registered_language_servers.contains(&server_status.name)
4981 || self.languages.is_lsp_adapter_available(&server_status.name);
4982 is_relevant.then_some(server_id)
4983 })
4984 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4985 .any(check)
4986 }
4987
4988 fn all_capable_for_proto_request<F>(
4989 &self,
4990 buffer: &Entity<Buffer>,
4991 mut check: F,
4992 cx: &App,
4993 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4994 where
4995 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4996 {
4997 let Some(language) = buffer.read(cx).language().cloned() else {
4998 return Vec::default();
4999 };
5000 let registered_language_servers = self
5001 .languages
5002 .lsp_adapters(&language.name())
5003 .into_iter()
5004 .map(|lsp_adapter| lsp_adapter.name())
5005 .collect::<HashSet<_>>();
5006 self.language_server_statuses
5007 .iter()
5008 .filter_map(|(server_id, server_status)| {
5009 // Include servers that are either registered for this language OR
5010 // available to be loaded (for SSH remote mode where adapters like
5011 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5012 // but only loaded on the server side)
5013 let is_relevant = registered_language_servers.contains(&server_status.name)
5014 || self.languages.is_lsp_adapter_available(&server_status.name);
5015 is_relevant.then_some((server_id, &server_status.name))
5016 })
5017 .filter_map(|(server_id, server_name)| {
5018 self.lsp_server_capabilities
5019 .get(server_id)
5020 .map(|c| (server_id, server_name, c))
5021 })
5022 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5023 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5024 .collect()
5025 }
5026
5027 pub fn request_lsp<R>(
5028 &mut self,
5029 buffer: Entity<Buffer>,
5030 server: LanguageServerToQuery,
5031 request: R,
5032 cx: &mut Context<Self>,
5033 ) -> Task<Result<R::Response>>
5034 where
5035 R: LspCommand,
5036 <R::LspRequest as lsp::request::Request>::Result: Send,
5037 <R::LspRequest as lsp::request::Request>::Params: Send,
5038 {
5039 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5040 return self.send_lsp_proto_request(
5041 buffer,
5042 upstream_client,
5043 upstream_project_id,
5044 request,
5045 cx,
5046 );
5047 }
5048
5049 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5050 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5051 local
5052 .language_servers_for_buffer(buffer, cx)
5053 .find(|(_, server)| {
5054 request.check_capabilities(server.adapter_server_capabilities())
5055 })
5056 .map(|(_, server)| server.clone())
5057 }),
5058 LanguageServerToQuery::Other(id) => self
5059 .language_server_for_local_buffer(buffer, id, cx)
5060 .and_then(|(_, server)| {
5061 request
5062 .check_capabilities(server.adapter_server_capabilities())
5063 .then(|| Arc::clone(server))
5064 }),
5065 }) else {
5066 return Task::ready(Ok(Default::default()));
5067 };
5068
5069 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5070
5071 let Some(file) = file else {
5072 return Task::ready(Ok(Default::default()));
5073 };
5074
5075 let lsp_params = match request.to_lsp_params_or_response(
5076 &file.abs_path(cx),
5077 buffer.read(cx),
5078 &language_server,
5079 cx,
5080 ) {
5081 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5082 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5083 Err(err) => {
5084 let message = format!(
5085 "{} via {} failed: {}",
5086 request.display_name(),
5087 language_server.name(),
5088 err
5089 );
5090 // rust-analyzer likes to error with this when its still loading up
5091 if !message.ends_with("content modified") {
5092 log::warn!("{message}");
5093 }
5094 return Task::ready(Err(anyhow!(message)));
5095 }
5096 };
5097
5098 let status = request.status();
5099 let request_timeout = ProjectSettings::get_global(cx)
5100 .global_lsp_settings
5101 .get_request_timeout();
5102
5103 cx.spawn(async move |this, cx| {
5104 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5105
5106 let id = lsp_request.id();
5107 let _cleanup = if status.is_some() {
5108 cx.update(|cx| {
5109 this.update(cx, |this, cx| {
5110 this.on_lsp_work_start(
5111 language_server.server_id(),
5112 ProgressToken::Number(id),
5113 LanguageServerProgress {
5114 is_disk_based_diagnostics_progress: false,
5115 is_cancellable: false,
5116 title: None,
5117 message: status.clone(),
5118 percentage: None,
5119 last_update_at: cx.background_executor().now(),
5120 },
5121 cx,
5122 );
5123 })
5124 })
5125 .log_err();
5126
5127 Some(defer(|| {
5128 cx.update(|cx| {
5129 this.update(cx, |this, cx| {
5130 this.on_lsp_work_end(
5131 language_server.server_id(),
5132 ProgressToken::Number(id),
5133 cx,
5134 );
5135 })
5136 })
5137 .log_err();
5138 }))
5139 } else {
5140 None
5141 };
5142
5143 let result = lsp_request.await.into_response();
5144
5145 let response = result.map_err(|err| {
5146 let message = format!(
5147 "{} via {} failed: {}",
5148 request.display_name(),
5149 language_server.name(),
5150 err
5151 );
5152 // rust-analyzer likes to error with this when its still loading up
5153 if !message.ends_with("content modified") {
5154 log::warn!("{message}");
5155 }
5156 anyhow::anyhow!(message)
5157 })?;
5158
5159 request
5160 .response_from_lsp(
5161 response,
5162 this.upgrade().context("no app context")?,
5163 buffer,
5164 language_server.server_id(),
5165 cx.clone(),
5166 )
5167 .await
5168 })
5169 }
5170
5171 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5172 let mut language_formatters_to_check = Vec::new();
5173 for buffer in self.buffer_store.read(cx).buffers() {
5174 let buffer = buffer.read(cx);
5175 let settings = LanguageSettings::for_buffer(buffer, cx);
5176 if buffer.language().is_some() {
5177 let buffer_file = File::from_dyn(buffer.file());
5178 language_formatters_to_check.push((
5179 buffer_file.map(|f| f.worktree_id(cx)),
5180 settings.into_owned(),
5181 ));
5182 }
5183 }
5184
5185 self.request_workspace_config_refresh();
5186
5187 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5188 prettier_store.update(cx, |prettier_store, cx| {
5189 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5190 })
5191 }
5192
5193 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5194 .global_lsp_settings
5195 .semantic_token_rules
5196 .clone();
5197 self.semantic_token_config
5198 .update_rules(new_semantic_token_rules);
5199 // Always clear cached stylizers so that changes to language-specific
5200 // semantic token rules (e.g. from extension install/uninstall) are
5201 // picked up. Stylizers are recreated lazily, so this is cheap.
5202 self.semantic_token_config.clear_stylizers();
5203
5204 let new_global_semantic_tokens_mode =
5205 all_language_settings(None, cx).defaults.semantic_tokens;
5206 if self
5207 .semantic_token_config
5208 .update_global_mode(new_global_semantic_tokens_mode)
5209 {
5210 self.restart_all_language_servers(cx);
5211 }
5212
5213 cx.notify();
5214 }
5215
5216 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5217 let buffer_store = self.buffer_store.clone();
5218 let Some(local) = self.as_local_mut() else {
5219 return;
5220 };
5221 let mut adapters = BTreeMap::default();
5222 let get_adapter = {
5223 let languages = local.languages.clone();
5224 let environment = local.environment.clone();
5225 let weak = local.weak.clone();
5226 let worktree_store = local.worktree_store.clone();
5227 let http_client = local.http_client.clone();
5228 let fs = local.fs.clone();
5229 move |worktree_id, cx: &mut App| {
5230 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5231 Some(LocalLspAdapterDelegate::new(
5232 languages.clone(),
5233 &environment,
5234 weak.clone(),
5235 &worktree,
5236 http_client.clone(),
5237 fs.clone(),
5238 cx,
5239 ))
5240 }
5241 };
5242
5243 let mut messages_to_report = Vec::new();
5244 let (new_tree, to_stop) = {
5245 let mut rebase = local.lsp_tree.rebase();
5246 let buffers = buffer_store
5247 .read(cx)
5248 .buffers()
5249 .filter_map(|buffer| {
5250 let raw_buffer = buffer.read(cx);
5251 if !local
5252 .registered_buffers
5253 .contains_key(&raw_buffer.remote_id())
5254 {
5255 return None;
5256 }
5257 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5258 let language = raw_buffer.language().cloned()?;
5259 Some((file, language, raw_buffer.remote_id()))
5260 })
5261 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5262 for (file, language, buffer_id) in buffers {
5263 let worktree_id = file.worktree_id(cx);
5264 let Some(worktree) = local
5265 .worktree_store
5266 .read(cx)
5267 .worktree_for_id(worktree_id, cx)
5268 else {
5269 continue;
5270 };
5271
5272 if let Some((_, apply)) = local.reuse_existing_language_server(
5273 rebase.server_tree(),
5274 &worktree,
5275 &language.name(),
5276 cx,
5277 ) {
5278 (apply)(rebase.server_tree());
5279 } else if let Some(lsp_delegate) = adapters
5280 .entry(worktree_id)
5281 .or_insert_with(|| get_adapter(worktree_id, cx))
5282 .clone()
5283 {
5284 let delegate =
5285 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5286 let path = file
5287 .path()
5288 .parent()
5289 .map(Arc::from)
5290 .unwrap_or_else(|| file.path().clone());
5291 let worktree_path = ProjectPath { worktree_id, path };
5292 let abs_path = file.abs_path(cx);
5293 let nodes = rebase
5294 .walk(
5295 worktree_path,
5296 language.name(),
5297 language.manifest(),
5298 delegate.clone(),
5299 cx,
5300 )
5301 .collect::<Vec<_>>();
5302 for node in nodes {
5303 let server_id = node.server_id_or_init(|disposition| {
5304 let path = &disposition.path;
5305 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5306 let key = LanguageServerSeed {
5307 worktree_id,
5308 name: disposition.server_name.clone(),
5309 settings: LanguageServerSeedSettings {
5310 binary: disposition.settings.binary.clone(),
5311 initialization_options: disposition
5312 .settings
5313 .initialization_options
5314 .clone(),
5315 },
5316 toolchain: local.toolchain_store.read(cx).active_toolchain(
5317 path.worktree_id,
5318 &path.path,
5319 language.name(),
5320 ),
5321 };
5322 local.language_server_ids.remove(&key);
5323
5324 let server_id = local.get_or_insert_language_server(
5325 &worktree,
5326 lsp_delegate.clone(),
5327 disposition,
5328 &language.name(),
5329 cx,
5330 );
5331 if let Some(state) = local.language_servers.get(&server_id)
5332 && let Ok(uri) = uri
5333 {
5334 state.add_workspace_folder(uri);
5335 };
5336 server_id
5337 });
5338
5339 if let Some(language_server_id) = server_id {
5340 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5341 language_server_id,
5342 name: node.name(),
5343 message:
5344 proto::update_language_server::Variant::RegisteredForBuffer(
5345 proto::RegisteredForBuffer {
5346 buffer_abs_path: abs_path
5347 .to_string_lossy()
5348 .into_owned(),
5349 buffer_id: buffer_id.to_proto(),
5350 },
5351 ),
5352 });
5353 }
5354 }
5355 } else {
5356 continue;
5357 }
5358 }
5359 rebase.finish()
5360 };
5361 for message in messages_to_report {
5362 cx.emit(message);
5363 }
5364 local.lsp_tree = new_tree;
5365 for (id, _) in to_stop {
5366 self.stop_local_language_server(id, cx).detach();
5367 }
5368 }
5369
5370 pub fn apply_code_action(
5371 &self,
5372 buffer_handle: Entity<Buffer>,
5373 mut action: CodeAction,
5374 push_to_history: bool,
5375 cx: &mut Context<Self>,
5376 ) -> Task<Result<ProjectTransaction>> {
5377 if let Some((upstream_client, project_id)) = self.upstream_client() {
5378 let request = proto::ApplyCodeAction {
5379 project_id,
5380 buffer_id: buffer_handle.read(cx).remote_id().into(),
5381 action: Some(Self::serialize_code_action(&action)),
5382 };
5383 let buffer_store = self.buffer_store();
5384 cx.spawn(async move |_, cx| {
5385 let response = upstream_client
5386 .request(request)
5387 .await?
5388 .transaction
5389 .context("missing transaction")?;
5390
5391 buffer_store
5392 .update(cx, |buffer_store, cx| {
5393 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5394 })
5395 .await
5396 })
5397 } else if self.mode.is_local() {
5398 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5399 let request_timeout = ProjectSettings::get_global(cx)
5400 .global_lsp_settings
5401 .get_request_timeout();
5402 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5403 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5404 }) else {
5405 return Task::ready(Ok(ProjectTransaction::default()));
5406 };
5407
5408 cx.spawn(async move |this, cx| {
5409 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5410 .await
5411 .context("resolving a code action")?;
5412 if let Some(edit) = action.lsp_action.edit()
5413 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5414 return LocalLspStore::deserialize_workspace_edit(
5415 this.upgrade().context("no app present")?,
5416 edit.clone(),
5417 push_to_history,
5418
5419 lang_server.clone(),
5420 cx,
5421 )
5422 .await;
5423 }
5424
5425 let Some(command) = action.lsp_action.command() else {
5426 return Ok(ProjectTransaction::default())
5427 };
5428
5429 let server_capabilities = lang_server.capabilities();
5430 let available_commands = server_capabilities
5431 .execute_command_provider
5432 .as_ref()
5433 .map(|options| options.commands.as_slice())
5434 .unwrap_or_default();
5435
5436 if !available_commands.contains(&command.command) {
5437 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5438 return Ok(ProjectTransaction::default())
5439 }
5440
5441 let request_timeout = cx.update(|app|
5442 ProjectSettings::get_global(app)
5443 .global_lsp_settings
5444 .get_request_timeout()
5445 );
5446
5447 this.update(cx, |this, _| {
5448 this.as_local_mut()
5449 .unwrap()
5450 .last_workspace_edits_by_language_server
5451 .remove(&lang_server.server_id());
5452 })?;
5453
5454 let _result = lang_server
5455 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5456 command: command.command.clone(),
5457 arguments: command.arguments.clone().unwrap_or_default(),
5458 ..lsp::ExecuteCommandParams::default()
5459 }, request_timeout)
5460 .await.into_response()
5461 .context("execute command")?;
5462
5463 return this.update(cx, |this, _| {
5464 this.as_local_mut()
5465 .unwrap()
5466 .last_workspace_edits_by_language_server
5467 .remove(&lang_server.server_id())
5468 .unwrap_or_default()
5469 });
5470 })
5471 } else {
5472 Task::ready(Err(anyhow!("no upstream client and not local")))
5473 }
5474 }
5475
5476 pub fn apply_code_action_kind(
5477 &mut self,
5478 buffers: HashSet<Entity<Buffer>>,
5479 kind: CodeActionKind,
5480 push_to_history: bool,
5481 cx: &mut Context<Self>,
5482 ) -> Task<anyhow::Result<ProjectTransaction>> {
5483 if self.as_local().is_some() {
5484 cx.spawn(async move |lsp_store, cx| {
5485 let buffers = buffers.into_iter().collect::<Vec<_>>();
5486 let result = LocalLspStore::execute_code_action_kind_locally(
5487 lsp_store.clone(),
5488 buffers,
5489 kind,
5490 push_to_history,
5491 cx,
5492 )
5493 .await;
5494 lsp_store.update(cx, |lsp_store, _| {
5495 lsp_store.update_last_formatting_failure(&result);
5496 })?;
5497 result
5498 })
5499 } else if let Some((client, project_id)) = self.upstream_client() {
5500 let buffer_store = self.buffer_store();
5501 cx.spawn(async move |lsp_store, cx| {
5502 let result = client
5503 .request(proto::ApplyCodeActionKind {
5504 project_id,
5505 kind: kind.as_str().to_owned(),
5506 buffer_ids: buffers
5507 .iter()
5508 .map(|buffer| {
5509 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5510 })
5511 .collect(),
5512 })
5513 .await
5514 .and_then(|result| result.transaction.context("missing transaction"));
5515 lsp_store.update(cx, |lsp_store, _| {
5516 lsp_store.update_last_formatting_failure(&result);
5517 })?;
5518
5519 let transaction_response = result?;
5520 buffer_store
5521 .update(cx, |buffer_store, cx| {
5522 buffer_store.deserialize_project_transaction(
5523 transaction_response,
5524 push_to_history,
5525 cx,
5526 )
5527 })
5528 .await
5529 })
5530 } else {
5531 Task::ready(Ok(ProjectTransaction::default()))
5532 }
5533 }
5534
5535 pub fn resolved_hint(
5536 &mut self,
5537 buffer_id: BufferId,
5538 id: InlayId,
5539 cx: &mut Context<Self>,
5540 ) -> Option<ResolvedHint> {
5541 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5542
5543 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5544 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5545 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5546 let (server_id, resolve_data) = match &hint.resolve_state {
5547 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5548 ResolveState::Resolving => {
5549 return Some(ResolvedHint::Resolving(
5550 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5551 ));
5552 }
5553 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5554 };
5555
5556 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5557 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5558 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5559 id,
5560 cx.spawn(async move |lsp_store, cx| {
5561 let resolved_hint = resolve_task.await;
5562 lsp_store
5563 .update(cx, |lsp_store, _| {
5564 if let Some(old_inlay_hint) = lsp_store
5565 .lsp_data
5566 .get_mut(&buffer_id)
5567 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5568 {
5569 match resolved_hint {
5570 Ok(resolved_hint) => {
5571 *old_inlay_hint = resolved_hint;
5572 }
5573 Err(e) => {
5574 old_inlay_hint.resolve_state =
5575 ResolveState::CanResolve(server_id, resolve_data);
5576 log::error!("Inlay hint resolve failed: {e:#}");
5577 }
5578 }
5579 }
5580 })
5581 .ok();
5582 })
5583 .shared(),
5584 );
5585 debug_assert!(
5586 previous_task.is_none(),
5587 "Did not change hint's resolve state after spawning its resolve"
5588 );
5589 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5590 None
5591 }
5592
5593 pub(crate) fn linked_edits(
5594 &mut self,
5595 buffer: &Entity<Buffer>,
5596 position: Anchor,
5597 cx: &mut Context<Self>,
5598 ) -> Task<Result<Vec<Range<Anchor>>>> {
5599 let snapshot = buffer.read(cx).snapshot();
5600 let scope = snapshot.language_scope_at(position);
5601 let Some(server_id) = self
5602 .as_local()
5603 .and_then(|local| {
5604 buffer.update(cx, |buffer, cx| {
5605 local
5606 .language_servers_for_buffer(buffer, cx)
5607 .filter(|(_, server)| {
5608 LinkedEditingRange::check_server_capabilities(server.capabilities())
5609 })
5610 .filter(|(adapter, _)| {
5611 scope
5612 .as_ref()
5613 .map(|scope| scope.language_allowed(&adapter.name))
5614 .unwrap_or(true)
5615 })
5616 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5617 .next()
5618 })
5619 })
5620 .or_else(|| {
5621 self.upstream_client()
5622 .is_some()
5623 .then_some(LanguageServerToQuery::FirstCapable)
5624 })
5625 .filter(|_| {
5626 maybe!({
5627 buffer.read(cx).language_at(position)?;
5628 Some(
5629 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5630 .linked_edits,
5631 )
5632 }) == Some(true)
5633 })
5634 else {
5635 return Task::ready(Ok(Vec::new()));
5636 };
5637
5638 self.request_lsp(
5639 buffer.clone(),
5640 server_id,
5641 LinkedEditingRange { position },
5642 cx,
5643 )
5644 }
5645
5646 fn apply_on_type_formatting(
5647 &mut self,
5648 buffer: Entity<Buffer>,
5649 position: Anchor,
5650 trigger: String,
5651 cx: &mut Context<Self>,
5652 ) -> Task<Result<Option<Transaction>>> {
5653 if let Some((client, project_id)) = self.upstream_client() {
5654 if !self.check_if_capable_for_proto_request(
5655 &buffer,
5656 |capabilities| {
5657 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5658 },
5659 cx,
5660 ) {
5661 return Task::ready(Ok(None));
5662 }
5663 let request = proto::OnTypeFormatting {
5664 project_id,
5665 buffer_id: buffer.read(cx).remote_id().into(),
5666 position: Some(serialize_anchor(&position)),
5667 trigger,
5668 version: serialize_version(&buffer.read(cx).version()),
5669 };
5670 cx.background_spawn(async move {
5671 client
5672 .request(request)
5673 .await?
5674 .transaction
5675 .map(language::proto::deserialize_transaction)
5676 .transpose()
5677 })
5678 } else if let Some(local) = self.as_local_mut() {
5679 let buffer_id = buffer.read(cx).remote_id();
5680 local.buffers_being_formatted.insert(buffer_id);
5681 cx.spawn(async move |this, cx| {
5682 let _cleanup = defer({
5683 let this = this.clone();
5684 let mut cx = cx.clone();
5685 move || {
5686 this.update(&mut cx, |this, _| {
5687 if let Some(local) = this.as_local_mut() {
5688 local.buffers_being_formatted.remove(&buffer_id);
5689 }
5690 })
5691 .ok();
5692 }
5693 });
5694
5695 buffer
5696 .update(cx, |buffer, _| {
5697 buffer.wait_for_edits(Some(position.timestamp()))
5698 })
5699 .await?;
5700 this.update(cx, |this, cx| {
5701 let position = position.to_point_utf16(buffer.read(cx));
5702 this.on_type_format(buffer, position, trigger, false, cx)
5703 })?
5704 .await
5705 })
5706 } else {
5707 Task::ready(Err(anyhow!("No upstream client or local language server")))
5708 }
5709 }
5710
5711 pub fn on_type_format<T: ToPointUtf16>(
5712 &mut self,
5713 buffer: Entity<Buffer>,
5714 position: T,
5715 trigger: String,
5716 push_to_history: bool,
5717 cx: &mut Context<Self>,
5718 ) -> Task<Result<Option<Transaction>>> {
5719 let position = position.to_point_utf16(buffer.read(cx));
5720 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5721 }
5722
5723 fn on_type_format_impl(
5724 &mut self,
5725 buffer: Entity<Buffer>,
5726 position: PointUtf16,
5727 trigger: String,
5728 push_to_history: bool,
5729 cx: &mut Context<Self>,
5730 ) -> Task<Result<Option<Transaction>>> {
5731 let options = buffer.update(cx, |buffer, cx| {
5732 lsp_command::lsp_formatting_options(
5733 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5734 )
5735 });
5736
5737 cx.spawn(async move |this, cx| {
5738 if let Some(waiter) =
5739 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5740 {
5741 waiter.await?;
5742 }
5743 cx.update(|cx| {
5744 this.update(cx, |this, cx| {
5745 this.request_lsp(
5746 buffer.clone(),
5747 LanguageServerToQuery::FirstCapable,
5748 OnTypeFormatting {
5749 position,
5750 trigger,
5751 options,
5752 push_to_history,
5753 },
5754 cx,
5755 )
5756 })
5757 })?
5758 .await
5759 })
5760 }
5761
5762 pub fn definitions(
5763 &mut self,
5764 buffer: &Entity<Buffer>,
5765 position: PointUtf16,
5766 cx: &mut Context<Self>,
5767 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5768 if let Some((upstream_client, project_id)) = self.upstream_client() {
5769 let request = GetDefinitions { position };
5770 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5771 return Task::ready(Ok(None));
5772 }
5773
5774 let request_timeout = ProjectSettings::get_global(cx)
5775 .global_lsp_settings
5776 .get_request_timeout();
5777
5778 let request_task = upstream_client.request_lsp(
5779 project_id,
5780 None,
5781 request_timeout,
5782 cx.background_executor().clone(),
5783 request.to_proto(project_id, buffer.read(cx)),
5784 );
5785 let buffer = buffer.clone();
5786 cx.spawn(async move |weak_lsp_store, cx| {
5787 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5788 return Ok(None);
5789 };
5790 let Some(responses) = request_task.await? else {
5791 return Ok(None);
5792 };
5793 let actions = join_all(responses.payload.into_iter().map(|response| {
5794 GetDefinitions { position }.response_from_proto(
5795 response.response,
5796 lsp_store.clone(),
5797 buffer.clone(),
5798 cx.clone(),
5799 )
5800 }))
5801 .await;
5802
5803 Ok(Some(
5804 actions
5805 .into_iter()
5806 .collect::<Result<Vec<Vec<_>>>>()?
5807 .into_iter()
5808 .flatten()
5809 .dedup()
5810 .collect(),
5811 ))
5812 })
5813 } else {
5814 let definitions_task = self.request_multiple_lsp_locally(
5815 buffer,
5816 Some(position),
5817 GetDefinitions { position },
5818 cx,
5819 );
5820 cx.background_spawn(async move {
5821 Ok(Some(
5822 definitions_task
5823 .await
5824 .into_iter()
5825 .flat_map(|(_, definitions)| definitions)
5826 .dedup()
5827 .collect(),
5828 ))
5829 })
5830 }
5831 }
5832
5833 pub fn declarations(
5834 &mut self,
5835 buffer: &Entity<Buffer>,
5836 position: PointUtf16,
5837 cx: &mut Context<Self>,
5838 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5839 if let Some((upstream_client, project_id)) = self.upstream_client() {
5840 let request = GetDeclarations { position };
5841 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5842 return Task::ready(Ok(None));
5843 }
5844 let request_timeout = ProjectSettings::get_global(cx)
5845 .global_lsp_settings
5846 .get_request_timeout();
5847 let request_task = upstream_client.request_lsp(
5848 project_id,
5849 None,
5850 request_timeout,
5851 cx.background_executor().clone(),
5852 request.to_proto(project_id, buffer.read(cx)),
5853 );
5854 let buffer = buffer.clone();
5855 cx.spawn(async move |weak_lsp_store, cx| {
5856 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5857 return Ok(None);
5858 };
5859 let Some(responses) = request_task.await? else {
5860 return Ok(None);
5861 };
5862 let actions = join_all(responses.payload.into_iter().map(|response| {
5863 GetDeclarations { position }.response_from_proto(
5864 response.response,
5865 lsp_store.clone(),
5866 buffer.clone(),
5867 cx.clone(),
5868 )
5869 }))
5870 .await;
5871
5872 Ok(Some(
5873 actions
5874 .into_iter()
5875 .collect::<Result<Vec<Vec<_>>>>()?
5876 .into_iter()
5877 .flatten()
5878 .dedup()
5879 .collect(),
5880 ))
5881 })
5882 } else {
5883 let declarations_task = self.request_multiple_lsp_locally(
5884 buffer,
5885 Some(position),
5886 GetDeclarations { position },
5887 cx,
5888 );
5889 cx.background_spawn(async move {
5890 Ok(Some(
5891 declarations_task
5892 .await
5893 .into_iter()
5894 .flat_map(|(_, declarations)| declarations)
5895 .dedup()
5896 .collect(),
5897 ))
5898 })
5899 }
5900 }
5901
5902 pub fn type_definitions(
5903 &mut self,
5904 buffer: &Entity<Buffer>,
5905 position: PointUtf16,
5906 cx: &mut Context<Self>,
5907 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5908 if let Some((upstream_client, project_id)) = self.upstream_client() {
5909 let request = GetTypeDefinitions { position };
5910 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5911 return Task::ready(Ok(None));
5912 }
5913 let request_timeout = ProjectSettings::get_global(cx)
5914 .global_lsp_settings
5915 .get_request_timeout();
5916 let request_task = upstream_client.request_lsp(
5917 project_id,
5918 None,
5919 request_timeout,
5920 cx.background_executor().clone(),
5921 request.to_proto(project_id, buffer.read(cx)),
5922 );
5923 let buffer = buffer.clone();
5924 cx.spawn(async move |weak_lsp_store, cx| {
5925 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5926 return Ok(None);
5927 };
5928 let Some(responses) = request_task.await? else {
5929 return Ok(None);
5930 };
5931 let actions = join_all(responses.payload.into_iter().map(|response| {
5932 GetTypeDefinitions { position }.response_from_proto(
5933 response.response,
5934 lsp_store.clone(),
5935 buffer.clone(),
5936 cx.clone(),
5937 )
5938 }))
5939 .await;
5940
5941 Ok(Some(
5942 actions
5943 .into_iter()
5944 .collect::<Result<Vec<Vec<_>>>>()?
5945 .into_iter()
5946 .flatten()
5947 .dedup()
5948 .collect(),
5949 ))
5950 })
5951 } else {
5952 let type_definitions_task = self.request_multiple_lsp_locally(
5953 buffer,
5954 Some(position),
5955 GetTypeDefinitions { position },
5956 cx,
5957 );
5958 cx.background_spawn(async move {
5959 Ok(Some(
5960 type_definitions_task
5961 .await
5962 .into_iter()
5963 .flat_map(|(_, type_definitions)| type_definitions)
5964 .dedup()
5965 .collect(),
5966 ))
5967 })
5968 }
5969 }
5970
5971 pub fn implementations(
5972 &mut self,
5973 buffer: &Entity<Buffer>,
5974 position: PointUtf16,
5975 cx: &mut Context<Self>,
5976 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5977 if let Some((upstream_client, project_id)) = self.upstream_client() {
5978 let request = GetImplementations { position };
5979 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5980 return Task::ready(Ok(None));
5981 }
5982
5983 let request_timeout = ProjectSettings::get_global(cx)
5984 .global_lsp_settings
5985 .get_request_timeout();
5986 let request_task = upstream_client.request_lsp(
5987 project_id,
5988 None,
5989 request_timeout,
5990 cx.background_executor().clone(),
5991 request.to_proto(project_id, buffer.read(cx)),
5992 );
5993 let buffer = buffer.clone();
5994 cx.spawn(async move |weak_lsp_store, cx| {
5995 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5996 return Ok(None);
5997 };
5998 let Some(responses) = request_task.await? else {
5999 return Ok(None);
6000 };
6001 let actions = join_all(responses.payload.into_iter().map(|response| {
6002 GetImplementations { position }.response_from_proto(
6003 response.response,
6004 lsp_store.clone(),
6005 buffer.clone(),
6006 cx.clone(),
6007 )
6008 }))
6009 .await;
6010
6011 Ok(Some(
6012 actions
6013 .into_iter()
6014 .collect::<Result<Vec<Vec<_>>>>()?
6015 .into_iter()
6016 .flatten()
6017 .dedup()
6018 .collect(),
6019 ))
6020 })
6021 } else {
6022 let implementations_task = self.request_multiple_lsp_locally(
6023 buffer,
6024 Some(position),
6025 GetImplementations { position },
6026 cx,
6027 );
6028 cx.background_spawn(async move {
6029 Ok(Some(
6030 implementations_task
6031 .await
6032 .into_iter()
6033 .flat_map(|(_, implementations)| implementations)
6034 .dedup()
6035 .collect(),
6036 ))
6037 })
6038 }
6039 }
6040
6041 pub fn references(
6042 &mut self,
6043 buffer: &Entity<Buffer>,
6044 position: PointUtf16,
6045 cx: &mut Context<Self>,
6046 ) -> Task<Result<Option<Vec<Location>>>> {
6047 if let Some((upstream_client, project_id)) = self.upstream_client() {
6048 let request = GetReferences { position };
6049 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6050 return Task::ready(Ok(None));
6051 }
6052
6053 let request_timeout = ProjectSettings::get_global(cx)
6054 .global_lsp_settings
6055 .get_request_timeout();
6056 let request_task = upstream_client.request_lsp(
6057 project_id,
6058 None,
6059 request_timeout,
6060 cx.background_executor().clone(),
6061 request.to_proto(project_id, buffer.read(cx)),
6062 );
6063 let buffer = buffer.clone();
6064 cx.spawn(async move |weak_lsp_store, cx| {
6065 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6066 return Ok(None);
6067 };
6068 let Some(responses) = request_task.await? else {
6069 return Ok(None);
6070 };
6071
6072 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6073 GetReferences { position }.response_from_proto(
6074 lsp_response.response,
6075 lsp_store.clone(),
6076 buffer.clone(),
6077 cx.clone(),
6078 )
6079 }))
6080 .await
6081 .into_iter()
6082 .collect::<Result<Vec<Vec<_>>>>()?
6083 .into_iter()
6084 .flatten()
6085 .dedup()
6086 .collect();
6087 Ok(Some(locations))
6088 })
6089 } else {
6090 let references_task = self.request_multiple_lsp_locally(
6091 buffer,
6092 Some(position),
6093 GetReferences { position },
6094 cx,
6095 );
6096 cx.background_spawn(async move {
6097 Ok(Some(
6098 references_task
6099 .await
6100 .into_iter()
6101 .flat_map(|(_, references)| references)
6102 .dedup()
6103 .collect(),
6104 ))
6105 })
6106 }
6107 }
6108
6109 pub fn code_actions(
6110 &mut self,
6111 buffer: &Entity<Buffer>,
6112 range: Range<Anchor>,
6113 kinds: Option<Vec<CodeActionKind>>,
6114 cx: &mut Context<Self>,
6115 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6116 if let Some((upstream_client, project_id)) = self.upstream_client() {
6117 let request = GetCodeActions {
6118 range: range.clone(),
6119 kinds: kinds.clone(),
6120 };
6121 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6122 return Task::ready(Ok(None));
6123 }
6124 let request_timeout = ProjectSettings::get_global(cx)
6125 .global_lsp_settings
6126 .get_request_timeout();
6127 let request_task = upstream_client.request_lsp(
6128 project_id,
6129 None,
6130 request_timeout,
6131 cx.background_executor().clone(),
6132 request.to_proto(project_id, buffer.read(cx)),
6133 );
6134 let buffer = buffer.clone();
6135 cx.spawn(async move |weak_lsp_store, cx| {
6136 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6137 return Ok(None);
6138 };
6139 let Some(responses) = request_task.await? else {
6140 return Ok(None);
6141 };
6142 let actions = join_all(responses.payload.into_iter().map(|response| {
6143 GetCodeActions {
6144 range: range.clone(),
6145 kinds: kinds.clone(),
6146 }
6147 .response_from_proto(
6148 response.response,
6149 lsp_store.clone(),
6150 buffer.clone(),
6151 cx.clone(),
6152 )
6153 }))
6154 .await;
6155
6156 Ok(Some(
6157 actions
6158 .into_iter()
6159 .collect::<Result<Vec<Vec<_>>>>()?
6160 .into_iter()
6161 .flatten()
6162 .collect(),
6163 ))
6164 })
6165 } else {
6166 let all_actions_task = self.request_multiple_lsp_locally(
6167 buffer,
6168 Some(range.start),
6169 GetCodeActions { range, kinds },
6170 cx,
6171 );
6172 cx.background_spawn(async move {
6173 Ok(Some(
6174 all_actions_task
6175 .await
6176 .into_iter()
6177 .flat_map(|(_, actions)| actions)
6178 .collect(),
6179 ))
6180 })
6181 }
6182 }
6183
6184 #[inline(never)]
6185 pub fn completions(
6186 &self,
6187 buffer: &Entity<Buffer>,
6188 position: PointUtf16,
6189 context: CompletionContext,
6190 cx: &mut Context<Self>,
6191 ) -> Task<Result<Vec<CompletionResponse>>> {
6192 let language_registry = self.languages.clone();
6193
6194 if let Some((upstream_client, project_id)) = self.upstream_client() {
6195 let snapshot = buffer.read(cx).snapshot();
6196 let offset = position.to_offset(&snapshot);
6197 let scope = snapshot.language_scope_at(offset);
6198 let capable_lsps = self.all_capable_for_proto_request(
6199 buffer,
6200 |server_name, capabilities| {
6201 capabilities.completion_provider.is_some()
6202 && scope
6203 .as_ref()
6204 .map(|scope| scope.language_allowed(server_name))
6205 .unwrap_or(true)
6206 },
6207 cx,
6208 );
6209 if capable_lsps.is_empty() {
6210 return Task::ready(Ok(Vec::new()));
6211 }
6212
6213 let language = buffer.read(cx).language().cloned();
6214
6215 let buffer = buffer.clone();
6216
6217 cx.spawn(async move |this, cx| {
6218 let requests = join_all(
6219 capable_lsps
6220 .into_iter()
6221 .map(|(id, server_name)| {
6222 let request = GetCompletions {
6223 position,
6224 context: context.clone(),
6225 server_id: Some(id),
6226 };
6227 let buffer = buffer.clone();
6228 let language = language.clone();
6229 let lsp_adapter = language.as_ref().and_then(|language| {
6230 let adapters = language_registry.lsp_adapters(&language.name());
6231 adapters
6232 .iter()
6233 .find(|adapter| adapter.name() == server_name)
6234 .or_else(|| adapters.first())
6235 .cloned()
6236 });
6237 let upstream_client = upstream_client.clone();
6238 let response = this
6239 .update(cx, |this, cx| {
6240 this.send_lsp_proto_request(
6241 buffer,
6242 upstream_client,
6243 project_id,
6244 request,
6245 cx,
6246 )
6247 })
6248 .log_err();
6249 async move {
6250 let response = response?.await.log_err()?;
6251
6252 let completions = populate_labels_for_completions(
6253 response.completions,
6254 language,
6255 lsp_adapter,
6256 )
6257 .await;
6258
6259 Some(CompletionResponse {
6260 completions,
6261 display_options: CompletionDisplayOptions::default(),
6262 is_incomplete: response.is_incomplete,
6263 })
6264 }
6265 })
6266 .collect::<Vec<_>>(),
6267 );
6268 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6269 })
6270 } else if let Some(local) = self.as_local() {
6271 let snapshot = buffer.read(cx).snapshot();
6272 let offset = position.to_offset(&snapshot);
6273 let scope = snapshot.language_scope_at(offset);
6274 let language = snapshot.language().cloned();
6275 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6276 .completions
6277 .clone();
6278 if !completion_settings.lsp {
6279 return Task::ready(Ok(Vec::new()));
6280 }
6281
6282 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6283 local
6284 .language_servers_for_buffer(buffer, cx)
6285 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6286 .filter(|(adapter, _)| {
6287 scope
6288 .as_ref()
6289 .map(|scope| scope.language_allowed(&adapter.name))
6290 .unwrap_or(true)
6291 })
6292 .map(|(_, server)| server.server_id())
6293 .collect()
6294 });
6295
6296 let buffer = buffer.clone();
6297 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6298 let lsp_timeout = if lsp_timeout > 0 {
6299 Some(Duration::from_millis(lsp_timeout))
6300 } else {
6301 None
6302 };
6303 cx.spawn(async move |this, cx| {
6304 let mut tasks = Vec::with_capacity(server_ids.len());
6305 this.update(cx, |lsp_store, cx| {
6306 for server_id in server_ids {
6307 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6308 let lsp_timeout = lsp_timeout
6309 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6310 let mut timeout = cx.background_spawn(async move {
6311 match lsp_timeout {
6312 Some(lsp_timeout) => {
6313 lsp_timeout.await;
6314 true
6315 },
6316 None => false,
6317 }
6318 }).fuse();
6319 let mut lsp_request = lsp_store.request_lsp(
6320 buffer.clone(),
6321 LanguageServerToQuery::Other(server_id),
6322 GetCompletions {
6323 position,
6324 context: context.clone(),
6325 server_id: Some(server_id),
6326 },
6327 cx,
6328 ).fuse();
6329 let new_task = cx.background_spawn(async move {
6330 select_biased! {
6331 response = lsp_request => anyhow::Ok(Some(response?)),
6332 timeout_happened = timeout => {
6333 if timeout_happened {
6334 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6335 Ok(None)
6336 } else {
6337 let completions = lsp_request.await?;
6338 Ok(Some(completions))
6339 }
6340 },
6341 }
6342 });
6343 tasks.push((lsp_adapter, new_task));
6344 }
6345 })?;
6346
6347 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6348 let completion_response = task.await.ok()??;
6349 let completions = populate_labels_for_completions(
6350 completion_response.completions,
6351 language.clone(),
6352 lsp_adapter,
6353 )
6354 .await;
6355 Some(CompletionResponse {
6356 completions,
6357 display_options: CompletionDisplayOptions::default(),
6358 is_incomplete: completion_response.is_incomplete,
6359 })
6360 });
6361
6362 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6363
6364 Ok(responses.into_iter().flatten().collect())
6365 })
6366 } else {
6367 Task::ready(Err(anyhow!("No upstream client or local language server")))
6368 }
6369 }
6370
6371 pub fn resolve_completions(
6372 &self,
6373 buffer: Entity<Buffer>,
6374 completion_indices: Vec<usize>,
6375 completions: Rc<RefCell<Box<[Completion]>>>,
6376 cx: &mut Context<Self>,
6377 ) -> Task<Result<bool>> {
6378 let client = self.upstream_client();
6379 let buffer_id = buffer.read(cx).remote_id();
6380 let buffer_snapshot = buffer.read(cx).snapshot();
6381
6382 if !self.check_if_capable_for_proto_request(
6383 &buffer,
6384 GetCompletions::can_resolve_completions,
6385 cx,
6386 ) {
6387 return Task::ready(Ok(false));
6388 }
6389 cx.spawn(async move |lsp_store, cx| {
6390 let request_timeout = cx.update(|app| {
6391 ProjectSettings::get_global(app)
6392 .global_lsp_settings
6393 .get_request_timeout()
6394 });
6395
6396 let mut did_resolve = false;
6397 if let Some((client, project_id)) = client {
6398 for completion_index in completion_indices {
6399 let server_id = {
6400 let completion = &completions.borrow()[completion_index];
6401 completion.source.server_id()
6402 };
6403 if let Some(server_id) = server_id {
6404 if Self::resolve_completion_remote(
6405 project_id,
6406 server_id,
6407 buffer_id,
6408 completions.clone(),
6409 completion_index,
6410 client.clone(),
6411 )
6412 .await
6413 .log_err()
6414 .is_some()
6415 {
6416 did_resolve = true;
6417 }
6418 } else {
6419 resolve_word_completion(
6420 &buffer_snapshot,
6421 &mut completions.borrow_mut()[completion_index],
6422 );
6423 }
6424 }
6425 } else {
6426 for completion_index in completion_indices {
6427 let server_id = {
6428 let completion = &completions.borrow()[completion_index];
6429 completion.source.server_id()
6430 };
6431 if let Some(server_id) = server_id {
6432 let server_and_adapter = lsp_store
6433 .read_with(cx, |lsp_store, _| {
6434 let server = lsp_store.language_server_for_id(server_id)?;
6435 let adapter =
6436 lsp_store.language_server_adapter_for_id(server.server_id())?;
6437 Some((server, adapter))
6438 })
6439 .ok()
6440 .flatten();
6441 let Some((server, adapter)) = server_and_adapter else {
6442 continue;
6443 };
6444
6445 let resolved = Self::resolve_completion_local(
6446 server,
6447 completions.clone(),
6448 completion_index,
6449 request_timeout,
6450 )
6451 .await
6452 .log_err()
6453 .is_some();
6454 if resolved {
6455 Self::regenerate_completion_labels(
6456 adapter,
6457 &buffer_snapshot,
6458 completions.clone(),
6459 completion_index,
6460 )
6461 .await
6462 .log_err();
6463 did_resolve = true;
6464 }
6465 } else {
6466 resolve_word_completion(
6467 &buffer_snapshot,
6468 &mut completions.borrow_mut()[completion_index],
6469 );
6470 }
6471 }
6472 }
6473
6474 Ok(did_resolve)
6475 })
6476 }
6477
6478 async fn resolve_completion_local(
6479 server: Arc<lsp::LanguageServer>,
6480 completions: Rc<RefCell<Box<[Completion]>>>,
6481 completion_index: usize,
6482 request_timeout: Duration,
6483 ) -> Result<()> {
6484 let server_id = server.server_id();
6485 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6486 return Ok(());
6487 }
6488
6489 let request = {
6490 let completion = &completions.borrow()[completion_index];
6491 match &completion.source {
6492 CompletionSource::Lsp {
6493 lsp_completion,
6494 resolved,
6495 server_id: completion_server_id,
6496 ..
6497 } => {
6498 if *resolved {
6499 return Ok(());
6500 }
6501 anyhow::ensure!(
6502 server_id == *completion_server_id,
6503 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6504 );
6505 server.request::<lsp::request::ResolveCompletionItem>(
6506 *lsp_completion.clone(),
6507 request_timeout,
6508 )
6509 }
6510 CompletionSource::BufferWord { .. }
6511 | CompletionSource::Dap { .. }
6512 | CompletionSource::Custom => {
6513 return Ok(());
6514 }
6515 }
6516 };
6517 let resolved_completion = request
6518 .await
6519 .into_response()
6520 .context("resolve completion")?;
6521
6522 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6523 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6524
6525 let mut completions = completions.borrow_mut();
6526 let completion = &mut completions[completion_index];
6527 if let CompletionSource::Lsp {
6528 lsp_completion,
6529 resolved,
6530 server_id: completion_server_id,
6531 ..
6532 } = &mut completion.source
6533 {
6534 if *resolved {
6535 return Ok(());
6536 }
6537 anyhow::ensure!(
6538 server_id == *completion_server_id,
6539 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6540 );
6541 **lsp_completion = resolved_completion;
6542 *resolved = true;
6543 }
6544 Ok(())
6545 }
6546
6547 async fn regenerate_completion_labels(
6548 adapter: Arc<CachedLspAdapter>,
6549 snapshot: &BufferSnapshot,
6550 completions: Rc<RefCell<Box<[Completion]>>>,
6551 completion_index: usize,
6552 ) -> Result<()> {
6553 let completion_item = completions.borrow()[completion_index]
6554 .source
6555 .lsp_completion(true)
6556 .map(Cow::into_owned);
6557 if let Some(lsp_documentation) = completion_item
6558 .as_ref()
6559 .and_then(|completion_item| completion_item.documentation.clone())
6560 {
6561 let mut completions = completions.borrow_mut();
6562 let completion = &mut completions[completion_index];
6563 completion.documentation = Some(lsp_documentation.into());
6564 } else {
6565 let mut completions = completions.borrow_mut();
6566 let completion = &mut completions[completion_index];
6567 completion.documentation = Some(CompletionDocumentation::Undocumented);
6568 }
6569
6570 let mut new_label = match completion_item {
6571 Some(completion_item) => {
6572 // Some language servers always return `detail` lazily via resolve, regardless of
6573 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6574 // See: https://github.com/yioneko/vtsls/issues/213
6575 let language = snapshot.language();
6576 match language {
6577 Some(language) => {
6578 adapter
6579 .labels_for_completions(
6580 std::slice::from_ref(&completion_item),
6581 language,
6582 )
6583 .await?
6584 }
6585 None => Vec::new(),
6586 }
6587 .pop()
6588 .flatten()
6589 .unwrap_or_else(|| {
6590 CodeLabel::fallback_for_completion(
6591 &completion_item,
6592 language.map(|language| language.as_ref()),
6593 )
6594 })
6595 }
6596 None => CodeLabel::plain(
6597 completions.borrow()[completion_index].new_text.clone(),
6598 None,
6599 ),
6600 };
6601 ensure_uniform_list_compatible_label(&mut new_label);
6602
6603 let mut completions = completions.borrow_mut();
6604 let completion = &mut completions[completion_index];
6605 if completion.label.filter_text() == new_label.filter_text() {
6606 completion.label = new_label;
6607 } else {
6608 log::error!(
6609 "Resolved completion changed display label from {} to {}. \
6610 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6611 completion.label.text(),
6612 new_label.text(),
6613 completion.label.filter_text(),
6614 new_label.filter_text()
6615 );
6616 }
6617
6618 Ok(())
6619 }
6620
6621 async fn resolve_completion_remote(
6622 project_id: u64,
6623 server_id: LanguageServerId,
6624 buffer_id: BufferId,
6625 completions: Rc<RefCell<Box<[Completion]>>>,
6626 completion_index: usize,
6627 client: AnyProtoClient,
6628 ) -> Result<()> {
6629 let lsp_completion = {
6630 let completion = &completions.borrow()[completion_index];
6631 match &completion.source {
6632 CompletionSource::Lsp {
6633 lsp_completion,
6634 resolved,
6635 server_id: completion_server_id,
6636 ..
6637 } => {
6638 anyhow::ensure!(
6639 server_id == *completion_server_id,
6640 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6641 );
6642 if *resolved {
6643 return Ok(());
6644 }
6645 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6646 }
6647 CompletionSource::Custom
6648 | CompletionSource::Dap { .. }
6649 | CompletionSource::BufferWord { .. } => {
6650 return Ok(());
6651 }
6652 }
6653 };
6654 let request = proto::ResolveCompletionDocumentation {
6655 project_id,
6656 language_server_id: server_id.0 as u64,
6657 lsp_completion,
6658 buffer_id: buffer_id.into(),
6659 };
6660
6661 let response = client
6662 .request(request)
6663 .await
6664 .context("completion documentation resolve proto request")?;
6665 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6666
6667 let documentation = if response.documentation.is_empty() {
6668 CompletionDocumentation::Undocumented
6669 } else if response.documentation_is_markdown {
6670 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6671 } else if response.documentation.lines().count() <= 1 {
6672 CompletionDocumentation::SingleLine(response.documentation.into())
6673 } else {
6674 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6675 };
6676
6677 let mut completions = completions.borrow_mut();
6678 let completion = &mut completions[completion_index];
6679 completion.documentation = Some(documentation);
6680 if let CompletionSource::Lsp {
6681 insert_range,
6682 lsp_completion,
6683 resolved,
6684 server_id: completion_server_id,
6685 lsp_defaults: _,
6686 } = &mut completion.source
6687 {
6688 let completion_insert_range = response
6689 .old_insert_start
6690 .and_then(deserialize_anchor)
6691 .zip(response.old_insert_end.and_then(deserialize_anchor));
6692 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6693
6694 if *resolved {
6695 return Ok(());
6696 }
6697 anyhow::ensure!(
6698 server_id == *completion_server_id,
6699 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6700 );
6701 **lsp_completion = resolved_lsp_completion;
6702 *resolved = true;
6703 }
6704
6705 let replace_range = response
6706 .old_replace_start
6707 .and_then(deserialize_anchor)
6708 .zip(response.old_replace_end.and_then(deserialize_anchor));
6709 if let Some((old_replace_start, old_replace_end)) = replace_range
6710 && !response.new_text.is_empty()
6711 {
6712 completion.new_text = response.new_text;
6713 completion.replace_range = old_replace_start..old_replace_end;
6714 }
6715
6716 Ok(())
6717 }
6718
6719 pub fn apply_additional_edits_for_completion(
6720 &self,
6721 buffer_handle: Entity<Buffer>,
6722 completions: Rc<RefCell<Box<[Completion]>>>,
6723 completion_index: usize,
6724 push_to_history: bool,
6725 all_commit_ranges: Vec<Range<language::Anchor>>,
6726 cx: &mut Context<Self>,
6727 ) -> Task<Result<Option<Transaction>>> {
6728 if let Some((client, project_id)) = self.upstream_client() {
6729 let buffer = buffer_handle.read(cx);
6730 let buffer_id = buffer.remote_id();
6731 cx.spawn(async move |_, cx| {
6732 let request = {
6733 let completion = completions.borrow()[completion_index].clone();
6734 proto::ApplyCompletionAdditionalEdits {
6735 project_id,
6736 buffer_id: buffer_id.into(),
6737 completion: Some(Self::serialize_completion(&CoreCompletion {
6738 replace_range: completion.replace_range,
6739 new_text: completion.new_text,
6740 source: completion.source,
6741 })),
6742 all_commit_ranges: all_commit_ranges
6743 .iter()
6744 .cloned()
6745 .map(language::proto::serialize_anchor_range)
6746 .collect(),
6747 }
6748 };
6749
6750 let Some(transaction) = client.request(request).await?.transaction else {
6751 return Ok(None);
6752 };
6753
6754 let transaction = language::proto::deserialize_transaction(transaction)?;
6755 buffer_handle
6756 .update(cx, |buffer, _| {
6757 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6758 })
6759 .await?;
6760 if push_to_history {
6761 buffer_handle.update(cx, |buffer, _| {
6762 buffer.push_transaction(transaction.clone(), Instant::now());
6763 buffer.finalize_last_transaction();
6764 });
6765 }
6766 Ok(Some(transaction))
6767 })
6768 } else {
6769 let request_timeout = ProjectSettings::get_global(cx)
6770 .global_lsp_settings
6771 .get_request_timeout();
6772
6773 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6774 let completion = &completions.borrow()[completion_index];
6775 let server_id = completion.source.server_id()?;
6776 Some(
6777 self.language_server_for_local_buffer(buffer, server_id, cx)?
6778 .1
6779 .clone(),
6780 )
6781 }) else {
6782 return Task::ready(Ok(None));
6783 };
6784
6785 cx.spawn(async move |this, cx| {
6786 Self::resolve_completion_local(
6787 server.clone(),
6788 completions.clone(),
6789 completion_index,
6790 request_timeout,
6791 )
6792 .await
6793 .context("resolving completion")?;
6794 let completion = completions.borrow()[completion_index].clone();
6795 let additional_text_edits = completion
6796 .source
6797 .lsp_completion(true)
6798 .as_ref()
6799 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6800 if let Some(edits) = additional_text_edits {
6801 let edits = this
6802 .update(cx, |this, cx| {
6803 this.as_local_mut().unwrap().edits_from_lsp(
6804 &buffer_handle,
6805 edits,
6806 server.server_id(),
6807 None,
6808 cx,
6809 )
6810 })?
6811 .await?;
6812
6813 buffer_handle.update(cx, |buffer, cx| {
6814 buffer.finalize_last_transaction();
6815 buffer.start_transaction();
6816
6817 for (range, text) in edits {
6818 let primary = &completion.replace_range;
6819
6820 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6821 // and the primary completion is just an insertion (empty range), then this is likely
6822 // an auto-import scenario and should not be considered overlapping
6823 // https://github.com/zed-industries/zed/issues/26136
6824 let is_file_start_auto_import = {
6825 let snapshot = buffer.snapshot();
6826 let primary_start_point = primary.start.to_point(&snapshot);
6827 let range_start_point = range.start.to_point(&snapshot);
6828
6829 let result = primary_start_point.row == 0
6830 && primary_start_point.column == 0
6831 && range_start_point.row == 0
6832 && range_start_point.column == 0;
6833
6834 result
6835 };
6836
6837 let has_overlap = if is_file_start_auto_import {
6838 false
6839 } else {
6840 all_commit_ranges.iter().any(|commit_range| {
6841 let start_within =
6842 commit_range.start.cmp(&range.start, buffer).is_le()
6843 && commit_range.end.cmp(&range.start, buffer).is_ge();
6844 let end_within =
6845 range.start.cmp(&commit_range.end, buffer).is_le()
6846 && range.end.cmp(&commit_range.end, buffer).is_ge();
6847 start_within || end_within
6848 })
6849 };
6850
6851 //Skip additional edits which overlap with the primary completion edit
6852 //https://github.com/zed-industries/zed/pull/1871
6853 if !has_overlap {
6854 buffer.edit([(range, text)], None, cx);
6855 }
6856 }
6857
6858 let transaction = if buffer.end_transaction(cx).is_some() {
6859 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6860 if !push_to_history {
6861 buffer.forget_transaction(transaction.id);
6862 }
6863 Some(transaction)
6864 } else {
6865 None
6866 };
6867 Ok(transaction)
6868 })
6869 } else {
6870 Ok(None)
6871 }
6872 })
6873 }
6874 }
6875
6876 pub fn pull_diagnostics(
6877 &mut self,
6878 buffer: Entity<Buffer>,
6879 cx: &mut Context<Self>,
6880 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6881 let buffer_id = buffer.read(cx).remote_id();
6882
6883 if let Some((client, upstream_project_id)) = self.upstream_client() {
6884 let mut suitable_capabilities = None;
6885 // Are we capable for proto request?
6886 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6887 &buffer,
6888 |capabilities| {
6889 if let Some(caps) = &capabilities.diagnostic_provider {
6890 suitable_capabilities = Some(caps.clone());
6891 true
6892 } else {
6893 false
6894 }
6895 },
6896 cx,
6897 );
6898 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6899 let Some(dynamic_caps) = suitable_capabilities else {
6900 return Task::ready(Ok(None));
6901 };
6902 assert!(any_server_has_diagnostics_provider);
6903
6904 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6905 let request = GetDocumentDiagnostics {
6906 previous_result_id: None,
6907 identifier,
6908 registration_id: None,
6909 };
6910 let request_timeout = ProjectSettings::get_global(cx)
6911 .global_lsp_settings
6912 .get_request_timeout();
6913 let request_task = client.request_lsp(
6914 upstream_project_id,
6915 None,
6916 request_timeout,
6917 cx.background_executor().clone(),
6918 request.to_proto(upstream_project_id, buffer.read(cx)),
6919 );
6920 cx.background_spawn(async move {
6921 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6922 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6923 // Do not attempt to further process the dummy responses here.
6924 let _response = request_task.await?;
6925 Ok(None)
6926 })
6927 } else {
6928 let servers = buffer.update(cx, |buffer, cx| {
6929 self.running_language_servers_for_local_buffer(buffer, cx)
6930 .map(|(_, server)| server.clone())
6931 .collect::<Vec<_>>()
6932 });
6933
6934 let pull_diagnostics = servers
6935 .into_iter()
6936 .flat_map(|server| {
6937 let result = maybe!({
6938 let local = self.as_local()?;
6939 let server_id = server.server_id();
6940 let providers_with_identifiers = local
6941 .language_server_dynamic_registrations
6942 .get(&server_id)
6943 .into_iter()
6944 .flat_map(|registrations| registrations.diagnostics.clone())
6945 .collect::<Vec<_>>();
6946 Some(
6947 providers_with_identifiers
6948 .into_iter()
6949 .map(|(registration_id, dynamic_caps)| {
6950 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6951 let registration_id = registration_id.map(SharedString::from);
6952 let result_id = self.result_id_for_buffer_pull(
6953 server_id,
6954 buffer_id,
6955 ®istration_id,
6956 cx,
6957 );
6958 self.request_lsp(
6959 buffer.clone(),
6960 LanguageServerToQuery::Other(server_id),
6961 GetDocumentDiagnostics {
6962 previous_result_id: result_id,
6963 registration_id,
6964 identifier,
6965 },
6966 cx,
6967 )
6968 })
6969 .collect::<Vec<_>>(),
6970 )
6971 });
6972
6973 result.unwrap_or_default()
6974 })
6975 .collect::<Vec<_>>();
6976
6977 cx.background_spawn(async move {
6978 let mut responses = Vec::new();
6979 for diagnostics in join_all(pull_diagnostics).await {
6980 responses.extend(diagnostics?);
6981 }
6982 Ok(Some(responses))
6983 })
6984 }
6985 }
6986
6987 pub fn applicable_inlay_chunks(
6988 &mut self,
6989 buffer: &Entity<Buffer>,
6990 ranges: &[Range<text::Anchor>],
6991 cx: &mut Context<Self>,
6992 ) -> Vec<Range<BufferRow>> {
6993 let buffer_snapshot = buffer.read(cx).snapshot();
6994 let ranges = ranges
6995 .iter()
6996 .map(|range| range.to_point(&buffer_snapshot))
6997 .collect::<Vec<_>>();
6998
6999 self.latest_lsp_data(buffer, cx)
7000 .inlay_hints
7001 .applicable_chunks(ranges.as_slice())
7002 .map(|chunk| chunk.row_range())
7003 .collect()
7004 }
7005
7006 pub fn invalidate_inlay_hints<'a>(
7007 &'a mut self,
7008 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7009 ) {
7010 for buffer_id in for_buffers {
7011 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7012 lsp_data.inlay_hints.clear();
7013 }
7014 }
7015 }
7016
7017 pub fn inlay_hints(
7018 &mut self,
7019 invalidate: InvalidationStrategy,
7020 buffer: Entity<Buffer>,
7021 ranges: Vec<Range<text::Anchor>>,
7022 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7023 cx: &mut Context<Self>,
7024 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7025 let next_hint_id = self.next_hint_id.clone();
7026 let lsp_data = self.latest_lsp_data(&buffer, cx);
7027 let query_version = lsp_data.buffer_version.clone();
7028 let mut lsp_refresh_requested = false;
7029 let for_server = if let InvalidationStrategy::RefreshRequested {
7030 server_id,
7031 request_id,
7032 } = invalidate
7033 {
7034 let invalidated = lsp_data
7035 .inlay_hints
7036 .invalidate_for_server_refresh(server_id, request_id);
7037 lsp_refresh_requested = invalidated;
7038 Some(server_id)
7039 } else {
7040 None
7041 };
7042 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7043 let known_chunks = known_chunks
7044 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7045 .map(|(_, known_chunks)| known_chunks)
7046 .unwrap_or_default();
7047
7048 let buffer_snapshot = buffer.read(cx).snapshot();
7049 let ranges = ranges
7050 .iter()
7051 .map(|range| range.to_point(&buffer_snapshot))
7052 .collect::<Vec<_>>();
7053
7054 let mut hint_fetch_tasks = Vec::new();
7055 let mut cached_inlay_hints = None;
7056 let mut ranges_to_query = None;
7057 let applicable_chunks = existing_inlay_hints
7058 .applicable_chunks(ranges.as_slice())
7059 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7060 .collect::<Vec<_>>();
7061 if applicable_chunks.is_empty() {
7062 return HashMap::default();
7063 }
7064
7065 for row_chunk in applicable_chunks {
7066 match (
7067 existing_inlay_hints
7068 .cached_hints(&row_chunk)
7069 .filter(|_| !lsp_refresh_requested)
7070 .cloned(),
7071 existing_inlay_hints
7072 .fetched_hints(&row_chunk)
7073 .as_ref()
7074 .filter(|_| !lsp_refresh_requested)
7075 .cloned(),
7076 ) {
7077 (None, None) => {
7078 let chunk_range = row_chunk.anchor_range();
7079 ranges_to_query
7080 .get_or_insert_with(Vec::new)
7081 .push((row_chunk, chunk_range));
7082 }
7083 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7084 (Some(cached_hints), None) => {
7085 for (server_id, cached_hints) in cached_hints {
7086 if for_server.is_none_or(|for_server| for_server == server_id) {
7087 cached_inlay_hints
7088 .get_or_insert_with(HashMap::default)
7089 .entry(row_chunk.row_range())
7090 .or_insert_with(HashMap::default)
7091 .entry(server_id)
7092 .or_insert_with(Vec::new)
7093 .extend(cached_hints);
7094 }
7095 }
7096 }
7097 (Some(cached_hints), Some(fetched_hints)) => {
7098 hint_fetch_tasks.push((row_chunk, fetched_hints));
7099 for (server_id, cached_hints) in cached_hints {
7100 if for_server.is_none_or(|for_server| for_server == server_id) {
7101 cached_inlay_hints
7102 .get_or_insert_with(HashMap::default)
7103 .entry(row_chunk.row_range())
7104 .or_insert_with(HashMap::default)
7105 .entry(server_id)
7106 .or_insert_with(Vec::new)
7107 .extend(cached_hints);
7108 }
7109 }
7110 }
7111 }
7112 }
7113
7114 if hint_fetch_tasks.is_empty()
7115 && ranges_to_query
7116 .as_ref()
7117 .is_none_or(|ranges| ranges.is_empty())
7118 && let Some(cached_inlay_hints) = cached_inlay_hints
7119 {
7120 cached_inlay_hints
7121 .into_iter()
7122 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7123 .collect()
7124 } else {
7125 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7126 // When a server refresh was requested, other servers' cached hints
7127 // are unaffected by the refresh and must be included in the result.
7128 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7129 // removes all visible hints but only adds back the requesting
7130 // server's new hints, permanently losing other servers' hints.
7131 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7132 lsp_data
7133 .inlay_hints
7134 .cached_hints(&chunk)
7135 .cloned()
7136 .unwrap_or_default()
7137 } else {
7138 HashMap::default()
7139 };
7140
7141 let next_hint_id = next_hint_id.clone();
7142 let buffer = buffer.clone();
7143 let query_version = query_version.clone();
7144 let new_inlay_hints = cx
7145 .spawn(async move |lsp_store, cx| {
7146 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7147 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7148 })?;
7149 new_fetch_task
7150 .await
7151 .and_then(|new_hints_by_server| {
7152 lsp_store.update(cx, |lsp_store, cx| {
7153 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7154 let update_cache = lsp_data.buffer_version == query_version;
7155 if new_hints_by_server.is_empty() {
7156 if update_cache {
7157 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7158 }
7159 other_servers_cached
7160 } else {
7161 let mut result = other_servers_cached;
7162 for (server_id, new_hints) in new_hints_by_server {
7163 let new_hints = new_hints
7164 .into_iter()
7165 .map(|new_hint| {
7166 (
7167 InlayId::Hint(next_hint_id.fetch_add(
7168 1,
7169 atomic::Ordering::AcqRel,
7170 )),
7171 new_hint,
7172 )
7173 })
7174 .collect::<Vec<_>>();
7175 if update_cache {
7176 lsp_data.inlay_hints.insert_new_hints(
7177 chunk,
7178 server_id,
7179 new_hints.clone(),
7180 );
7181 }
7182 result.insert(server_id, new_hints);
7183 }
7184 result
7185 }
7186 })
7187 })
7188 .map_err(Arc::new)
7189 })
7190 .shared();
7191
7192 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7193 *fetch_task = Some(new_inlay_hints.clone());
7194 hint_fetch_tasks.push((chunk, new_inlay_hints));
7195 }
7196
7197 cached_inlay_hints
7198 .unwrap_or_default()
7199 .into_iter()
7200 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7201 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7202 (
7203 chunk.row_range(),
7204 cx.spawn(async move |_, _| {
7205 hints_fetch.await.map_err(|e| {
7206 if e.error_code() != ErrorCode::Internal {
7207 anyhow!(e.error_code())
7208 } else {
7209 anyhow!("{e:#}")
7210 }
7211 })
7212 }),
7213 )
7214 }))
7215 .collect()
7216 }
7217 }
7218
7219 fn fetch_inlay_hints(
7220 &mut self,
7221 for_server: Option<LanguageServerId>,
7222 buffer: &Entity<Buffer>,
7223 range: Range<Anchor>,
7224 cx: &mut Context<Self>,
7225 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7226 let request = InlayHints {
7227 range: range.clone(),
7228 };
7229 if let Some((upstream_client, project_id)) = self.upstream_client() {
7230 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7231 return Task::ready(Ok(HashMap::default()));
7232 }
7233 let request_timeout = ProjectSettings::get_global(cx)
7234 .global_lsp_settings
7235 .get_request_timeout();
7236 let request_task = upstream_client.request_lsp(
7237 project_id,
7238 for_server.map(|id| id.to_proto()),
7239 request_timeout,
7240 cx.background_executor().clone(),
7241 request.to_proto(project_id, buffer.read(cx)),
7242 );
7243 let buffer = buffer.clone();
7244 cx.spawn(async move |weak_lsp_store, cx| {
7245 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7246 return Ok(HashMap::default());
7247 };
7248 let Some(responses) = request_task.await? else {
7249 return Ok(HashMap::default());
7250 };
7251
7252 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7253 let lsp_store = lsp_store.clone();
7254 let buffer = buffer.clone();
7255 let cx = cx.clone();
7256 let request = request.clone();
7257 async move {
7258 (
7259 LanguageServerId::from_proto(response.server_id),
7260 request
7261 .response_from_proto(response.response, lsp_store, buffer, cx)
7262 .await,
7263 )
7264 }
7265 }))
7266 .await;
7267
7268 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7269 let mut has_errors = false;
7270 let inlay_hints = inlay_hints
7271 .into_iter()
7272 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7273 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7274 Err(e) => {
7275 has_errors = true;
7276 log::error!("{e:#}");
7277 None
7278 }
7279 })
7280 .map(|(server_id, mut new_hints)| {
7281 new_hints.retain(|hint| {
7282 hint.position.is_valid(&buffer_snapshot)
7283 && range.start.is_valid(&buffer_snapshot)
7284 && range.end.is_valid(&buffer_snapshot)
7285 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7286 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7287 });
7288 (server_id, new_hints)
7289 })
7290 .collect::<HashMap<_, _>>();
7291 anyhow::ensure!(
7292 !has_errors || !inlay_hints.is_empty(),
7293 "Failed to fetch inlay hints"
7294 );
7295 Ok(inlay_hints)
7296 })
7297 } else {
7298 let inlay_hints_task = match for_server {
7299 Some(server_id) => {
7300 let server_task = self.request_lsp(
7301 buffer.clone(),
7302 LanguageServerToQuery::Other(server_id),
7303 request,
7304 cx,
7305 );
7306 cx.background_spawn(async move {
7307 let mut responses = Vec::new();
7308 match server_task.await {
7309 Ok(response) => responses.push((server_id, response)),
7310 // rust-analyzer likes to error with this when its still loading up
7311 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7312 Err(e) => log::error!(
7313 "Error handling response for inlay hints request: {e:#}"
7314 ),
7315 }
7316 responses
7317 })
7318 }
7319 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7320 };
7321 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7322 cx.background_spawn(async move {
7323 Ok(inlay_hints_task
7324 .await
7325 .into_iter()
7326 .map(|(server_id, mut new_hints)| {
7327 new_hints.retain(|hint| {
7328 hint.position.is_valid(&buffer_snapshot)
7329 && range.start.is_valid(&buffer_snapshot)
7330 && range.end.is_valid(&buffer_snapshot)
7331 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7332 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7333 });
7334 (server_id, new_hints)
7335 })
7336 .collect())
7337 })
7338 }
7339 }
7340
7341 fn diagnostic_registration_exists(
7342 &self,
7343 server_id: LanguageServerId,
7344 registration_id: &Option<SharedString>,
7345 ) -> bool {
7346 let Some(local) = self.as_local() else {
7347 return false;
7348 };
7349 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7350 else {
7351 return false;
7352 };
7353 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7354 registrations.diagnostics.contains_key(®istration_key)
7355 }
7356
7357 pub fn pull_diagnostics_for_buffer(
7358 &mut self,
7359 buffer: Entity<Buffer>,
7360 cx: &mut Context<Self>,
7361 ) -> Task<anyhow::Result<()>> {
7362 let diagnostics = self.pull_diagnostics(buffer, cx);
7363 cx.spawn(async move |lsp_store, cx| {
7364 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7365 return Ok(());
7366 };
7367 lsp_store.update(cx, |lsp_store, cx| {
7368 if lsp_store.as_local().is_none() {
7369 return;
7370 }
7371
7372 let mut unchanged_buffers = HashMap::default();
7373 let server_diagnostics_updates = diagnostics
7374 .into_iter()
7375 .filter_map(|diagnostics_set| match diagnostics_set {
7376 LspPullDiagnostics::Response {
7377 server_id,
7378 uri,
7379 diagnostics,
7380 registration_id,
7381 } => Some((server_id, uri, diagnostics, registration_id)),
7382 LspPullDiagnostics::Default => None,
7383 })
7384 .filter(|(server_id, _, _, registration_id)| {
7385 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7386 })
7387 .fold(
7388 HashMap::default(),
7389 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7390 let (result_id, diagnostics) = match diagnostics {
7391 PulledDiagnostics::Unchanged { result_id } => {
7392 unchanged_buffers
7393 .entry(new_registration_id.clone())
7394 .or_insert_with(HashSet::default)
7395 .insert(uri.clone());
7396 (Some(result_id), Vec::new())
7397 }
7398 PulledDiagnostics::Changed {
7399 result_id,
7400 diagnostics,
7401 } => (result_id, diagnostics),
7402 };
7403 let disk_based_sources = Cow::Owned(
7404 lsp_store
7405 .language_server_adapter_for_id(server_id)
7406 .as_ref()
7407 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7408 .unwrap_or(&[])
7409 .to_vec(),
7410 );
7411 acc.entry(server_id)
7412 .or_insert_with(HashMap::default)
7413 .entry(new_registration_id.clone())
7414 .or_insert_with(Vec::new)
7415 .push(DocumentDiagnosticsUpdate {
7416 server_id,
7417 diagnostics: lsp::PublishDiagnosticsParams {
7418 uri,
7419 diagnostics,
7420 version: None,
7421 },
7422 result_id: result_id.map(SharedString::new),
7423 disk_based_sources,
7424 registration_id: new_registration_id,
7425 });
7426 acc
7427 },
7428 );
7429
7430 for diagnostic_updates in server_diagnostics_updates.into_values() {
7431 for (registration_id, diagnostic_updates) in diagnostic_updates {
7432 lsp_store
7433 .merge_lsp_diagnostics(
7434 DiagnosticSourceKind::Pulled,
7435 diagnostic_updates,
7436 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7437 DiagnosticSourceKind::Pulled => {
7438 old_diagnostic.registration_id != registration_id
7439 || unchanged_buffers
7440 .get(&old_diagnostic.registration_id)
7441 .is_some_and(|unchanged_buffers| {
7442 unchanged_buffers.contains(&document_uri)
7443 })
7444 }
7445 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7446 true
7447 }
7448 },
7449 cx,
7450 )
7451 .log_err();
7452 }
7453 }
7454 })
7455 })
7456 }
7457
7458 pub fn signature_help<T: ToPointUtf16>(
7459 &mut self,
7460 buffer: &Entity<Buffer>,
7461 position: T,
7462 cx: &mut Context<Self>,
7463 ) -> Task<Option<Vec<SignatureHelp>>> {
7464 let position = position.to_point_utf16(buffer.read(cx));
7465
7466 if let Some((client, upstream_project_id)) = self.upstream_client() {
7467 let request = GetSignatureHelp { position };
7468 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7469 return Task::ready(None);
7470 }
7471 let request_timeout = ProjectSettings::get_global(cx)
7472 .global_lsp_settings
7473 .get_request_timeout();
7474 let request_task = client.request_lsp(
7475 upstream_project_id,
7476 None,
7477 request_timeout,
7478 cx.background_executor().clone(),
7479 request.to_proto(upstream_project_id, buffer.read(cx)),
7480 );
7481 let buffer = buffer.clone();
7482 cx.spawn(async move |weak_lsp_store, cx| {
7483 let lsp_store = weak_lsp_store.upgrade()?;
7484 let signatures = join_all(
7485 request_task
7486 .await
7487 .log_err()
7488 .flatten()
7489 .map(|response| response.payload)
7490 .unwrap_or_default()
7491 .into_iter()
7492 .map(|response| {
7493 let response = GetSignatureHelp { position }.response_from_proto(
7494 response.response,
7495 lsp_store.clone(),
7496 buffer.clone(),
7497 cx.clone(),
7498 );
7499 async move { response.await.log_err().flatten() }
7500 }),
7501 )
7502 .await
7503 .into_iter()
7504 .flatten()
7505 .collect();
7506 Some(signatures)
7507 })
7508 } else {
7509 let all_actions_task = self.request_multiple_lsp_locally(
7510 buffer,
7511 Some(position),
7512 GetSignatureHelp { position },
7513 cx,
7514 );
7515 cx.background_spawn(async move {
7516 Some(
7517 all_actions_task
7518 .await
7519 .into_iter()
7520 .flat_map(|(_, actions)| actions)
7521 .collect::<Vec<_>>(),
7522 )
7523 })
7524 }
7525 }
7526
7527 pub fn hover(
7528 &mut self,
7529 buffer: &Entity<Buffer>,
7530 position: PointUtf16,
7531 cx: &mut Context<Self>,
7532 ) -> Task<Option<Vec<Hover>>> {
7533 if let Some((client, upstream_project_id)) = self.upstream_client() {
7534 let request = GetHover { position };
7535 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7536 return Task::ready(None);
7537 }
7538 let request_timeout = ProjectSettings::get_global(cx)
7539 .global_lsp_settings
7540 .get_request_timeout();
7541 let request_task = client.request_lsp(
7542 upstream_project_id,
7543 None,
7544 request_timeout,
7545 cx.background_executor().clone(),
7546 request.to_proto(upstream_project_id, buffer.read(cx)),
7547 );
7548 let buffer = buffer.clone();
7549 cx.spawn(async move |weak_lsp_store, cx| {
7550 let lsp_store = weak_lsp_store.upgrade()?;
7551 let hovers = join_all(
7552 request_task
7553 .await
7554 .log_err()
7555 .flatten()
7556 .map(|response| response.payload)
7557 .unwrap_or_default()
7558 .into_iter()
7559 .map(|response| {
7560 let response = GetHover { position }.response_from_proto(
7561 response.response,
7562 lsp_store.clone(),
7563 buffer.clone(),
7564 cx.clone(),
7565 );
7566 async move {
7567 response
7568 .await
7569 .log_err()
7570 .flatten()
7571 .and_then(remove_empty_hover_blocks)
7572 }
7573 }),
7574 )
7575 .await
7576 .into_iter()
7577 .flatten()
7578 .collect();
7579 Some(hovers)
7580 })
7581 } else {
7582 let all_actions_task = self.request_multiple_lsp_locally(
7583 buffer,
7584 Some(position),
7585 GetHover { position },
7586 cx,
7587 );
7588 cx.background_spawn(async move {
7589 Some(
7590 all_actions_task
7591 .await
7592 .into_iter()
7593 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7594 .collect::<Vec<Hover>>(),
7595 )
7596 })
7597 }
7598 }
7599
7600 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7601 let language_registry = self.languages.clone();
7602
7603 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7604 let request = upstream_client.request(proto::GetProjectSymbols {
7605 project_id: *project_id,
7606 query: query.to_string(),
7607 });
7608 cx.foreground_executor().spawn(async move {
7609 let response = request.await?;
7610 let mut symbols = Vec::new();
7611 let core_symbols = response
7612 .symbols
7613 .into_iter()
7614 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7615 .collect::<Vec<_>>();
7616 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7617 .await;
7618 Ok(symbols)
7619 })
7620 } else if let Some(local) = self.as_local() {
7621 struct WorkspaceSymbolsResult {
7622 server_id: LanguageServerId,
7623 lsp_adapter: Arc<CachedLspAdapter>,
7624 worktree: WeakEntity<Worktree>,
7625 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7626 }
7627
7628 let mut requests = Vec::new();
7629 let mut requested_servers = BTreeSet::new();
7630 let request_timeout = ProjectSettings::get_global(cx)
7631 .global_lsp_settings
7632 .get_request_timeout();
7633
7634 for (seed, state) in local.language_server_ids.iter() {
7635 let Some(worktree_handle) = self
7636 .worktree_store
7637 .read(cx)
7638 .worktree_for_id(seed.worktree_id, cx)
7639 else {
7640 continue;
7641 };
7642
7643 let worktree = worktree_handle.read(cx);
7644 if !worktree.is_visible() {
7645 continue;
7646 }
7647
7648 if !requested_servers.insert(state.id) {
7649 continue;
7650 }
7651
7652 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7653 Some(LanguageServerState::Running {
7654 adapter, server, ..
7655 }) => (adapter.clone(), server),
7656
7657 _ => continue,
7658 };
7659
7660 let supports_workspace_symbol_request =
7661 match server.capabilities().workspace_symbol_provider {
7662 Some(OneOf::Left(supported)) => supported,
7663 Some(OneOf::Right(_)) => true,
7664 None => false,
7665 };
7666
7667 if !supports_workspace_symbol_request {
7668 continue;
7669 }
7670
7671 let worktree_handle = worktree_handle.clone();
7672 let server_id = server.server_id();
7673 requests.push(
7674 server
7675 .request::<lsp::request::WorkspaceSymbolRequest>(
7676 lsp::WorkspaceSymbolParams {
7677 query: query.to_string(),
7678 ..Default::default()
7679 },
7680 request_timeout,
7681 )
7682 .map(move |response| {
7683 let lsp_symbols = response
7684 .into_response()
7685 .context("workspace symbols request")
7686 .log_err()
7687 .flatten()
7688 .map(|symbol_response| match symbol_response {
7689 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7690 flat_responses
7691 .into_iter()
7692 .map(|lsp_symbol| {
7693 (
7694 lsp_symbol.name,
7695 lsp_symbol.kind,
7696 lsp_symbol.location,
7697 lsp_symbol.container_name,
7698 )
7699 })
7700 .collect::<Vec<_>>()
7701 }
7702 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7703 nested_responses
7704 .into_iter()
7705 .filter_map(|lsp_symbol| {
7706 let location = match lsp_symbol.location {
7707 OneOf::Left(location) => location,
7708 OneOf::Right(_) => {
7709 log::error!(
7710 "Unexpected: client capabilities \
7711 forbid symbol resolutions in \
7712 workspace.symbol.resolveSupport"
7713 );
7714 return None;
7715 }
7716 };
7717 Some((
7718 lsp_symbol.name,
7719 lsp_symbol.kind,
7720 location,
7721 lsp_symbol.container_name,
7722 ))
7723 })
7724 .collect::<Vec<_>>()
7725 }
7726 })
7727 .unwrap_or_default();
7728
7729 WorkspaceSymbolsResult {
7730 server_id,
7731 lsp_adapter,
7732 worktree: worktree_handle.downgrade(),
7733 lsp_symbols,
7734 }
7735 }),
7736 );
7737 }
7738
7739 cx.spawn(async move |this, cx| {
7740 let responses = futures::future::join_all(requests).await;
7741 let this = match this.upgrade() {
7742 Some(this) => this,
7743 None => return Ok(Vec::new()),
7744 };
7745
7746 let mut symbols = Vec::new();
7747 for result in responses {
7748 let core_symbols = this.update(cx, |this, cx| {
7749 result
7750 .lsp_symbols
7751 .into_iter()
7752 .filter_map(
7753 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7754 let abs_path = symbol_location.uri.to_file_path().ok()?;
7755 let source_worktree = result.worktree.upgrade()?;
7756 let source_worktree_id = source_worktree.read(cx).id();
7757
7758 let path = if let Some((tree, rel_path)) =
7759 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7760 {
7761 let worktree_id = tree.read(cx).id();
7762 SymbolLocation::InProject(ProjectPath {
7763 worktree_id,
7764 path: rel_path,
7765 })
7766 } else {
7767 SymbolLocation::OutsideProject {
7768 signature: this.symbol_signature(&abs_path),
7769 abs_path: abs_path.into(),
7770 }
7771 };
7772
7773 Some(CoreSymbol {
7774 source_language_server_id: result.server_id,
7775 language_server_name: result.lsp_adapter.name.clone(),
7776 source_worktree_id,
7777 path,
7778 kind: symbol_kind,
7779 name: collapse_newlines(&symbol_name, "↵ "),
7780 range: range_from_lsp(symbol_location.range),
7781 container_name: container_name
7782 .map(|c| collapse_newlines(&c, "↵ ")),
7783 })
7784 },
7785 )
7786 .collect::<Vec<_>>()
7787 });
7788
7789 populate_labels_for_symbols(
7790 core_symbols,
7791 &language_registry,
7792 Some(result.lsp_adapter),
7793 &mut symbols,
7794 )
7795 .await;
7796 }
7797
7798 Ok(symbols)
7799 })
7800 } else {
7801 Task::ready(Err(anyhow!("No upstream client or local language server")))
7802 }
7803 }
7804
7805 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7806 let mut summary = DiagnosticSummary::default();
7807 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7808 summary.error_count += path_summary.error_count;
7809 summary.warning_count += path_summary.warning_count;
7810 }
7811 summary
7812 }
7813
7814 /// Returns the diagnostic summary for a specific project path.
7815 pub fn diagnostic_summary_for_path(
7816 &self,
7817 project_path: &ProjectPath,
7818 _: &App,
7819 ) -> DiagnosticSummary {
7820 if let Some(summaries) = self
7821 .diagnostic_summaries
7822 .get(&project_path.worktree_id)
7823 .and_then(|map| map.get(&project_path.path))
7824 {
7825 let (error_count, warning_count) = summaries.iter().fold(
7826 (0, 0),
7827 |(error_count, warning_count), (_language_server_id, summary)| {
7828 (
7829 error_count + summary.error_count,
7830 warning_count + summary.warning_count,
7831 )
7832 },
7833 );
7834
7835 DiagnosticSummary {
7836 error_count,
7837 warning_count,
7838 }
7839 } else {
7840 DiagnosticSummary::default()
7841 }
7842 }
7843
7844 pub fn diagnostic_summaries<'a>(
7845 &'a self,
7846 include_ignored: bool,
7847 cx: &'a App,
7848 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7849 self.worktree_store
7850 .read(cx)
7851 .visible_worktrees(cx)
7852 .filter_map(|worktree| {
7853 let worktree = worktree.read(cx);
7854 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7855 })
7856 .flat_map(move |(worktree, summaries)| {
7857 let worktree_id = worktree.id();
7858 summaries
7859 .iter()
7860 .filter(move |(path, _)| {
7861 include_ignored
7862 || worktree
7863 .entry_for_path(path.as_ref())
7864 .is_some_and(|entry| !entry.is_ignored)
7865 })
7866 .flat_map(move |(path, summaries)| {
7867 summaries.iter().map(move |(server_id, summary)| {
7868 (
7869 ProjectPath {
7870 worktree_id,
7871 path: path.clone(),
7872 },
7873 *server_id,
7874 *summary,
7875 )
7876 })
7877 })
7878 })
7879 }
7880
7881 pub fn on_buffer_edited(
7882 &mut self,
7883 buffer: Entity<Buffer>,
7884 cx: &mut Context<Self>,
7885 ) -> Option<()> {
7886 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7887 Some(
7888 self.as_local()?
7889 .language_servers_for_buffer(buffer, cx)
7890 .map(|i| i.1.clone())
7891 .collect(),
7892 )
7893 })?;
7894
7895 let buffer = buffer.read(cx);
7896 let file = File::from_dyn(buffer.file())?;
7897 let abs_path = file.as_local()?.abs_path(cx);
7898 let uri = lsp::Uri::from_file_path(&abs_path)
7899 .ok()
7900 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7901 .log_err()?;
7902 let next_snapshot = buffer.text_snapshot();
7903 for language_server in language_servers {
7904 let language_server = language_server.clone();
7905
7906 let buffer_snapshots = self
7907 .as_local_mut()?
7908 .buffer_snapshots
7909 .get_mut(&buffer.remote_id())
7910 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7911 let previous_snapshot = buffer_snapshots.last()?;
7912
7913 let build_incremental_change = || {
7914 buffer
7915 .edits_since::<Dimensions<PointUtf16, usize>>(
7916 previous_snapshot.snapshot.version(),
7917 )
7918 .map(|edit| {
7919 let edit_start = edit.new.start.0;
7920 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7921 let new_text = next_snapshot
7922 .text_for_range(edit.new.start.1..edit.new.end.1)
7923 .collect();
7924 lsp::TextDocumentContentChangeEvent {
7925 range: Some(lsp::Range::new(
7926 point_to_lsp(edit_start),
7927 point_to_lsp(edit_end),
7928 )),
7929 range_length: None,
7930 text: new_text,
7931 }
7932 })
7933 .collect()
7934 };
7935
7936 let document_sync_kind = language_server
7937 .capabilities()
7938 .text_document_sync
7939 .as_ref()
7940 .and_then(|sync| match sync {
7941 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7942 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7943 });
7944
7945 let content_changes: Vec<_> = match document_sync_kind {
7946 Some(lsp::TextDocumentSyncKind::FULL) => {
7947 vec![lsp::TextDocumentContentChangeEvent {
7948 range: None,
7949 range_length: None,
7950 text: next_snapshot.text(),
7951 }]
7952 }
7953 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7954 _ => {
7955 #[cfg(any(test, feature = "test-support"))]
7956 {
7957 build_incremental_change()
7958 }
7959
7960 #[cfg(not(any(test, feature = "test-support")))]
7961 {
7962 continue;
7963 }
7964 }
7965 };
7966
7967 let next_version = previous_snapshot.version + 1;
7968 buffer_snapshots.push(LspBufferSnapshot {
7969 version: next_version,
7970 snapshot: next_snapshot.clone(),
7971 });
7972
7973 language_server
7974 .notify::<lsp::notification::DidChangeTextDocument>(
7975 lsp::DidChangeTextDocumentParams {
7976 text_document: lsp::VersionedTextDocumentIdentifier::new(
7977 uri.clone(),
7978 next_version,
7979 ),
7980 content_changes,
7981 },
7982 )
7983 .ok();
7984 self.pull_workspace_diagnostics(language_server.server_id());
7985 }
7986
7987 None
7988 }
7989
7990 pub fn on_buffer_saved(
7991 &mut self,
7992 buffer: Entity<Buffer>,
7993 cx: &mut Context<Self>,
7994 ) -> Option<()> {
7995 let file = File::from_dyn(buffer.read(cx).file())?;
7996 let worktree_id = file.worktree_id(cx);
7997 let abs_path = file.as_local()?.abs_path(cx);
7998 let text_document = lsp::TextDocumentIdentifier {
7999 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8000 };
8001 let local = self.as_local()?;
8002
8003 for server in local.language_servers_for_worktree(worktree_id) {
8004 if let Some(include_text) = include_text(server.as_ref()) {
8005 let text = if include_text {
8006 Some(buffer.read(cx).text())
8007 } else {
8008 None
8009 };
8010 server
8011 .notify::<lsp::notification::DidSaveTextDocument>(
8012 lsp::DidSaveTextDocumentParams {
8013 text_document: text_document.clone(),
8014 text,
8015 },
8016 )
8017 .ok();
8018 }
8019 }
8020
8021 let language_servers = buffer.update(cx, |buffer, cx| {
8022 local.language_server_ids_for_buffer(buffer, cx)
8023 });
8024 for language_server_id in language_servers {
8025 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8026 }
8027
8028 None
8029 }
8030
8031 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8032 maybe!(async move {
8033 let mut refreshed_servers = HashSet::default();
8034 let servers = lsp_store
8035 .update(cx, |lsp_store, cx| {
8036 let local = lsp_store.as_local()?;
8037
8038 let servers = local
8039 .language_server_ids
8040 .iter()
8041 .filter_map(|(seed, state)| {
8042 let worktree = lsp_store
8043 .worktree_store
8044 .read(cx)
8045 .worktree_for_id(seed.worktree_id, cx);
8046 let delegate: Arc<dyn LspAdapterDelegate> =
8047 worktree.map(|worktree| {
8048 LocalLspAdapterDelegate::new(
8049 local.languages.clone(),
8050 &local.environment,
8051 cx.weak_entity(),
8052 &worktree,
8053 local.http_client.clone(),
8054 local.fs.clone(),
8055 cx,
8056 )
8057 })?;
8058 let server_id = state.id;
8059
8060 let states = local.language_servers.get(&server_id)?;
8061
8062 match states {
8063 LanguageServerState::Starting { .. } => None,
8064 LanguageServerState::Running {
8065 adapter, server, ..
8066 } => {
8067 let adapter = adapter.clone();
8068 let server = server.clone();
8069 refreshed_servers.insert(server.name());
8070 let toolchain = seed.toolchain.clone();
8071 Some(cx.spawn(async move |_, cx| {
8072 let settings =
8073 LocalLspStore::workspace_configuration_for_adapter(
8074 adapter.adapter.clone(),
8075 &delegate,
8076 toolchain,
8077 None,
8078 cx,
8079 )
8080 .await
8081 .ok()?;
8082 server
8083 .notify::<lsp::notification::DidChangeConfiguration>(
8084 lsp::DidChangeConfigurationParams { settings },
8085 )
8086 .ok()?;
8087 Some(())
8088 }))
8089 }
8090 }
8091 })
8092 .collect::<Vec<_>>();
8093
8094 Some(servers)
8095 })
8096 .ok()
8097 .flatten()?;
8098
8099 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8100 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8101 // to stop and unregister its language server wrapper.
8102 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8103 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8104 let _: Vec<Option<()>> = join_all(servers).await;
8105
8106 Some(())
8107 })
8108 .await;
8109 }
8110
8111 fn maintain_workspace_config(
8112 external_refresh_requests: watch::Receiver<()>,
8113 cx: &mut Context<Self>,
8114 ) -> Task<Result<()>> {
8115 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8116 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8117
8118 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8119 *settings_changed_tx.borrow_mut() = ();
8120 });
8121
8122 let mut joint_future =
8123 futures::stream::select(settings_changed_rx, external_refresh_requests);
8124 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8125 // - 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).
8126 // - 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.
8127 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8128 // - 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,
8129 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8130 cx.spawn(async move |this, cx| {
8131 while let Some(()) = joint_future.next().await {
8132 this.update(cx, |this, cx| {
8133 this.refresh_server_tree(cx);
8134 })
8135 .ok();
8136
8137 Self::refresh_workspace_configurations(&this, cx).await;
8138 }
8139
8140 drop(settings_observation);
8141 anyhow::Ok(())
8142 })
8143 }
8144
8145 pub fn running_language_servers_for_local_buffer<'a>(
8146 &'a self,
8147 buffer: &Buffer,
8148 cx: &mut App,
8149 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8150 let local = self.as_local();
8151 let language_server_ids = local
8152 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8153 .unwrap_or_default();
8154
8155 language_server_ids
8156 .into_iter()
8157 .filter_map(
8158 move |server_id| match local?.language_servers.get(&server_id)? {
8159 LanguageServerState::Running {
8160 adapter, server, ..
8161 } => Some((adapter, server)),
8162 _ => None,
8163 },
8164 )
8165 }
8166
8167 pub fn language_servers_for_local_buffer(
8168 &self,
8169 buffer: &Buffer,
8170 cx: &mut App,
8171 ) -> Vec<LanguageServerId> {
8172 let local = self.as_local();
8173 local
8174 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8175 .unwrap_or_default()
8176 }
8177
8178 pub fn language_server_for_local_buffer<'a>(
8179 &'a self,
8180 buffer: &'a Buffer,
8181 server_id: LanguageServerId,
8182 cx: &'a mut App,
8183 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8184 self.as_local()?
8185 .language_servers_for_buffer(buffer, cx)
8186 .find(|(_, s)| s.server_id() == server_id)
8187 }
8188
8189 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8190 self.diagnostic_summaries.remove(&id_to_remove);
8191 if let Some(local) = self.as_local_mut() {
8192 let to_remove = local.remove_worktree(id_to_remove, cx);
8193 for server in to_remove {
8194 self.language_server_statuses.remove(&server);
8195 }
8196 }
8197 }
8198
8199 fn invalidate_diagnostic_summaries_for_removed_entries(
8200 &mut self,
8201 worktree_id: WorktreeId,
8202 changes: &UpdatedEntriesSet,
8203 cx: &mut Context<Self>,
8204 ) {
8205 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8206 return;
8207 };
8208
8209 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8210 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8211 let downstream = self.downstream_client.clone();
8212
8213 for (path, _, _) in changes
8214 .iter()
8215 .filter(|(_, _, change)| *change == PathChange::Removed)
8216 {
8217 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8218 for (server_id, _) in &summaries_by_server_id {
8219 cleared_server_ids.insert(*server_id);
8220 if let Some((client, project_id)) = &downstream {
8221 client
8222 .send(proto::UpdateDiagnosticSummary {
8223 project_id: *project_id,
8224 worktree_id: worktree_id.to_proto(),
8225 summary: Some(proto::DiagnosticSummary {
8226 path: path.as_ref().to_proto(),
8227 language_server_id: server_id.0 as u64,
8228 error_count: 0,
8229 warning_count: 0,
8230 }),
8231 more_summaries: Vec::new(),
8232 })
8233 .ok();
8234 }
8235 }
8236 cleared_paths.push(ProjectPath {
8237 worktree_id,
8238 path: path.clone(),
8239 });
8240 }
8241 }
8242
8243 if !cleared_paths.is_empty() {
8244 for server_id in cleared_server_ids {
8245 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8246 server_id,
8247 paths: cleared_paths.clone(),
8248 });
8249 }
8250 }
8251 }
8252
8253 pub fn shared(
8254 &mut self,
8255 project_id: u64,
8256 downstream_client: AnyProtoClient,
8257 _: &mut Context<Self>,
8258 ) {
8259 self.downstream_client = Some((downstream_client.clone(), project_id));
8260
8261 for (server_id, status) in &self.language_server_statuses {
8262 if let Some(server) = self.language_server_for_id(*server_id) {
8263 downstream_client
8264 .send(proto::StartLanguageServer {
8265 project_id,
8266 server: Some(proto::LanguageServer {
8267 id: server_id.to_proto(),
8268 name: status.name.to_string(),
8269 worktree_id: status.worktree.map(|id| id.to_proto()),
8270 }),
8271 capabilities: serde_json::to_string(&server.capabilities())
8272 .expect("serializing server LSP capabilities"),
8273 })
8274 .log_err();
8275 }
8276 }
8277 }
8278
8279 pub fn disconnected_from_host(&mut self) {
8280 self.downstream_client.take();
8281 }
8282
8283 pub fn disconnected_from_ssh_remote(&mut self) {
8284 if let LspStoreMode::Remote(RemoteLspStore {
8285 upstream_client, ..
8286 }) = &mut self.mode
8287 {
8288 upstream_client.take();
8289 }
8290 }
8291
8292 pub(crate) fn set_language_server_statuses_from_proto(
8293 &mut self,
8294 project: WeakEntity<Project>,
8295 language_servers: Vec<proto::LanguageServer>,
8296 server_capabilities: Vec<String>,
8297 cx: &mut Context<Self>,
8298 ) {
8299 let lsp_logs = cx
8300 .try_global::<GlobalLogStore>()
8301 .map(|lsp_store| lsp_store.0.clone());
8302
8303 self.language_server_statuses = language_servers
8304 .into_iter()
8305 .zip(server_capabilities)
8306 .map(|(server, server_capabilities)| {
8307 let server_id = LanguageServerId(server.id as usize);
8308 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8309 self.lsp_server_capabilities
8310 .insert(server_id, server_capabilities);
8311 }
8312
8313 let name = LanguageServerName::from_proto(server.name);
8314 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8315
8316 if let Some(lsp_logs) = &lsp_logs {
8317 lsp_logs.update(cx, |lsp_logs, cx| {
8318 lsp_logs.add_language_server(
8319 // Only remote clients get their language servers set from proto
8320 LanguageServerKind::Remote {
8321 project: project.clone(),
8322 },
8323 server_id,
8324 Some(name.clone()),
8325 worktree,
8326 None,
8327 cx,
8328 );
8329 });
8330 }
8331
8332 (
8333 server_id,
8334 LanguageServerStatus {
8335 name,
8336 server_version: None,
8337 server_readable_version: None,
8338 pending_work: Default::default(),
8339 has_pending_diagnostic_updates: false,
8340 progress_tokens: Default::default(),
8341 worktree,
8342 binary: None,
8343 configuration: None,
8344 workspace_folders: BTreeSet::new(),
8345 process_id: None,
8346 },
8347 )
8348 })
8349 .collect();
8350 }
8351
8352 #[cfg(feature = "test-support")]
8353 pub fn update_diagnostic_entries(
8354 &mut self,
8355 server_id: LanguageServerId,
8356 abs_path: PathBuf,
8357 result_id: Option<SharedString>,
8358 version: Option<i32>,
8359 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8360 cx: &mut Context<Self>,
8361 ) -> anyhow::Result<()> {
8362 self.merge_diagnostic_entries(
8363 vec![DocumentDiagnosticsUpdate {
8364 diagnostics: DocumentDiagnostics {
8365 diagnostics,
8366 document_abs_path: abs_path,
8367 version,
8368 },
8369 result_id,
8370 server_id,
8371 disk_based_sources: Cow::Borrowed(&[]),
8372 registration_id: None,
8373 }],
8374 |_, _, _| false,
8375 cx,
8376 )?;
8377 Ok(())
8378 }
8379
8380 pub fn merge_diagnostic_entries<'a>(
8381 &mut self,
8382 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8383 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8384 cx: &mut Context<Self>,
8385 ) -> anyhow::Result<()> {
8386 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8387 let mut updated_diagnostics_paths = HashMap::default();
8388 for mut update in diagnostic_updates {
8389 let abs_path = &update.diagnostics.document_abs_path;
8390 let server_id = update.server_id;
8391 let Some((worktree, relative_path)) =
8392 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8393 else {
8394 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8395 return Ok(());
8396 };
8397
8398 let worktree_id = worktree.read(cx).id();
8399 let project_path = ProjectPath {
8400 worktree_id,
8401 path: relative_path,
8402 };
8403
8404 let document_uri = lsp::Uri::from_file_path(abs_path)
8405 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8406 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8407 let snapshot = buffer_handle.read(cx).snapshot();
8408 let buffer = buffer_handle.read(cx);
8409 let reused_diagnostics = buffer
8410 .buffer_diagnostics(Some(server_id))
8411 .iter()
8412 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8413 .map(|v| {
8414 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8415 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8416 DiagnosticEntry {
8417 range: start..end,
8418 diagnostic: v.diagnostic.clone(),
8419 }
8420 })
8421 .collect::<Vec<_>>();
8422
8423 self.as_local_mut()
8424 .context("cannot merge diagnostics on a remote LspStore")?
8425 .update_buffer_diagnostics(
8426 &buffer_handle,
8427 server_id,
8428 Some(update.registration_id),
8429 update.result_id,
8430 update.diagnostics.version,
8431 update.diagnostics.diagnostics.clone(),
8432 reused_diagnostics.clone(),
8433 cx,
8434 )?;
8435
8436 update.diagnostics.diagnostics.extend(reused_diagnostics);
8437 } else if let Some(local) = self.as_local() {
8438 let reused_diagnostics = local
8439 .diagnostics
8440 .get(&worktree_id)
8441 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8442 .and_then(|diagnostics_by_server_id| {
8443 diagnostics_by_server_id
8444 .binary_search_by_key(&server_id, |e| e.0)
8445 .ok()
8446 .map(|ix| &diagnostics_by_server_id[ix].1)
8447 })
8448 .into_iter()
8449 .flatten()
8450 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8451
8452 update
8453 .diagnostics
8454 .diagnostics
8455 .extend(reused_diagnostics.cloned());
8456 }
8457
8458 let updated = worktree.update(cx, |worktree, cx| {
8459 self.update_worktree_diagnostics(
8460 worktree.id(),
8461 server_id,
8462 project_path.path.clone(),
8463 update.diagnostics.diagnostics,
8464 cx,
8465 )
8466 })?;
8467 match updated {
8468 ControlFlow::Continue(new_summary) => {
8469 if let Some((project_id, new_summary)) = new_summary {
8470 match &mut diagnostics_summary {
8471 Some(diagnostics_summary) => {
8472 diagnostics_summary
8473 .more_summaries
8474 .push(proto::DiagnosticSummary {
8475 path: project_path.path.as_ref().to_proto(),
8476 language_server_id: server_id.0 as u64,
8477 error_count: new_summary.error_count,
8478 warning_count: new_summary.warning_count,
8479 })
8480 }
8481 None => {
8482 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8483 project_id,
8484 worktree_id: worktree_id.to_proto(),
8485 summary: Some(proto::DiagnosticSummary {
8486 path: project_path.path.as_ref().to_proto(),
8487 language_server_id: server_id.0 as u64,
8488 error_count: new_summary.error_count,
8489 warning_count: new_summary.warning_count,
8490 }),
8491 more_summaries: Vec::new(),
8492 })
8493 }
8494 }
8495 }
8496 updated_diagnostics_paths
8497 .entry(server_id)
8498 .or_insert_with(Vec::new)
8499 .push(project_path);
8500 }
8501 ControlFlow::Break(()) => {}
8502 }
8503 }
8504
8505 if let Some((diagnostics_summary, (downstream_client, _))) =
8506 diagnostics_summary.zip(self.downstream_client.as_ref())
8507 {
8508 downstream_client.send(diagnostics_summary).log_err();
8509 }
8510 for (server_id, paths) in updated_diagnostics_paths {
8511 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8512 }
8513 Ok(())
8514 }
8515
8516 fn update_worktree_diagnostics(
8517 &mut self,
8518 worktree_id: WorktreeId,
8519 server_id: LanguageServerId,
8520 path_in_worktree: Arc<RelPath>,
8521 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8522 _: &mut Context<Worktree>,
8523 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8524 let local = match &mut self.mode {
8525 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8526 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8527 };
8528
8529 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8530 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8531 let summaries_by_server_id = summaries_for_tree
8532 .entry(path_in_worktree.clone())
8533 .or_default();
8534
8535 let old_summary = summaries_by_server_id
8536 .remove(&server_id)
8537 .unwrap_or_default();
8538
8539 let new_summary = DiagnosticSummary::new(&diagnostics);
8540 if diagnostics.is_empty() {
8541 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8542 {
8543 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8544 diagnostics_by_server_id.remove(ix);
8545 }
8546 if diagnostics_by_server_id.is_empty() {
8547 diagnostics_for_tree.remove(&path_in_worktree);
8548 }
8549 }
8550 } else {
8551 summaries_by_server_id.insert(server_id, new_summary);
8552 let diagnostics_by_server_id = diagnostics_for_tree
8553 .entry(path_in_worktree.clone())
8554 .or_default();
8555 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8556 Ok(ix) => {
8557 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8558 }
8559 Err(ix) => {
8560 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8561 }
8562 }
8563 }
8564
8565 if !old_summary.is_empty() || !new_summary.is_empty() {
8566 if let Some((_, project_id)) = &self.downstream_client {
8567 Ok(ControlFlow::Continue(Some((
8568 *project_id,
8569 proto::DiagnosticSummary {
8570 path: path_in_worktree.to_proto(),
8571 language_server_id: server_id.0 as u64,
8572 error_count: new_summary.error_count as u32,
8573 warning_count: new_summary.warning_count as u32,
8574 },
8575 ))))
8576 } else {
8577 Ok(ControlFlow::Continue(None))
8578 }
8579 } else {
8580 Ok(ControlFlow::Break(()))
8581 }
8582 }
8583
8584 pub fn open_buffer_for_symbol(
8585 &mut self,
8586 symbol: &Symbol,
8587 cx: &mut Context<Self>,
8588 ) -> Task<Result<Entity<Buffer>>> {
8589 if let Some((client, project_id)) = self.upstream_client() {
8590 let request = client.request(proto::OpenBufferForSymbol {
8591 project_id,
8592 symbol: Some(Self::serialize_symbol(symbol)),
8593 });
8594 cx.spawn(async move |this, cx| {
8595 let response = request.await?;
8596 let buffer_id = BufferId::new(response.buffer_id)?;
8597 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8598 .await
8599 })
8600 } else if let Some(local) = self.as_local() {
8601 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8602 seed.worktree_id == symbol.source_worktree_id
8603 && state.id == symbol.source_language_server_id
8604 && symbol.language_server_name == seed.name
8605 });
8606 if !is_valid {
8607 return Task::ready(Err(anyhow!(
8608 "language server for worktree and language not found"
8609 )));
8610 };
8611
8612 let symbol_abs_path = match &symbol.path {
8613 SymbolLocation::InProject(project_path) => self
8614 .worktree_store
8615 .read(cx)
8616 .absolutize(&project_path, cx)
8617 .context("no such worktree"),
8618 SymbolLocation::OutsideProject {
8619 abs_path,
8620 signature: _,
8621 } => Ok(abs_path.to_path_buf()),
8622 };
8623 let symbol_abs_path = match symbol_abs_path {
8624 Ok(abs_path) => abs_path,
8625 Err(err) => return Task::ready(Err(err)),
8626 };
8627 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8628 uri
8629 } else {
8630 return Task::ready(Err(anyhow!("invalid symbol path")));
8631 };
8632
8633 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8634 } else {
8635 Task::ready(Err(anyhow!("no upstream client or local store")))
8636 }
8637 }
8638
8639 pub(crate) fn open_local_buffer_via_lsp(
8640 &mut self,
8641 abs_path: lsp::Uri,
8642 language_server_id: LanguageServerId,
8643 cx: &mut Context<Self>,
8644 ) -> Task<Result<Entity<Buffer>>> {
8645 let path_style = self.worktree_store.read(cx).path_style();
8646 cx.spawn(async move |lsp_store, cx| {
8647 // Escape percent-encoded string.
8648 let current_scheme = abs_path.scheme().to_owned();
8649 // Uri is immutable, so we can't modify the scheme
8650
8651 let abs_path = abs_path
8652 .to_file_path_ext(path_style)
8653 .map_err(|()| anyhow!("can't convert URI to path"))?;
8654 let p = abs_path.clone();
8655 let yarn_worktree = lsp_store
8656 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8657 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8658 cx.spawn(async move |this, cx| {
8659 let t = this
8660 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8661 .ok()?;
8662 t.await
8663 })
8664 }),
8665 None => Task::ready(None),
8666 })?
8667 .await;
8668 let (worktree_root_target, known_relative_path) =
8669 if let Some((zip_root, relative_path)) = yarn_worktree {
8670 (zip_root, Some(relative_path))
8671 } else {
8672 (Arc::<Path>::from(abs_path.as_path()), None)
8673 };
8674 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8675 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8676 worktree_store.find_worktree(&worktree_root_target, cx)
8677 })
8678 })?;
8679 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8680 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8681 (result.0, relative_path, None)
8682 } else {
8683 let worktree = lsp_store
8684 .update(cx, |lsp_store, cx| {
8685 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8686 worktree_store.create_worktree(&worktree_root_target, false, cx)
8687 })
8688 })?
8689 .await?;
8690 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8691 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8692 lsp_store
8693 .update(cx, |lsp_store, cx| {
8694 if let Some(local) = lsp_store.as_local_mut() {
8695 local.register_language_server_for_invisible_worktree(
8696 &worktree,
8697 language_server_id,
8698 cx,
8699 )
8700 }
8701 match lsp_store.language_server_statuses.get(&language_server_id) {
8702 Some(status) => status.worktree,
8703 None => None,
8704 }
8705 })
8706 .ok()
8707 .flatten()
8708 .zip(Some(worktree_root.clone()))
8709 } else {
8710 None
8711 };
8712 let relative_path = if let Some(known_path) = known_relative_path {
8713 known_path
8714 } else {
8715 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8716 .into_arc()
8717 };
8718 (worktree, relative_path, source_ws)
8719 };
8720 let project_path = ProjectPath {
8721 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8722 path: relative_path,
8723 };
8724 let buffer = lsp_store
8725 .update(cx, |lsp_store, cx| {
8726 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8727 buffer_store.open_buffer(project_path, cx)
8728 })
8729 })?
8730 .await?;
8731 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8732 if let Some((source_ws, worktree_root)) = source_ws {
8733 buffer.update(cx, |buffer, cx| {
8734 let settings = WorktreeSettings::get(
8735 Some(
8736 (&ProjectPath {
8737 worktree_id: source_ws,
8738 path: Arc::from(RelPath::empty()),
8739 })
8740 .into(),
8741 ),
8742 cx,
8743 );
8744 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8745 if is_read_only {
8746 buffer.set_capability(Capability::ReadOnly, cx);
8747 }
8748 });
8749 }
8750 Ok(buffer)
8751 })
8752 }
8753
8754 fn local_lsp_servers_for_buffer(
8755 &self,
8756 buffer: &Entity<Buffer>,
8757 cx: &mut Context<Self>,
8758 ) -> Vec<LanguageServerId> {
8759 let Some(local) = self.as_local() else {
8760 return Vec::new();
8761 };
8762
8763 let snapshot = buffer.read(cx).snapshot();
8764
8765 buffer.update(cx, |buffer, cx| {
8766 local
8767 .language_servers_for_buffer(buffer, cx)
8768 .map(|(_, server)| server.server_id())
8769 .filter(|server_id| {
8770 self.as_local().is_none_or(|local| {
8771 local
8772 .buffers_opened_in_servers
8773 .get(&snapshot.remote_id())
8774 .is_some_and(|servers| servers.contains(server_id))
8775 })
8776 })
8777 .collect()
8778 })
8779 }
8780
8781 fn request_multiple_lsp_locally<P, R>(
8782 &mut self,
8783 buffer: &Entity<Buffer>,
8784 position: Option<P>,
8785 request: R,
8786 cx: &mut Context<Self>,
8787 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8788 where
8789 P: ToOffset,
8790 R: LspCommand + Clone,
8791 <R::LspRequest as lsp::request::Request>::Result: Send,
8792 <R::LspRequest as lsp::request::Request>::Params: Send,
8793 {
8794 let Some(local) = self.as_local() else {
8795 return Task::ready(Vec::new());
8796 };
8797
8798 let snapshot = buffer.read(cx).snapshot();
8799 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8800
8801 let server_ids = buffer.update(cx, |buffer, cx| {
8802 local
8803 .language_servers_for_buffer(buffer, cx)
8804 .filter(|(adapter, _)| {
8805 scope
8806 .as_ref()
8807 .map(|scope| scope.language_allowed(&adapter.name))
8808 .unwrap_or(true)
8809 })
8810 .map(|(_, server)| server.server_id())
8811 .filter(|server_id| {
8812 self.as_local().is_none_or(|local| {
8813 local
8814 .buffers_opened_in_servers
8815 .get(&snapshot.remote_id())
8816 .is_some_and(|servers| servers.contains(server_id))
8817 })
8818 })
8819 .collect::<Vec<_>>()
8820 });
8821
8822 let mut response_results = server_ids
8823 .into_iter()
8824 .map(|server_id| {
8825 let task = self.request_lsp(
8826 buffer.clone(),
8827 LanguageServerToQuery::Other(server_id),
8828 request.clone(),
8829 cx,
8830 );
8831 async move { (server_id, task.await) }
8832 })
8833 .collect::<FuturesUnordered<_>>();
8834
8835 cx.background_spawn(async move {
8836 let mut responses = Vec::with_capacity(response_results.len());
8837 while let Some((server_id, response_result)) = response_results.next().await {
8838 match response_result {
8839 Ok(response) => responses.push((server_id, response)),
8840 // rust-analyzer likes to error with this when its still loading up
8841 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8842 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8843 }
8844 }
8845 responses
8846 })
8847 }
8848
8849 async fn handle_lsp_get_completions(
8850 this: Entity<Self>,
8851 envelope: TypedEnvelope<proto::GetCompletions>,
8852 mut cx: AsyncApp,
8853 ) -> Result<proto::GetCompletionsResponse> {
8854 let sender_id = envelope.original_sender_id().unwrap_or_default();
8855
8856 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8857 let buffer_handle = this.update(&mut cx, |this, cx| {
8858 this.buffer_store.read(cx).get_existing(buffer_id)
8859 })?;
8860 let request = GetCompletions::from_proto(
8861 envelope.payload,
8862 this.clone(),
8863 buffer_handle.clone(),
8864 cx.clone(),
8865 )
8866 .await?;
8867
8868 let server_to_query = match request.server_id {
8869 Some(server_id) => LanguageServerToQuery::Other(server_id),
8870 None => LanguageServerToQuery::FirstCapable,
8871 };
8872
8873 let response = this
8874 .update(&mut cx, |this, cx| {
8875 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8876 })
8877 .await?;
8878 this.update(&mut cx, |this, cx| {
8879 Ok(GetCompletions::response_to_proto(
8880 response,
8881 this,
8882 sender_id,
8883 &buffer_handle.read(cx).version(),
8884 cx,
8885 ))
8886 })
8887 }
8888
8889 async fn handle_lsp_command<T: LspCommand>(
8890 this: Entity<Self>,
8891 envelope: TypedEnvelope<T::ProtoRequest>,
8892 mut cx: AsyncApp,
8893 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8894 where
8895 <T::LspRequest as lsp::request::Request>::Params: Send,
8896 <T::LspRequest as lsp::request::Request>::Result: Send,
8897 {
8898 let sender_id = envelope.original_sender_id().unwrap_or_default();
8899 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8900 let buffer_handle = this.update(&mut cx, |this, cx| {
8901 this.buffer_store.read(cx).get_existing(buffer_id)
8902 })?;
8903 let request = T::from_proto(
8904 envelope.payload,
8905 this.clone(),
8906 buffer_handle.clone(),
8907 cx.clone(),
8908 )
8909 .await?;
8910 let response = this
8911 .update(&mut cx, |this, cx| {
8912 this.request_lsp(
8913 buffer_handle.clone(),
8914 LanguageServerToQuery::FirstCapable,
8915 request,
8916 cx,
8917 )
8918 })
8919 .await?;
8920 this.update(&mut cx, |this, cx| {
8921 Ok(T::response_to_proto(
8922 response,
8923 this,
8924 sender_id,
8925 &buffer_handle.read(cx).version(),
8926 cx,
8927 ))
8928 })
8929 }
8930
8931 async fn handle_lsp_query(
8932 lsp_store: Entity<Self>,
8933 envelope: TypedEnvelope<proto::LspQuery>,
8934 mut cx: AsyncApp,
8935 ) -> Result<proto::Ack> {
8936 use proto::lsp_query::Request;
8937 let sender_id = envelope.original_sender_id().unwrap_or_default();
8938 let lsp_query = envelope.payload;
8939 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8940 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8941 match lsp_query.request.context("invalid LSP query request")? {
8942 Request::GetReferences(get_references) => {
8943 let position = get_references.position.clone().and_then(deserialize_anchor);
8944 Self::query_lsp_locally::<GetReferences>(
8945 lsp_store,
8946 server_id,
8947 sender_id,
8948 lsp_request_id,
8949 get_references,
8950 position,
8951 &mut cx,
8952 )
8953 .await?;
8954 }
8955 Request::GetDocumentColor(get_document_color) => {
8956 Self::query_lsp_locally::<GetDocumentColor>(
8957 lsp_store,
8958 server_id,
8959 sender_id,
8960 lsp_request_id,
8961 get_document_color,
8962 None,
8963 &mut cx,
8964 )
8965 .await?;
8966 }
8967 Request::GetFoldingRanges(get_folding_ranges) => {
8968 Self::query_lsp_locally::<GetFoldingRanges>(
8969 lsp_store,
8970 server_id,
8971 sender_id,
8972 lsp_request_id,
8973 get_folding_ranges,
8974 None,
8975 &mut cx,
8976 )
8977 .await?;
8978 }
8979 Request::GetDocumentSymbols(get_document_symbols) => {
8980 Self::query_lsp_locally::<GetDocumentSymbols>(
8981 lsp_store,
8982 server_id,
8983 sender_id,
8984 lsp_request_id,
8985 get_document_symbols,
8986 None,
8987 &mut cx,
8988 )
8989 .await?;
8990 }
8991 Request::GetHover(get_hover) => {
8992 let position = get_hover.position.clone().and_then(deserialize_anchor);
8993 Self::query_lsp_locally::<GetHover>(
8994 lsp_store,
8995 server_id,
8996 sender_id,
8997 lsp_request_id,
8998 get_hover,
8999 position,
9000 &mut cx,
9001 )
9002 .await?;
9003 }
9004 Request::GetCodeActions(get_code_actions) => {
9005 Self::query_lsp_locally::<GetCodeActions>(
9006 lsp_store,
9007 server_id,
9008 sender_id,
9009 lsp_request_id,
9010 get_code_actions,
9011 None,
9012 &mut cx,
9013 )
9014 .await?;
9015 }
9016 Request::GetSignatureHelp(get_signature_help) => {
9017 let position = get_signature_help
9018 .position
9019 .clone()
9020 .and_then(deserialize_anchor);
9021 Self::query_lsp_locally::<GetSignatureHelp>(
9022 lsp_store,
9023 server_id,
9024 sender_id,
9025 lsp_request_id,
9026 get_signature_help,
9027 position,
9028 &mut cx,
9029 )
9030 .await?;
9031 }
9032 Request::GetCodeLens(get_code_lens) => {
9033 Self::query_lsp_locally::<GetCodeLens>(
9034 lsp_store,
9035 server_id,
9036 sender_id,
9037 lsp_request_id,
9038 get_code_lens,
9039 None,
9040 &mut cx,
9041 )
9042 .await?;
9043 }
9044 Request::GetDefinition(get_definition) => {
9045 let position = get_definition.position.clone().and_then(deserialize_anchor);
9046 Self::query_lsp_locally::<GetDefinitions>(
9047 lsp_store,
9048 server_id,
9049 sender_id,
9050 lsp_request_id,
9051 get_definition,
9052 position,
9053 &mut cx,
9054 )
9055 .await?;
9056 }
9057 Request::GetDeclaration(get_declaration) => {
9058 let position = get_declaration
9059 .position
9060 .clone()
9061 .and_then(deserialize_anchor);
9062 Self::query_lsp_locally::<GetDeclarations>(
9063 lsp_store,
9064 server_id,
9065 sender_id,
9066 lsp_request_id,
9067 get_declaration,
9068 position,
9069 &mut cx,
9070 )
9071 .await?;
9072 }
9073 Request::GetTypeDefinition(get_type_definition) => {
9074 let position = get_type_definition
9075 .position
9076 .clone()
9077 .and_then(deserialize_anchor);
9078 Self::query_lsp_locally::<GetTypeDefinitions>(
9079 lsp_store,
9080 server_id,
9081 sender_id,
9082 lsp_request_id,
9083 get_type_definition,
9084 position,
9085 &mut cx,
9086 )
9087 .await?;
9088 }
9089 Request::GetImplementation(get_implementation) => {
9090 let position = get_implementation
9091 .position
9092 .clone()
9093 .and_then(deserialize_anchor);
9094 Self::query_lsp_locally::<GetImplementations>(
9095 lsp_store,
9096 server_id,
9097 sender_id,
9098 lsp_request_id,
9099 get_implementation,
9100 position,
9101 &mut cx,
9102 )
9103 .await?;
9104 }
9105 Request::InlayHints(inlay_hints) => {
9106 let query_start = inlay_hints
9107 .start
9108 .clone()
9109 .and_then(deserialize_anchor)
9110 .context("invalid inlay hints range start")?;
9111 let query_end = inlay_hints
9112 .end
9113 .clone()
9114 .and_then(deserialize_anchor)
9115 .context("invalid inlay hints range end")?;
9116 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9117 &lsp_store,
9118 server_id,
9119 lsp_request_id,
9120 &inlay_hints,
9121 query_start..query_end,
9122 &mut cx,
9123 )
9124 .await
9125 .context("preparing inlay hints request")?;
9126 Self::query_lsp_locally::<InlayHints>(
9127 lsp_store,
9128 server_id,
9129 sender_id,
9130 lsp_request_id,
9131 inlay_hints,
9132 None,
9133 &mut cx,
9134 )
9135 .await
9136 .context("querying for inlay hints")?
9137 }
9138 //////////////////////////////
9139 // Below are LSP queries that need to fetch more data,
9140 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9141 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9142 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9143 &lsp_store,
9144 &get_document_diagnostics,
9145 &mut cx,
9146 )
9147 .await?;
9148 lsp_store.update(&mut cx, |lsp_store, cx| {
9149 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9150 let key = LspKey {
9151 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9152 server_queried: server_id,
9153 };
9154 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9155 ) {
9156 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9157 lsp_requests.clear();
9158 };
9159 }
9160
9161 lsp_data.lsp_requests.entry(key).or_default().insert(
9162 lsp_request_id,
9163 cx.spawn(async move |lsp_store, cx| {
9164 let diagnostics_pull = lsp_store
9165 .update(cx, |lsp_store, cx| {
9166 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9167 })
9168 .ok();
9169 if let Some(diagnostics_pull) = diagnostics_pull {
9170 match diagnostics_pull.await {
9171 Ok(()) => {}
9172 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9173 };
9174 }
9175 }),
9176 );
9177 });
9178 }
9179 Request::SemanticTokens(semantic_tokens) => {
9180 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9181 &lsp_store,
9182 &semantic_tokens,
9183 &mut cx,
9184 )
9185 .await?;
9186 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9187 lsp_store.update(&mut cx, |lsp_store, cx| {
9188 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9189 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9190 let key = LspKey {
9191 request_type: TypeId::of::<SemanticTokensFull>(),
9192 server_queried: server_id,
9193 };
9194 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9195 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9196 lsp_requests.clear();
9197 };
9198 }
9199
9200 lsp_data.lsp_requests.entry(key).or_default().insert(
9201 lsp_request_id,
9202 cx.spawn(async move |lsp_store, cx| {
9203 let tokens_fetch = lsp_store
9204 .update(cx, |lsp_store, cx| {
9205 lsp_store
9206 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9207 })
9208 .ok();
9209 if let Some(tokens_fetch) = tokens_fetch {
9210 let new_tokens = tokens_fetch.await;
9211 if let Some(new_tokens) = new_tokens {
9212 lsp_store
9213 .update(cx, |lsp_store, cx| {
9214 let response = new_tokens
9215 .into_iter()
9216 .map(|(server_id, response)| {
9217 (
9218 server_id.to_proto(),
9219 SemanticTokensFull::response_to_proto(
9220 response,
9221 lsp_store,
9222 sender_id,
9223 &buffer_version,
9224 cx,
9225 ),
9226 )
9227 })
9228 .collect::<HashMap<_, _>>();
9229 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9230 project_id,
9231 lsp_request_id,
9232 response,
9233 ) {
9234 Ok(()) => {}
9235 Err(e) => {
9236 log::error!(
9237 "Failed to send semantic tokens LSP response: {e:#}",
9238 )
9239 }
9240 }
9241 })
9242 .ok();
9243 }
9244 }
9245 }),
9246 );
9247 }
9248 });
9249 }
9250 }
9251 Ok(proto::Ack {})
9252 }
9253
9254 async fn handle_lsp_query_response(
9255 lsp_store: Entity<Self>,
9256 envelope: TypedEnvelope<proto::LspQueryResponse>,
9257 cx: AsyncApp,
9258 ) -> Result<()> {
9259 lsp_store.read_with(&cx, |lsp_store, _| {
9260 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9261 upstream_client.handle_lsp_response(envelope.clone());
9262 }
9263 });
9264 Ok(())
9265 }
9266
9267 async fn handle_apply_code_action(
9268 this: Entity<Self>,
9269 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9270 mut cx: AsyncApp,
9271 ) -> Result<proto::ApplyCodeActionResponse> {
9272 let sender_id = envelope.original_sender_id().unwrap_or_default();
9273 let action =
9274 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9275 let apply_code_action = this.update(&mut cx, |this, cx| {
9276 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9277 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9278 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9279 })?;
9280
9281 let project_transaction = apply_code_action.await?;
9282 let project_transaction = this.update(&mut cx, |this, cx| {
9283 this.buffer_store.update(cx, |buffer_store, cx| {
9284 buffer_store.serialize_project_transaction_for_peer(
9285 project_transaction,
9286 sender_id,
9287 cx,
9288 )
9289 })
9290 });
9291 Ok(proto::ApplyCodeActionResponse {
9292 transaction: Some(project_transaction),
9293 })
9294 }
9295
9296 async fn handle_register_buffer_with_language_servers(
9297 this: Entity<Self>,
9298 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9299 mut cx: AsyncApp,
9300 ) -> Result<proto::Ack> {
9301 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9302 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9303 this.update(&mut cx, |this, cx| {
9304 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9305 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9306 project_id: upstream_project_id,
9307 buffer_id: buffer_id.to_proto(),
9308 only_servers: envelope.payload.only_servers,
9309 });
9310 }
9311
9312 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9313 anyhow::bail!("buffer is not open");
9314 };
9315
9316 let handle = this.register_buffer_with_language_servers(
9317 &buffer,
9318 envelope
9319 .payload
9320 .only_servers
9321 .into_iter()
9322 .filter_map(|selector| {
9323 Some(match selector.selector? {
9324 proto::language_server_selector::Selector::ServerId(server_id) => {
9325 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9326 }
9327 proto::language_server_selector::Selector::Name(name) => {
9328 LanguageServerSelector::Name(LanguageServerName(
9329 SharedString::from(name),
9330 ))
9331 }
9332 })
9333 })
9334 .collect(),
9335 false,
9336 cx,
9337 );
9338 // Pull diagnostics for the buffer even if it was already registered.
9339 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9340 // but it's unclear if we need it.
9341 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9342 .detach();
9343 this.buffer_store().update(cx, |buffer_store, _| {
9344 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9345 });
9346
9347 Ok(())
9348 })?;
9349 Ok(proto::Ack {})
9350 }
9351
9352 async fn handle_rename_project_entry(
9353 this: Entity<Self>,
9354 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9355 mut cx: AsyncApp,
9356 ) -> Result<proto::ProjectEntryResponse> {
9357 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9358 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9359 let new_path =
9360 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9361
9362 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9363 .update(&mut cx, |this, cx| {
9364 let (worktree, entry) = this
9365 .worktree_store
9366 .read(cx)
9367 .worktree_and_entry_for_id(entry_id, cx)?;
9368 let new_worktree = this
9369 .worktree_store
9370 .read(cx)
9371 .worktree_for_id(new_worktree_id, cx)?;
9372 Some((
9373 this.worktree_store.clone(),
9374 worktree,
9375 new_worktree,
9376 entry.clone(),
9377 ))
9378 })
9379 .context("worktree not found")?;
9380 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9381 (worktree.absolutize(&old_entry.path), worktree.id())
9382 });
9383 let new_abs_path =
9384 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9385
9386 let _transaction = Self::will_rename_entry(
9387 this.downgrade(),
9388 old_worktree_id,
9389 &old_abs_path,
9390 &new_abs_path,
9391 old_entry.is_dir(),
9392 cx.clone(),
9393 )
9394 .await;
9395 let response = WorktreeStore::handle_rename_project_entry(
9396 worktree_store,
9397 envelope.payload,
9398 cx.clone(),
9399 )
9400 .await;
9401 this.read_with(&cx, |this, _| {
9402 this.did_rename_entry(
9403 old_worktree_id,
9404 &old_abs_path,
9405 &new_abs_path,
9406 old_entry.is_dir(),
9407 );
9408 });
9409 response
9410 }
9411
9412 async fn handle_update_diagnostic_summary(
9413 this: Entity<Self>,
9414 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9415 mut cx: AsyncApp,
9416 ) -> Result<()> {
9417 this.update(&mut cx, |lsp_store, cx| {
9418 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9419 let mut updated_diagnostics_paths = HashMap::default();
9420 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9421 for message_summary in envelope
9422 .payload
9423 .summary
9424 .into_iter()
9425 .chain(envelope.payload.more_summaries)
9426 {
9427 let project_path = ProjectPath {
9428 worktree_id,
9429 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9430 };
9431 let path = project_path.path.clone();
9432 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9433 let summary = DiagnosticSummary {
9434 error_count: message_summary.error_count as usize,
9435 warning_count: message_summary.warning_count as usize,
9436 };
9437
9438 if summary.is_empty() {
9439 if let Some(worktree_summaries) =
9440 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9441 && let Some(summaries) = worktree_summaries.get_mut(&path)
9442 {
9443 summaries.remove(&server_id);
9444 if summaries.is_empty() {
9445 worktree_summaries.remove(&path);
9446 }
9447 }
9448 } else {
9449 lsp_store
9450 .diagnostic_summaries
9451 .entry(worktree_id)
9452 .or_default()
9453 .entry(path)
9454 .or_default()
9455 .insert(server_id, summary);
9456 }
9457
9458 if let Some((_, project_id)) = &lsp_store.downstream_client {
9459 match &mut diagnostics_summary {
9460 Some(diagnostics_summary) => {
9461 diagnostics_summary
9462 .more_summaries
9463 .push(proto::DiagnosticSummary {
9464 path: project_path.path.as_ref().to_proto(),
9465 language_server_id: server_id.0 as u64,
9466 error_count: summary.error_count as u32,
9467 warning_count: summary.warning_count as u32,
9468 })
9469 }
9470 None => {
9471 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9472 project_id: *project_id,
9473 worktree_id: worktree_id.to_proto(),
9474 summary: Some(proto::DiagnosticSummary {
9475 path: project_path.path.as_ref().to_proto(),
9476 language_server_id: server_id.0 as u64,
9477 error_count: summary.error_count as u32,
9478 warning_count: summary.warning_count as u32,
9479 }),
9480 more_summaries: Vec::new(),
9481 })
9482 }
9483 }
9484 }
9485 updated_diagnostics_paths
9486 .entry(server_id)
9487 .or_insert_with(Vec::new)
9488 .push(project_path);
9489 }
9490
9491 if let Some((diagnostics_summary, (downstream_client, _))) =
9492 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9493 {
9494 downstream_client.send(diagnostics_summary).log_err();
9495 }
9496 for (server_id, paths) in updated_diagnostics_paths {
9497 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9498 }
9499 Ok(())
9500 })
9501 }
9502
9503 async fn handle_start_language_server(
9504 lsp_store: Entity<Self>,
9505 envelope: TypedEnvelope<proto::StartLanguageServer>,
9506 mut cx: AsyncApp,
9507 ) -> Result<()> {
9508 let server = envelope.payload.server.context("invalid server")?;
9509 let server_capabilities =
9510 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9511 .with_context(|| {
9512 format!(
9513 "incorrect server capabilities {}",
9514 envelope.payload.capabilities
9515 )
9516 })?;
9517 lsp_store.update(&mut cx, |lsp_store, cx| {
9518 let server_id = LanguageServerId(server.id as usize);
9519 let server_name = LanguageServerName::from_proto(server.name.clone());
9520 lsp_store
9521 .lsp_server_capabilities
9522 .insert(server_id, server_capabilities);
9523 lsp_store.language_server_statuses.insert(
9524 server_id,
9525 LanguageServerStatus {
9526 name: server_name.clone(),
9527 server_version: None,
9528 server_readable_version: None,
9529 pending_work: Default::default(),
9530 has_pending_diagnostic_updates: false,
9531 progress_tokens: Default::default(),
9532 worktree: server.worktree_id.map(WorktreeId::from_proto),
9533 binary: None,
9534 configuration: None,
9535 workspace_folders: BTreeSet::new(),
9536 process_id: None,
9537 },
9538 );
9539 cx.emit(LspStoreEvent::LanguageServerAdded(
9540 server_id,
9541 server_name,
9542 server.worktree_id.map(WorktreeId::from_proto),
9543 ));
9544 cx.notify();
9545 });
9546 Ok(())
9547 }
9548
9549 async fn handle_update_language_server(
9550 lsp_store: Entity<Self>,
9551 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9552 mut cx: AsyncApp,
9553 ) -> Result<()> {
9554 lsp_store.update(&mut cx, |lsp_store, cx| {
9555 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9556
9557 match envelope.payload.variant.context("invalid variant")? {
9558 proto::update_language_server::Variant::WorkStart(payload) => {
9559 lsp_store.on_lsp_work_start(
9560 language_server_id,
9561 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9562 .context("invalid progress token value")?,
9563 LanguageServerProgress {
9564 title: payload.title,
9565 is_disk_based_diagnostics_progress: false,
9566 is_cancellable: payload.is_cancellable.unwrap_or(false),
9567 message: payload.message,
9568 percentage: payload.percentage.map(|p| p as usize),
9569 last_update_at: cx.background_executor().now(),
9570 },
9571 cx,
9572 );
9573 }
9574 proto::update_language_server::Variant::WorkProgress(payload) => {
9575 lsp_store.on_lsp_work_progress(
9576 language_server_id,
9577 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9578 .context("invalid progress token value")?,
9579 LanguageServerProgress {
9580 title: None,
9581 is_disk_based_diagnostics_progress: false,
9582 is_cancellable: payload.is_cancellable.unwrap_or(false),
9583 message: payload.message,
9584 percentage: payload.percentage.map(|p| p as usize),
9585 last_update_at: cx.background_executor().now(),
9586 },
9587 cx,
9588 );
9589 }
9590
9591 proto::update_language_server::Variant::WorkEnd(payload) => {
9592 lsp_store.on_lsp_work_end(
9593 language_server_id,
9594 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9595 .context("invalid progress token value")?,
9596 cx,
9597 );
9598 }
9599
9600 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9601 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9602 }
9603
9604 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9605 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9606 }
9607
9608 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9609 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9610 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9611 cx.emit(LspStoreEvent::LanguageServerUpdate {
9612 language_server_id,
9613 name: envelope
9614 .payload
9615 .server_name
9616 .map(SharedString::new)
9617 .map(LanguageServerName),
9618 message: non_lsp,
9619 });
9620 }
9621 }
9622
9623 Ok(())
9624 })
9625 }
9626
9627 async fn handle_language_server_log(
9628 this: Entity<Self>,
9629 envelope: TypedEnvelope<proto::LanguageServerLog>,
9630 mut cx: AsyncApp,
9631 ) -> Result<()> {
9632 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9633 let log_type = envelope
9634 .payload
9635 .log_type
9636 .map(LanguageServerLogType::from_proto)
9637 .context("invalid language server log type")?;
9638
9639 let message = envelope.payload.message;
9640
9641 this.update(&mut cx, |_, cx| {
9642 cx.emit(LspStoreEvent::LanguageServerLog(
9643 language_server_id,
9644 log_type,
9645 message,
9646 ));
9647 });
9648 Ok(())
9649 }
9650
9651 async fn handle_lsp_ext_cancel_flycheck(
9652 lsp_store: Entity<Self>,
9653 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9654 cx: AsyncApp,
9655 ) -> Result<proto::Ack> {
9656 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9657 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9658 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9659 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9660 } else {
9661 None
9662 }
9663 });
9664 if let Some(task) = task {
9665 task.context("handling lsp ext cancel flycheck")?;
9666 }
9667
9668 Ok(proto::Ack {})
9669 }
9670
9671 async fn handle_lsp_ext_run_flycheck(
9672 lsp_store: Entity<Self>,
9673 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9674 mut cx: AsyncApp,
9675 ) -> Result<proto::Ack> {
9676 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9677 lsp_store.update(&mut cx, |lsp_store, cx| {
9678 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9679 let text_document = if envelope.payload.current_file_only {
9680 let buffer_id = envelope
9681 .payload
9682 .buffer_id
9683 .map(|id| BufferId::new(id))
9684 .transpose()?;
9685 buffer_id
9686 .and_then(|buffer_id| {
9687 lsp_store
9688 .buffer_store()
9689 .read(cx)
9690 .get(buffer_id)
9691 .and_then(|buffer| {
9692 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9693 })
9694 .map(|path| make_text_document_identifier(&path))
9695 })
9696 .transpose()?
9697 } else {
9698 None
9699 };
9700 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9701 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9702 )?;
9703 }
9704 anyhow::Ok(())
9705 })?;
9706
9707 Ok(proto::Ack {})
9708 }
9709
9710 async fn handle_lsp_ext_clear_flycheck(
9711 lsp_store: Entity<Self>,
9712 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9713 cx: AsyncApp,
9714 ) -> Result<proto::Ack> {
9715 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9716 lsp_store.read_with(&cx, |lsp_store, _| {
9717 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9718 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9719 } else {
9720 None
9721 }
9722 });
9723
9724 Ok(proto::Ack {})
9725 }
9726
9727 pub fn disk_based_diagnostics_started(
9728 &mut self,
9729 language_server_id: LanguageServerId,
9730 cx: &mut Context<Self>,
9731 ) {
9732 if let Some(language_server_status) =
9733 self.language_server_statuses.get_mut(&language_server_id)
9734 {
9735 language_server_status.has_pending_diagnostic_updates = true;
9736 }
9737
9738 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9739 cx.emit(LspStoreEvent::LanguageServerUpdate {
9740 language_server_id,
9741 name: self
9742 .language_server_adapter_for_id(language_server_id)
9743 .map(|adapter| adapter.name()),
9744 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9745 Default::default(),
9746 ),
9747 })
9748 }
9749
9750 pub fn disk_based_diagnostics_finished(
9751 &mut self,
9752 language_server_id: LanguageServerId,
9753 cx: &mut Context<Self>,
9754 ) {
9755 if let Some(language_server_status) =
9756 self.language_server_statuses.get_mut(&language_server_id)
9757 {
9758 language_server_status.has_pending_diagnostic_updates = false;
9759 }
9760
9761 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9762 cx.emit(LspStoreEvent::LanguageServerUpdate {
9763 language_server_id,
9764 name: self
9765 .language_server_adapter_for_id(language_server_id)
9766 .map(|adapter| adapter.name()),
9767 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9768 Default::default(),
9769 ),
9770 })
9771 }
9772
9773 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9774 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9775 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9776 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9777 // the language server might take some time to publish diagnostics.
9778 fn simulate_disk_based_diagnostics_events_if_needed(
9779 &mut self,
9780 language_server_id: LanguageServerId,
9781 cx: &mut Context<Self>,
9782 ) {
9783 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9784
9785 let Some(LanguageServerState::Running {
9786 simulate_disk_based_diagnostics_completion,
9787 adapter,
9788 ..
9789 }) = self
9790 .as_local_mut()
9791 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9792 else {
9793 return;
9794 };
9795
9796 if adapter.disk_based_diagnostics_progress_token.is_some() {
9797 return;
9798 }
9799
9800 let prev_task =
9801 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9802 cx.background_executor()
9803 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9804 .await;
9805
9806 this.update(cx, |this, cx| {
9807 this.disk_based_diagnostics_finished(language_server_id, cx);
9808
9809 if let Some(LanguageServerState::Running {
9810 simulate_disk_based_diagnostics_completion,
9811 ..
9812 }) = this.as_local_mut().and_then(|local_store| {
9813 local_store.language_servers.get_mut(&language_server_id)
9814 }) {
9815 *simulate_disk_based_diagnostics_completion = None;
9816 }
9817 })
9818 .ok();
9819 }));
9820
9821 if prev_task.is_none() {
9822 self.disk_based_diagnostics_started(language_server_id, cx);
9823 }
9824 }
9825
9826 pub fn language_server_statuses(
9827 &self,
9828 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9829 self.language_server_statuses
9830 .iter()
9831 .map(|(key, value)| (*key, value))
9832 }
9833
9834 pub(super) fn did_rename_entry(
9835 &self,
9836 worktree_id: WorktreeId,
9837 old_path: &Path,
9838 new_path: &Path,
9839 is_dir: bool,
9840 ) {
9841 maybe!({
9842 let local_store = self.as_local()?;
9843
9844 let old_uri = lsp::Uri::from_file_path(old_path)
9845 .ok()
9846 .map(|uri| uri.to_string())?;
9847 let new_uri = lsp::Uri::from_file_path(new_path)
9848 .ok()
9849 .map(|uri| uri.to_string())?;
9850
9851 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9852 let Some(filter) = local_store
9853 .language_server_paths_watched_for_rename
9854 .get(&language_server.server_id())
9855 else {
9856 continue;
9857 };
9858
9859 if filter.should_send_did_rename(&old_uri, is_dir) {
9860 language_server
9861 .notify::<DidRenameFiles>(RenameFilesParams {
9862 files: vec![FileRename {
9863 old_uri: old_uri.clone(),
9864 new_uri: new_uri.clone(),
9865 }],
9866 })
9867 .ok();
9868 }
9869 }
9870 Some(())
9871 });
9872 }
9873
9874 pub(super) fn will_rename_entry(
9875 this: WeakEntity<Self>,
9876 worktree_id: WorktreeId,
9877 old_path: &Path,
9878 new_path: &Path,
9879 is_dir: bool,
9880 cx: AsyncApp,
9881 ) -> Task<ProjectTransaction> {
9882 let old_uri = lsp::Uri::from_file_path(old_path)
9883 .ok()
9884 .map(|uri| uri.to_string());
9885 let new_uri = lsp::Uri::from_file_path(new_path)
9886 .ok()
9887 .map(|uri| uri.to_string());
9888 cx.spawn(async move |cx| {
9889 let mut tasks = vec![];
9890 this.update(cx, |this, cx| {
9891 let local_store = this.as_local()?;
9892 let old_uri = old_uri?;
9893 let new_uri = new_uri?;
9894 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9895 let Some(filter) = local_store
9896 .language_server_paths_watched_for_rename
9897 .get(&language_server.server_id())
9898 else {
9899 continue;
9900 };
9901
9902 if !filter.should_send_will_rename(&old_uri, is_dir) {
9903 continue;
9904 }
9905 let request_timeout = ProjectSettings::get_global(cx)
9906 .global_lsp_settings
9907 .get_request_timeout();
9908
9909 let apply_edit = cx.spawn({
9910 let old_uri = old_uri.clone();
9911 let new_uri = new_uri.clone();
9912 let language_server = language_server.clone();
9913 async move |this, cx| {
9914 let edit = language_server
9915 .request::<WillRenameFiles>(
9916 RenameFilesParams {
9917 files: vec![FileRename { old_uri, new_uri }],
9918 },
9919 request_timeout,
9920 )
9921 .await
9922 .into_response()
9923 .context("will rename files")
9924 .log_err()
9925 .flatten()?;
9926
9927 LocalLspStore::deserialize_workspace_edit(
9928 this.upgrade()?,
9929 edit,
9930 false,
9931 language_server.clone(),
9932 cx,
9933 )
9934 .await
9935 .ok()
9936 }
9937 });
9938 tasks.push(apply_edit);
9939 }
9940 Some(())
9941 })
9942 .ok()
9943 .flatten();
9944 let mut merged_transaction = ProjectTransaction::default();
9945 for task in tasks {
9946 // Await on tasks sequentially so that the order of application of edits is deterministic
9947 // (at least with regards to the order of registration of language servers)
9948 if let Some(transaction) = task.await {
9949 for (buffer, buffer_transaction) in transaction.0 {
9950 merged_transaction.0.insert(buffer, buffer_transaction);
9951 }
9952 }
9953 }
9954 merged_transaction
9955 })
9956 }
9957
9958 fn lsp_notify_abs_paths_changed(
9959 &mut self,
9960 server_id: LanguageServerId,
9961 changes: Vec<PathEvent>,
9962 ) {
9963 maybe!({
9964 let server = self.language_server_for_id(server_id)?;
9965 let changes = changes
9966 .into_iter()
9967 .filter_map(|event| {
9968 let typ = match event.kind? {
9969 PathEventKind::Created => lsp::FileChangeType::CREATED,
9970 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9971 PathEventKind::Changed | PathEventKind::Rescan => {
9972 lsp::FileChangeType::CHANGED
9973 }
9974 };
9975 Some(lsp::FileEvent {
9976 uri: file_path_to_lsp_url(&event.path).log_err()?,
9977 typ,
9978 })
9979 })
9980 .collect::<Vec<_>>();
9981 if !changes.is_empty() {
9982 server
9983 .notify::<lsp::notification::DidChangeWatchedFiles>(
9984 lsp::DidChangeWatchedFilesParams { changes },
9985 )
9986 .ok();
9987 }
9988 Some(())
9989 });
9990 }
9991
9992 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9993 self.as_local()?.language_server_for_id(id)
9994 }
9995
9996 fn on_lsp_progress(
9997 &mut self,
9998 progress_params: lsp::ProgressParams,
9999 language_server_id: LanguageServerId,
10000 disk_based_diagnostics_progress_token: Option<String>,
10001 cx: &mut Context<Self>,
10002 ) {
10003 match progress_params.value {
10004 lsp::ProgressParamsValue::WorkDone(progress) => {
10005 self.handle_work_done_progress(
10006 progress,
10007 language_server_id,
10008 disk_based_diagnostics_progress_token,
10009 ProgressToken::from_lsp(progress_params.token),
10010 cx,
10011 );
10012 }
10013 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10014 let registration_id = match progress_params.token {
10015 lsp::NumberOrString::Number(_) => None,
10016 lsp::NumberOrString::String(token) => token
10017 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10018 .map(|(_, id)| id.to_owned()),
10019 };
10020 if let Some(LanguageServerState::Running {
10021 workspace_diagnostics_refresh_tasks,
10022 ..
10023 }) = self
10024 .as_local_mut()
10025 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10026 && let Some(workspace_diagnostics) =
10027 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10028 {
10029 workspace_diagnostics.progress_tx.try_send(()).ok();
10030 self.apply_workspace_diagnostic_report(
10031 language_server_id,
10032 report,
10033 registration_id.map(SharedString::from),
10034 cx,
10035 )
10036 }
10037 }
10038 }
10039 }
10040
10041 fn handle_work_done_progress(
10042 &mut self,
10043 progress: lsp::WorkDoneProgress,
10044 language_server_id: LanguageServerId,
10045 disk_based_diagnostics_progress_token: Option<String>,
10046 token: ProgressToken,
10047 cx: &mut Context<Self>,
10048 ) {
10049 let language_server_status =
10050 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10051 status
10052 } else {
10053 return;
10054 };
10055
10056 if !language_server_status.progress_tokens.contains(&token) {
10057 return;
10058 }
10059
10060 let is_disk_based_diagnostics_progress =
10061 if let (Some(disk_based_token), ProgressToken::String(token)) =
10062 (&disk_based_diagnostics_progress_token, &token)
10063 {
10064 token.starts_with(disk_based_token)
10065 } else {
10066 false
10067 };
10068
10069 match progress {
10070 lsp::WorkDoneProgress::Begin(report) => {
10071 if is_disk_based_diagnostics_progress {
10072 self.disk_based_diagnostics_started(language_server_id, cx);
10073 }
10074 self.on_lsp_work_start(
10075 language_server_id,
10076 token.clone(),
10077 LanguageServerProgress {
10078 title: Some(report.title),
10079 is_disk_based_diagnostics_progress,
10080 is_cancellable: report.cancellable.unwrap_or(false),
10081 message: report.message.clone(),
10082 percentage: report.percentage.map(|p| p as usize),
10083 last_update_at: cx.background_executor().now(),
10084 },
10085 cx,
10086 );
10087 }
10088 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10089 language_server_id,
10090 token,
10091 LanguageServerProgress {
10092 title: None,
10093 is_disk_based_diagnostics_progress,
10094 is_cancellable: report.cancellable.unwrap_or(false),
10095 message: report.message,
10096 percentage: report.percentage.map(|p| p as usize),
10097 last_update_at: cx.background_executor().now(),
10098 },
10099 cx,
10100 ),
10101 lsp::WorkDoneProgress::End(_) => {
10102 language_server_status.progress_tokens.remove(&token);
10103 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10104 if is_disk_based_diagnostics_progress {
10105 self.disk_based_diagnostics_finished(language_server_id, cx);
10106 }
10107 }
10108 }
10109 }
10110
10111 fn on_lsp_work_start(
10112 &mut self,
10113 language_server_id: LanguageServerId,
10114 token: ProgressToken,
10115 progress: LanguageServerProgress,
10116 cx: &mut Context<Self>,
10117 ) {
10118 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10119 status.pending_work.insert(token.clone(), progress.clone());
10120 cx.notify();
10121 }
10122 cx.emit(LspStoreEvent::LanguageServerUpdate {
10123 language_server_id,
10124 name: self
10125 .language_server_adapter_for_id(language_server_id)
10126 .map(|adapter| adapter.name()),
10127 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10128 token: Some(token.to_proto()),
10129 title: progress.title,
10130 message: progress.message,
10131 percentage: progress.percentage.map(|p| p as u32),
10132 is_cancellable: Some(progress.is_cancellable),
10133 }),
10134 })
10135 }
10136
10137 fn on_lsp_work_progress(
10138 &mut self,
10139 language_server_id: LanguageServerId,
10140 token: ProgressToken,
10141 progress: LanguageServerProgress,
10142 cx: &mut Context<Self>,
10143 ) {
10144 let mut did_update = false;
10145 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10146 match status.pending_work.entry(token.clone()) {
10147 btree_map::Entry::Vacant(entry) => {
10148 entry.insert(progress.clone());
10149 did_update = true;
10150 }
10151 btree_map::Entry::Occupied(mut entry) => {
10152 let entry = entry.get_mut();
10153 if (progress.last_update_at - entry.last_update_at)
10154 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10155 {
10156 entry.last_update_at = progress.last_update_at;
10157 if progress.message.is_some() {
10158 entry.message = progress.message.clone();
10159 }
10160 if progress.percentage.is_some() {
10161 entry.percentage = progress.percentage;
10162 }
10163 if progress.is_cancellable != entry.is_cancellable {
10164 entry.is_cancellable = progress.is_cancellable;
10165 }
10166 did_update = true;
10167 }
10168 }
10169 }
10170 }
10171
10172 if did_update {
10173 cx.emit(LspStoreEvent::LanguageServerUpdate {
10174 language_server_id,
10175 name: self
10176 .language_server_adapter_for_id(language_server_id)
10177 .map(|adapter| adapter.name()),
10178 message: proto::update_language_server::Variant::WorkProgress(
10179 proto::LspWorkProgress {
10180 token: Some(token.to_proto()),
10181 message: progress.message,
10182 percentage: progress.percentage.map(|p| p as u32),
10183 is_cancellable: Some(progress.is_cancellable),
10184 },
10185 ),
10186 })
10187 }
10188 }
10189
10190 fn on_lsp_work_end(
10191 &mut self,
10192 language_server_id: LanguageServerId,
10193 token: ProgressToken,
10194 cx: &mut Context<Self>,
10195 ) {
10196 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10197 if let Some(work) = status.pending_work.remove(&token)
10198 && !work.is_disk_based_diagnostics_progress
10199 {
10200 cx.emit(LspStoreEvent::RefreshInlayHints {
10201 server_id: language_server_id,
10202 request_id: None,
10203 });
10204 }
10205 cx.notify();
10206 }
10207
10208 cx.emit(LspStoreEvent::LanguageServerUpdate {
10209 language_server_id,
10210 name: self
10211 .language_server_adapter_for_id(language_server_id)
10212 .map(|adapter| adapter.name()),
10213 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10214 token: Some(token.to_proto()),
10215 }),
10216 })
10217 }
10218
10219 pub async fn handle_resolve_completion_documentation(
10220 this: Entity<Self>,
10221 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10222 mut cx: AsyncApp,
10223 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10224 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10225
10226 let completion = this
10227 .read_with(&cx, |this, cx| {
10228 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10229 let server = this
10230 .language_server_for_id(id)
10231 .with_context(|| format!("No language server {id}"))?;
10232
10233 let request_timeout = ProjectSettings::get_global(cx)
10234 .global_lsp_settings
10235 .get_request_timeout();
10236
10237 anyhow::Ok(cx.background_spawn(async move {
10238 let can_resolve = server
10239 .capabilities()
10240 .completion_provider
10241 .as_ref()
10242 .and_then(|options| options.resolve_provider)
10243 .unwrap_or(false);
10244 if can_resolve {
10245 server
10246 .request::<lsp::request::ResolveCompletionItem>(
10247 lsp_completion,
10248 request_timeout,
10249 )
10250 .await
10251 .into_response()
10252 .context("resolve completion item")
10253 } else {
10254 anyhow::Ok(lsp_completion)
10255 }
10256 }))
10257 })?
10258 .await?;
10259
10260 let mut documentation_is_markdown = false;
10261 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10262 let documentation = match completion.documentation {
10263 Some(lsp::Documentation::String(text)) => text,
10264
10265 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10266 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10267 value
10268 }
10269
10270 _ => String::new(),
10271 };
10272
10273 // If we have a new buffer_id, that means we're talking to a new client
10274 // and want to check for new text_edits in the completion too.
10275 let mut old_replace_start = None;
10276 let mut old_replace_end = None;
10277 let mut old_insert_start = None;
10278 let mut old_insert_end = None;
10279 let mut new_text = String::default();
10280 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10281 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10282 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10283 anyhow::Ok(buffer.read(cx).snapshot())
10284 })?;
10285
10286 if let Some(text_edit) = completion.text_edit.as_ref() {
10287 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10288
10289 if let Some(mut edit) = edit {
10290 LineEnding::normalize(&mut edit.new_text);
10291
10292 new_text = edit.new_text;
10293 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10294 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10295 if let Some(insert_range) = edit.insert_range {
10296 old_insert_start = Some(serialize_anchor(&insert_range.start));
10297 old_insert_end = Some(serialize_anchor(&insert_range.end));
10298 }
10299 }
10300 }
10301 }
10302
10303 Ok(proto::ResolveCompletionDocumentationResponse {
10304 documentation,
10305 documentation_is_markdown,
10306 old_replace_start,
10307 old_replace_end,
10308 new_text,
10309 lsp_completion,
10310 old_insert_start,
10311 old_insert_end,
10312 })
10313 }
10314
10315 async fn handle_on_type_formatting(
10316 this: Entity<Self>,
10317 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10318 mut cx: AsyncApp,
10319 ) -> Result<proto::OnTypeFormattingResponse> {
10320 let on_type_formatting = this.update(&mut cx, |this, cx| {
10321 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10322 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10323 let position = envelope
10324 .payload
10325 .position
10326 .and_then(deserialize_anchor)
10327 .context("invalid position")?;
10328 anyhow::Ok(this.apply_on_type_formatting(
10329 buffer,
10330 position,
10331 envelope.payload.trigger.clone(),
10332 cx,
10333 ))
10334 })?;
10335
10336 let transaction = on_type_formatting
10337 .await?
10338 .as_ref()
10339 .map(language::proto::serialize_transaction);
10340 Ok(proto::OnTypeFormattingResponse { transaction })
10341 }
10342
10343 async fn handle_pull_workspace_diagnostics(
10344 lsp_store: Entity<Self>,
10345 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10346 mut cx: AsyncApp,
10347 ) -> Result<proto::Ack> {
10348 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10349 lsp_store.update(&mut cx, |lsp_store, _| {
10350 lsp_store.pull_workspace_diagnostics(server_id);
10351 });
10352 Ok(proto::Ack {})
10353 }
10354
10355 async fn handle_open_buffer_for_symbol(
10356 this: Entity<Self>,
10357 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10358 mut cx: AsyncApp,
10359 ) -> Result<proto::OpenBufferForSymbolResponse> {
10360 let peer_id = envelope.original_sender_id().unwrap_or_default();
10361 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10362 let symbol = Self::deserialize_symbol(symbol)?;
10363 this.read_with(&cx, |this, _| {
10364 if let SymbolLocation::OutsideProject {
10365 abs_path,
10366 signature,
10367 } = &symbol.path
10368 {
10369 let new_signature = this.symbol_signature(&abs_path);
10370 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10371 }
10372 Ok(())
10373 })?;
10374 let buffer = this
10375 .update(&mut cx, |this, cx| {
10376 this.open_buffer_for_symbol(
10377 &Symbol {
10378 language_server_name: symbol.language_server_name,
10379 source_worktree_id: symbol.source_worktree_id,
10380 source_language_server_id: symbol.source_language_server_id,
10381 path: symbol.path,
10382 name: symbol.name,
10383 kind: symbol.kind,
10384 range: symbol.range,
10385 label: CodeLabel::default(),
10386 container_name: symbol.container_name,
10387 },
10388 cx,
10389 )
10390 })
10391 .await?;
10392
10393 this.update(&mut cx, |this, cx| {
10394 let is_private = buffer
10395 .read(cx)
10396 .file()
10397 .map(|f| f.is_private())
10398 .unwrap_or_default();
10399 if is_private {
10400 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10401 } else {
10402 this.buffer_store
10403 .update(cx, |buffer_store, cx| {
10404 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10405 })
10406 .detach_and_log_err(cx);
10407 let buffer_id = buffer.read(cx).remote_id().to_proto();
10408 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10409 }
10410 })
10411 }
10412
10413 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10414 let mut hasher = Sha256::new();
10415 hasher.update(abs_path.to_string_lossy().as_bytes());
10416 hasher.update(self.nonce.to_be_bytes());
10417 hasher.finalize().as_slice().try_into().unwrap()
10418 }
10419
10420 pub async fn handle_get_project_symbols(
10421 this: Entity<Self>,
10422 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10423 mut cx: AsyncApp,
10424 ) -> Result<proto::GetProjectSymbolsResponse> {
10425 let symbols = this
10426 .update(&mut cx, |this, cx| {
10427 this.symbols(&envelope.payload.query, cx)
10428 })
10429 .await?;
10430
10431 Ok(proto::GetProjectSymbolsResponse {
10432 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10433 })
10434 }
10435
10436 pub async fn handle_restart_language_servers(
10437 this: Entity<Self>,
10438 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10439 mut cx: AsyncApp,
10440 ) -> Result<proto::Ack> {
10441 this.update(&mut cx, |lsp_store, cx| {
10442 let buffers =
10443 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10444 lsp_store.restart_language_servers_for_buffers(
10445 buffers,
10446 envelope
10447 .payload
10448 .only_servers
10449 .into_iter()
10450 .filter_map(|selector| {
10451 Some(match selector.selector? {
10452 proto::language_server_selector::Selector::ServerId(server_id) => {
10453 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10454 }
10455 proto::language_server_selector::Selector::Name(name) => {
10456 LanguageServerSelector::Name(LanguageServerName(
10457 SharedString::from(name),
10458 ))
10459 }
10460 })
10461 })
10462 .collect(),
10463 cx,
10464 );
10465 });
10466
10467 Ok(proto::Ack {})
10468 }
10469
10470 pub async fn handle_stop_language_servers(
10471 lsp_store: Entity<Self>,
10472 envelope: TypedEnvelope<proto::StopLanguageServers>,
10473 mut cx: AsyncApp,
10474 ) -> Result<proto::Ack> {
10475 lsp_store.update(&mut cx, |lsp_store, cx| {
10476 if envelope.payload.all
10477 && envelope.payload.also_servers.is_empty()
10478 && envelope.payload.buffer_ids.is_empty()
10479 {
10480 lsp_store.stop_all_language_servers(cx);
10481 } else {
10482 let buffers =
10483 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10484 lsp_store
10485 .stop_language_servers_for_buffers(
10486 buffers,
10487 envelope
10488 .payload
10489 .also_servers
10490 .into_iter()
10491 .filter_map(|selector| {
10492 Some(match selector.selector? {
10493 proto::language_server_selector::Selector::ServerId(
10494 server_id,
10495 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10496 server_id,
10497 )),
10498 proto::language_server_selector::Selector::Name(name) => {
10499 LanguageServerSelector::Name(LanguageServerName(
10500 SharedString::from(name),
10501 ))
10502 }
10503 })
10504 })
10505 .collect(),
10506 cx,
10507 )
10508 .detach_and_log_err(cx);
10509 }
10510 });
10511
10512 Ok(proto::Ack {})
10513 }
10514
10515 pub async fn handle_cancel_language_server_work(
10516 lsp_store: Entity<Self>,
10517 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10518 mut cx: AsyncApp,
10519 ) -> Result<proto::Ack> {
10520 lsp_store.update(&mut cx, |lsp_store, cx| {
10521 if let Some(work) = envelope.payload.work {
10522 match work {
10523 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10524 let buffers =
10525 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10526 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10527 }
10528 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10529 let server_id = LanguageServerId::from_proto(work.language_server_id);
10530 let token = work
10531 .token
10532 .map(|token| {
10533 ProgressToken::from_proto(token)
10534 .context("invalid work progress token")
10535 })
10536 .transpose()?;
10537 lsp_store.cancel_language_server_work(server_id, token, cx);
10538 }
10539 }
10540 }
10541 anyhow::Ok(())
10542 })?;
10543
10544 Ok(proto::Ack {})
10545 }
10546
10547 fn buffer_ids_to_buffers(
10548 &mut self,
10549 buffer_ids: impl Iterator<Item = u64>,
10550 cx: &mut Context<Self>,
10551 ) -> Vec<Entity<Buffer>> {
10552 buffer_ids
10553 .into_iter()
10554 .flat_map(|buffer_id| {
10555 self.buffer_store
10556 .read(cx)
10557 .get(BufferId::new(buffer_id).log_err()?)
10558 })
10559 .collect::<Vec<_>>()
10560 }
10561
10562 async fn handle_apply_additional_edits_for_completion(
10563 this: Entity<Self>,
10564 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10565 mut cx: AsyncApp,
10566 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10567 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10568 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10569 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10570 let completion = Self::deserialize_completion(
10571 envelope.payload.completion.context("invalid completion")?,
10572 )?;
10573 let all_commit_ranges = envelope
10574 .payload
10575 .all_commit_ranges
10576 .into_iter()
10577 .map(language::proto::deserialize_anchor_range)
10578 .collect::<Result<Vec<_>, _>>()?;
10579 anyhow::Ok((buffer, completion, all_commit_ranges))
10580 })?;
10581
10582 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10583 this.apply_additional_edits_for_completion(
10584 buffer,
10585 Rc::new(RefCell::new(Box::new([Completion {
10586 replace_range: completion.replace_range,
10587 new_text: completion.new_text,
10588 source: completion.source,
10589 documentation: None,
10590 label: CodeLabel::default(),
10591 match_start: None,
10592 snippet_deduplication_key: None,
10593 insert_text_mode: None,
10594 icon_path: None,
10595 confirm: None,
10596 }]))),
10597 0,
10598 false,
10599 all_commit_ranges,
10600 cx,
10601 )
10602 });
10603
10604 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10605 transaction: apply_additional_edits
10606 .await?
10607 .as_ref()
10608 .map(language::proto::serialize_transaction),
10609 })
10610 }
10611
10612 pub fn last_formatting_failure(&self) -> Option<&str> {
10613 self.last_formatting_failure.as_deref()
10614 }
10615
10616 pub fn reset_last_formatting_failure(&mut self) {
10617 self.last_formatting_failure = None;
10618 }
10619
10620 pub fn environment_for_buffer(
10621 &self,
10622 buffer: &Entity<Buffer>,
10623 cx: &mut Context<Self>,
10624 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10625 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10626 environment.update(cx, |env, cx| {
10627 env.buffer_environment(buffer, &self.worktree_store, cx)
10628 })
10629 } else {
10630 Task::ready(None).shared()
10631 }
10632 }
10633
10634 pub fn format(
10635 &mut self,
10636 buffers: HashSet<Entity<Buffer>>,
10637 target: LspFormatTarget,
10638 push_to_history: bool,
10639 trigger: FormatTrigger,
10640 cx: &mut Context<Self>,
10641 ) -> Task<anyhow::Result<ProjectTransaction>> {
10642 let logger = zlog::scoped!("format");
10643 if self.as_local().is_some() {
10644 zlog::trace!(logger => "Formatting locally");
10645 let logger = zlog::scoped!(logger => "local");
10646 let buffers = buffers
10647 .into_iter()
10648 .map(|buffer_handle| {
10649 let buffer = buffer_handle.read(cx);
10650 let buffer_abs_path = File::from_dyn(buffer.file())
10651 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10652
10653 (buffer_handle, buffer_abs_path, buffer.remote_id())
10654 })
10655 .collect::<Vec<_>>();
10656
10657 cx.spawn(async move |lsp_store, cx| {
10658 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10659
10660 for (handle, abs_path, id) in buffers {
10661 let env = lsp_store
10662 .update(cx, |lsp_store, cx| {
10663 lsp_store.environment_for_buffer(&handle, cx)
10664 })?
10665 .await;
10666
10667 let ranges = match &target {
10668 LspFormatTarget::Buffers => None,
10669 LspFormatTarget::Ranges(ranges) => {
10670 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10671 }
10672 };
10673
10674 formattable_buffers.push(FormattableBuffer {
10675 handle,
10676 abs_path,
10677 env,
10678 ranges,
10679 });
10680 }
10681 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10682
10683 let format_timer = zlog::time!(logger => "Formatting buffers");
10684 let result = LocalLspStore::format_locally(
10685 lsp_store.clone(),
10686 formattable_buffers,
10687 push_to_history,
10688 trigger,
10689 logger,
10690 cx,
10691 )
10692 .await;
10693 format_timer.end();
10694
10695 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10696
10697 lsp_store.update(cx, |lsp_store, _| {
10698 lsp_store.update_last_formatting_failure(&result);
10699 })?;
10700
10701 result
10702 })
10703 } else if let Some((client, project_id)) = self.upstream_client() {
10704 zlog::trace!(logger => "Formatting remotely");
10705 let logger = zlog::scoped!(logger => "remote");
10706
10707 let buffer_ranges = match &target {
10708 LspFormatTarget::Buffers => Vec::new(),
10709 LspFormatTarget::Ranges(ranges) => ranges
10710 .iter()
10711 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10712 buffer_id: buffer_id.to_proto(),
10713 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10714 })
10715 .collect(),
10716 };
10717
10718 let buffer_store = self.buffer_store();
10719 cx.spawn(async move |lsp_store, cx| {
10720 zlog::trace!(logger => "Sending remote format request");
10721 let request_timer = zlog::time!(logger => "remote format request");
10722 let result = client
10723 .request(proto::FormatBuffers {
10724 project_id,
10725 trigger: trigger as i32,
10726 buffer_ids: buffers
10727 .iter()
10728 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10729 .collect(),
10730 buffer_ranges,
10731 })
10732 .await
10733 .and_then(|result| result.transaction.context("missing transaction"));
10734 request_timer.end();
10735
10736 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10737
10738 lsp_store.update(cx, |lsp_store, _| {
10739 lsp_store.update_last_formatting_failure(&result);
10740 })?;
10741
10742 let transaction_response = result?;
10743 let _timer = zlog::time!(logger => "deserializing project transaction");
10744 buffer_store
10745 .update(cx, |buffer_store, cx| {
10746 buffer_store.deserialize_project_transaction(
10747 transaction_response,
10748 push_to_history,
10749 cx,
10750 )
10751 })
10752 .await
10753 })
10754 } else {
10755 zlog::trace!(logger => "Not formatting");
10756 Task::ready(Ok(ProjectTransaction::default()))
10757 }
10758 }
10759
10760 async fn handle_format_buffers(
10761 this: Entity<Self>,
10762 envelope: TypedEnvelope<proto::FormatBuffers>,
10763 mut cx: AsyncApp,
10764 ) -> Result<proto::FormatBuffersResponse> {
10765 let sender_id = envelope.original_sender_id().unwrap_or_default();
10766 let format = this.update(&mut cx, |this, cx| {
10767 let mut buffers = HashSet::default();
10768 for buffer_id in &envelope.payload.buffer_ids {
10769 let buffer_id = BufferId::new(*buffer_id)?;
10770 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10771 }
10772
10773 let target = if envelope.payload.buffer_ranges.is_empty() {
10774 LspFormatTarget::Buffers
10775 } else {
10776 let mut ranges_map = BTreeMap::new();
10777 for buffer_range in &envelope.payload.buffer_ranges {
10778 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10779 let ranges: Result<Vec<_>> = buffer_range
10780 .ranges
10781 .iter()
10782 .map(|range| {
10783 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10784 })
10785 .collect();
10786 ranges_map.insert(buffer_id, ranges?);
10787 }
10788 LspFormatTarget::Ranges(ranges_map)
10789 };
10790
10791 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10792 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10793 })?;
10794
10795 let project_transaction = format.await?;
10796 let project_transaction = this.update(&mut cx, |this, cx| {
10797 this.buffer_store.update(cx, |buffer_store, cx| {
10798 buffer_store.serialize_project_transaction_for_peer(
10799 project_transaction,
10800 sender_id,
10801 cx,
10802 )
10803 })
10804 });
10805 Ok(proto::FormatBuffersResponse {
10806 transaction: Some(project_transaction),
10807 })
10808 }
10809
10810 async fn handle_apply_code_action_kind(
10811 this: Entity<Self>,
10812 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10813 mut cx: AsyncApp,
10814 ) -> Result<proto::ApplyCodeActionKindResponse> {
10815 let sender_id = envelope.original_sender_id().unwrap_or_default();
10816 let format = this.update(&mut cx, |this, cx| {
10817 let mut buffers = HashSet::default();
10818 for buffer_id in &envelope.payload.buffer_ids {
10819 let buffer_id = BufferId::new(*buffer_id)?;
10820 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10821 }
10822 let kind = match envelope.payload.kind.as_str() {
10823 "" => CodeActionKind::EMPTY,
10824 "quickfix" => CodeActionKind::QUICKFIX,
10825 "refactor" => CodeActionKind::REFACTOR,
10826 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10827 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10828 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10829 "source" => CodeActionKind::SOURCE,
10830 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10831 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10832 _ => anyhow::bail!(
10833 "Invalid code action kind {}",
10834 envelope.payload.kind.as_str()
10835 ),
10836 };
10837 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10838 })?;
10839
10840 let project_transaction = format.await?;
10841 let project_transaction = this.update(&mut cx, |this, cx| {
10842 this.buffer_store.update(cx, |buffer_store, cx| {
10843 buffer_store.serialize_project_transaction_for_peer(
10844 project_transaction,
10845 sender_id,
10846 cx,
10847 )
10848 })
10849 });
10850 Ok(proto::ApplyCodeActionKindResponse {
10851 transaction: Some(project_transaction),
10852 })
10853 }
10854
10855 async fn shutdown_language_server(
10856 server_state: Option<LanguageServerState>,
10857 name: LanguageServerName,
10858 cx: &mut AsyncApp,
10859 ) {
10860 let server = match server_state {
10861 Some(LanguageServerState::Starting { startup, .. }) => {
10862 let mut timer = cx
10863 .background_executor()
10864 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10865 .fuse();
10866
10867 select! {
10868 server = startup.fuse() => server,
10869 () = timer => {
10870 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10871 None
10872 },
10873 }
10874 }
10875
10876 Some(LanguageServerState::Running { server, .. }) => Some(server),
10877
10878 None => None,
10879 };
10880
10881 let Some(server) = server else { return };
10882 if let Some(shutdown) = server.shutdown() {
10883 shutdown.await;
10884 }
10885 }
10886
10887 // Returns a list of all of the worktrees which no longer have a language server and the root path
10888 // for the stopped server
10889 fn stop_local_language_server(
10890 &mut self,
10891 server_id: LanguageServerId,
10892 cx: &mut Context<Self>,
10893 ) -> Task<()> {
10894 let local = match &mut self.mode {
10895 LspStoreMode::Local(local) => local,
10896 _ => {
10897 return Task::ready(());
10898 }
10899 };
10900
10901 // Remove this server ID from all entries in the given worktree.
10902 local
10903 .language_server_ids
10904 .retain(|_, state| state.id != server_id);
10905 self.buffer_store.update(cx, |buffer_store, cx| {
10906 for buffer in buffer_store.buffers() {
10907 buffer.update(cx, |buffer, cx| {
10908 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10909 buffer.set_completion_triggers(server_id, Default::default(), cx);
10910 });
10911 }
10912 });
10913
10914 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10915 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10916 summaries.retain(|path, summaries_by_server_id| {
10917 if summaries_by_server_id.remove(&server_id).is_some() {
10918 if let Some((client, project_id)) = self.downstream_client.clone() {
10919 client
10920 .send(proto::UpdateDiagnosticSummary {
10921 project_id,
10922 worktree_id: worktree_id.to_proto(),
10923 summary: Some(proto::DiagnosticSummary {
10924 path: path.as_ref().to_proto(),
10925 language_server_id: server_id.0 as u64,
10926 error_count: 0,
10927 warning_count: 0,
10928 }),
10929 more_summaries: Vec::new(),
10930 })
10931 .log_err();
10932 }
10933 cleared_paths.push(ProjectPath {
10934 worktree_id: *worktree_id,
10935 path: path.clone(),
10936 });
10937 !summaries_by_server_id.is_empty()
10938 } else {
10939 true
10940 }
10941 });
10942 }
10943 if !cleared_paths.is_empty() {
10944 cx.emit(LspStoreEvent::DiagnosticsUpdated {
10945 server_id,
10946 paths: cleared_paths,
10947 });
10948 }
10949
10950 let local = self.as_local_mut().unwrap();
10951 for diagnostics in local.diagnostics.values_mut() {
10952 diagnostics.retain(|_, diagnostics_by_server_id| {
10953 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10954 diagnostics_by_server_id.remove(ix);
10955 !diagnostics_by_server_id.is_empty()
10956 } else {
10957 true
10958 }
10959 });
10960 }
10961 local.language_server_watched_paths.remove(&server_id);
10962
10963 let server_state = local.language_servers.remove(&server_id);
10964 self.cleanup_lsp_data(server_id);
10965 let name = self
10966 .language_server_statuses
10967 .remove(&server_id)
10968 .map(|status| status.name)
10969 .or_else(|| {
10970 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10971 Some(adapter.name())
10972 } else {
10973 None
10974 }
10975 });
10976
10977 if let Some(name) = name {
10978 log::info!("stopping language server {name}");
10979 self.languages
10980 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10981 cx.notify();
10982
10983 return cx.spawn(async move |lsp_store, cx| {
10984 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10985 lsp_store
10986 .update(cx, |lsp_store, cx| {
10987 lsp_store
10988 .languages
10989 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10990 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10991 cx.notify();
10992 })
10993 .ok();
10994 });
10995 }
10996
10997 if server_state.is_some() {
10998 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10999 }
11000 Task::ready(())
11001 }
11002
11003 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11004 self.shutdown_all_language_servers(cx).detach();
11005 }
11006
11007 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11008 if let Some((client, project_id)) = self.upstream_client() {
11009 let request = client.request(proto::StopLanguageServers {
11010 project_id,
11011 buffer_ids: Vec::new(),
11012 also_servers: Vec::new(),
11013 all: true,
11014 });
11015 cx.background_spawn(async move {
11016 request.await.ok();
11017 })
11018 } else {
11019 let Some(local) = self.as_local_mut() else {
11020 return Task::ready(());
11021 };
11022 let language_servers_to_stop = local
11023 .language_server_ids
11024 .values()
11025 .map(|state| state.id)
11026 .collect();
11027 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11028 let tasks = language_servers_to_stop
11029 .into_iter()
11030 .map(|server| self.stop_local_language_server(server, cx))
11031 .collect::<Vec<_>>();
11032 cx.background_spawn(async move {
11033 futures::future::join_all(tasks).await;
11034 })
11035 }
11036 }
11037
11038 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11039 let buffers = self.buffer_store.read(cx).buffers().collect();
11040 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11041 }
11042
11043 pub fn restart_language_servers_for_buffers(
11044 &mut self,
11045 buffers: Vec<Entity<Buffer>>,
11046 only_restart_servers: HashSet<LanguageServerSelector>,
11047 cx: &mut Context<Self>,
11048 ) {
11049 if let Some((client, project_id)) = self.upstream_client() {
11050 let request = client.request(proto::RestartLanguageServers {
11051 project_id,
11052 buffer_ids: buffers
11053 .into_iter()
11054 .map(|b| b.read(cx).remote_id().to_proto())
11055 .collect(),
11056 only_servers: only_restart_servers
11057 .into_iter()
11058 .map(|selector| {
11059 let selector = match selector {
11060 LanguageServerSelector::Id(language_server_id) => {
11061 proto::language_server_selector::Selector::ServerId(
11062 language_server_id.to_proto(),
11063 )
11064 }
11065 LanguageServerSelector::Name(language_server_name) => {
11066 proto::language_server_selector::Selector::Name(
11067 language_server_name.to_string(),
11068 )
11069 }
11070 };
11071 proto::LanguageServerSelector {
11072 selector: Some(selector),
11073 }
11074 })
11075 .collect(),
11076 all: false,
11077 });
11078 cx.background_spawn(request).detach_and_log_err(cx);
11079 } else {
11080 let stop_task = if only_restart_servers.is_empty() {
11081 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11082 } else {
11083 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11084 };
11085 cx.spawn(async move |lsp_store, cx| {
11086 stop_task.await;
11087 lsp_store.update(cx, |lsp_store, cx| {
11088 for buffer in buffers {
11089 lsp_store.register_buffer_with_language_servers(
11090 &buffer,
11091 only_restart_servers.clone(),
11092 true,
11093 cx,
11094 );
11095 }
11096 })
11097 })
11098 .detach();
11099 }
11100 }
11101
11102 pub fn stop_language_servers_for_buffers(
11103 &mut self,
11104 buffers: Vec<Entity<Buffer>>,
11105 also_stop_servers: HashSet<LanguageServerSelector>,
11106 cx: &mut Context<Self>,
11107 ) -> Task<Result<()>> {
11108 if let Some((client, project_id)) = self.upstream_client() {
11109 let request = client.request(proto::StopLanguageServers {
11110 project_id,
11111 buffer_ids: buffers
11112 .into_iter()
11113 .map(|b| b.read(cx).remote_id().to_proto())
11114 .collect(),
11115 also_servers: also_stop_servers
11116 .into_iter()
11117 .map(|selector| {
11118 let selector = match selector {
11119 LanguageServerSelector::Id(language_server_id) => {
11120 proto::language_server_selector::Selector::ServerId(
11121 language_server_id.to_proto(),
11122 )
11123 }
11124 LanguageServerSelector::Name(language_server_name) => {
11125 proto::language_server_selector::Selector::Name(
11126 language_server_name.to_string(),
11127 )
11128 }
11129 };
11130 proto::LanguageServerSelector {
11131 selector: Some(selector),
11132 }
11133 })
11134 .collect(),
11135 all: false,
11136 });
11137 cx.background_spawn(async move {
11138 let _ = request.await?;
11139 Ok(())
11140 })
11141 } else {
11142 let task =
11143 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11144 cx.background_spawn(async move {
11145 task.await;
11146 Ok(())
11147 })
11148 }
11149 }
11150
11151 fn stop_local_language_servers_for_buffers(
11152 &mut self,
11153 buffers: &[Entity<Buffer>],
11154 also_stop_servers: HashSet<LanguageServerSelector>,
11155 cx: &mut Context<Self>,
11156 ) -> Task<()> {
11157 let Some(local) = self.as_local_mut() else {
11158 return Task::ready(());
11159 };
11160 let mut language_server_names_to_stop = BTreeSet::default();
11161 let mut language_servers_to_stop = also_stop_servers
11162 .into_iter()
11163 .flat_map(|selector| match selector {
11164 LanguageServerSelector::Id(id) => Some(id),
11165 LanguageServerSelector::Name(name) => {
11166 language_server_names_to_stop.insert(name);
11167 None
11168 }
11169 })
11170 .collect::<BTreeSet<_>>();
11171
11172 let mut covered_worktrees = HashSet::default();
11173 for buffer in buffers {
11174 buffer.update(cx, |buffer, cx| {
11175 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11176 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11177 && covered_worktrees.insert(worktree_id)
11178 {
11179 language_server_names_to_stop.retain(|name| {
11180 let old_ids_count = language_servers_to_stop.len();
11181 let all_language_servers_with_this_name = local
11182 .language_server_ids
11183 .iter()
11184 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11185 language_servers_to_stop.extend(all_language_servers_with_this_name);
11186 old_ids_count == language_servers_to_stop.len()
11187 });
11188 }
11189 });
11190 }
11191 for name in language_server_names_to_stop {
11192 language_servers_to_stop.extend(
11193 local
11194 .language_server_ids
11195 .iter()
11196 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11197 );
11198 }
11199
11200 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11201 let tasks = language_servers_to_stop
11202 .into_iter()
11203 .map(|server| self.stop_local_language_server(server, cx))
11204 .collect::<Vec<_>>();
11205
11206 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11207 }
11208
11209 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11210 let (worktree, relative_path) =
11211 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11212
11213 let project_path = ProjectPath {
11214 worktree_id: worktree.read(cx).id(),
11215 path: relative_path,
11216 };
11217
11218 Some(
11219 self.buffer_store()
11220 .read(cx)
11221 .get_by_path(&project_path)?
11222 .read(cx),
11223 )
11224 }
11225
11226 #[cfg(any(test, feature = "test-support"))]
11227 pub fn update_diagnostics(
11228 &mut self,
11229 server_id: LanguageServerId,
11230 diagnostics: lsp::PublishDiagnosticsParams,
11231 result_id: Option<SharedString>,
11232 source_kind: DiagnosticSourceKind,
11233 disk_based_sources: &[String],
11234 cx: &mut Context<Self>,
11235 ) -> Result<()> {
11236 self.merge_lsp_diagnostics(
11237 source_kind,
11238 vec![DocumentDiagnosticsUpdate {
11239 diagnostics,
11240 result_id,
11241 server_id,
11242 disk_based_sources: Cow::Borrowed(disk_based_sources),
11243 registration_id: None,
11244 }],
11245 |_, _, _| false,
11246 cx,
11247 )
11248 }
11249
11250 pub fn merge_lsp_diagnostics(
11251 &mut self,
11252 source_kind: DiagnosticSourceKind,
11253 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11254 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11255 cx: &mut Context<Self>,
11256 ) -> Result<()> {
11257 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11258 let updates = lsp_diagnostics
11259 .into_iter()
11260 .filter_map(|update| {
11261 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11262 Some(DocumentDiagnosticsUpdate {
11263 diagnostics: self.lsp_to_document_diagnostics(
11264 abs_path,
11265 source_kind,
11266 update.server_id,
11267 update.diagnostics,
11268 &update.disk_based_sources,
11269 update.registration_id.clone(),
11270 ),
11271 result_id: update.result_id,
11272 server_id: update.server_id,
11273 disk_based_sources: update.disk_based_sources,
11274 registration_id: update.registration_id,
11275 })
11276 })
11277 .collect();
11278 self.merge_diagnostic_entries(updates, merge, cx)?;
11279 Ok(())
11280 }
11281
11282 fn lsp_to_document_diagnostics(
11283 &mut self,
11284 document_abs_path: PathBuf,
11285 source_kind: DiagnosticSourceKind,
11286 server_id: LanguageServerId,
11287 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11288 disk_based_sources: &[String],
11289 registration_id: Option<SharedString>,
11290 ) -> DocumentDiagnostics {
11291 let mut diagnostics = Vec::default();
11292 let mut primary_diagnostic_group_ids = HashMap::default();
11293 let mut sources_by_group_id = HashMap::default();
11294 let mut supporting_diagnostics = HashMap::default();
11295
11296 let adapter = self.language_server_adapter_for_id(server_id);
11297
11298 // Ensure that primary diagnostics are always the most severe
11299 lsp_diagnostics
11300 .diagnostics
11301 .sort_by_key(|item| item.severity);
11302
11303 for diagnostic in &lsp_diagnostics.diagnostics {
11304 let source = diagnostic.source.as_ref();
11305 let range = range_from_lsp(diagnostic.range);
11306 let is_supporting = diagnostic
11307 .related_information
11308 .as_ref()
11309 .is_some_and(|infos| {
11310 infos.iter().any(|info| {
11311 primary_diagnostic_group_ids.contains_key(&(
11312 source,
11313 diagnostic.code.clone(),
11314 range_from_lsp(info.location.range),
11315 ))
11316 })
11317 });
11318
11319 let is_unnecessary = diagnostic
11320 .tags
11321 .as_ref()
11322 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11323
11324 let underline = self
11325 .language_server_adapter_for_id(server_id)
11326 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11327
11328 if is_supporting {
11329 supporting_diagnostics.insert(
11330 (source, diagnostic.code.clone(), range),
11331 (diagnostic.severity, is_unnecessary),
11332 );
11333 } else {
11334 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11335 let is_disk_based =
11336 source.is_some_and(|source| disk_based_sources.contains(source));
11337
11338 sources_by_group_id.insert(group_id, source);
11339 primary_diagnostic_group_ids
11340 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11341
11342 diagnostics.push(DiagnosticEntry {
11343 range,
11344 diagnostic: Diagnostic {
11345 source: diagnostic.source.clone(),
11346 source_kind,
11347 code: diagnostic.code.clone(),
11348 code_description: diagnostic
11349 .code_description
11350 .as_ref()
11351 .and_then(|d| d.href.clone()),
11352 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11353 markdown: adapter.as_ref().and_then(|adapter| {
11354 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11355 }),
11356 message: diagnostic.message.trim().to_string(),
11357 group_id,
11358 is_primary: true,
11359 is_disk_based,
11360 is_unnecessary,
11361 underline,
11362 data: diagnostic.data.clone(),
11363 registration_id: registration_id.clone(),
11364 },
11365 });
11366 if let Some(infos) = &diagnostic.related_information {
11367 for info in infos {
11368 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11369 let range = range_from_lsp(info.location.range);
11370 diagnostics.push(DiagnosticEntry {
11371 range,
11372 diagnostic: Diagnostic {
11373 source: diagnostic.source.clone(),
11374 source_kind,
11375 code: diagnostic.code.clone(),
11376 code_description: diagnostic
11377 .code_description
11378 .as_ref()
11379 .and_then(|d| d.href.clone()),
11380 severity: DiagnosticSeverity::INFORMATION,
11381 markdown: adapter.as_ref().and_then(|adapter| {
11382 adapter.diagnostic_message_to_markdown(&info.message)
11383 }),
11384 message: info.message.trim().to_string(),
11385 group_id,
11386 is_primary: false,
11387 is_disk_based,
11388 is_unnecessary: false,
11389 underline,
11390 data: diagnostic.data.clone(),
11391 registration_id: registration_id.clone(),
11392 },
11393 });
11394 }
11395 }
11396 }
11397 }
11398 }
11399
11400 for entry in &mut diagnostics {
11401 let diagnostic = &mut entry.diagnostic;
11402 if !diagnostic.is_primary {
11403 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11404 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11405 source,
11406 diagnostic.code.clone(),
11407 entry.range.clone(),
11408 )) {
11409 if let Some(severity) = severity {
11410 diagnostic.severity = severity;
11411 }
11412 diagnostic.is_unnecessary = is_unnecessary;
11413 }
11414 }
11415 }
11416
11417 DocumentDiagnostics {
11418 diagnostics,
11419 document_abs_path,
11420 version: lsp_diagnostics.version,
11421 }
11422 }
11423
11424 fn insert_newly_running_language_server(
11425 &mut self,
11426 adapter: Arc<CachedLspAdapter>,
11427 language_server: Arc<LanguageServer>,
11428 server_id: LanguageServerId,
11429 key: LanguageServerSeed,
11430 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11431 cx: &mut Context<Self>,
11432 ) {
11433 let Some(local) = self.as_local_mut() else {
11434 return;
11435 };
11436 // If the language server for this key doesn't match the server id, don't store the
11437 // server. Which will cause it to be dropped, killing the process
11438 if local
11439 .language_server_ids
11440 .get(&key)
11441 .map(|state| state.id != server_id)
11442 .unwrap_or(false)
11443 {
11444 return;
11445 }
11446
11447 // Update language_servers collection with Running variant of LanguageServerState
11448 // indicating that the server is up and running and ready
11449 let workspace_folders = workspace_folders.lock().clone();
11450 language_server.set_workspace_folders(workspace_folders);
11451
11452 let workspace_diagnostics_refresh_tasks = language_server
11453 .capabilities()
11454 .diagnostic_provider
11455 .and_then(|provider| {
11456 local
11457 .language_server_dynamic_registrations
11458 .entry(server_id)
11459 .or_default()
11460 .diagnostics
11461 .entry(None)
11462 .or_insert(provider.clone());
11463 let workspace_refresher =
11464 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11465
11466 Some((None, workspace_refresher))
11467 })
11468 .into_iter()
11469 .collect();
11470 local.language_servers.insert(
11471 server_id,
11472 LanguageServerState::Running {
11473 workspace_diagnostics_refresh_tasks,
11474 adapter: adapter.clone(),
11475 server: language_server.clone(),
11476 simulate_disk_based_diagnostics_completion: None,
11477 },
11478 );
11479 local
11480 .languages
11481 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11482 if let Some(file_ops_caps) = language_server
11483 .capabilities()
11484 .workspace
11485 .as_ref()
11486 .and_then(|ws| ws.file_operations.as_ref())
11487 {
11488 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11489 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11490 if did_rename_caps.or(will_rename_caps).is_some() {
11491 let watcher = RenamePathsWatchedForServer::default()
11492 .with_did_rename_patterns(did_rename_caps)
11493 .with_will_rename_patterns(will_rename_caps);
11494 local
11495 .language_server_paths_watched_for_rename
11496 .insert(server_id, watcher);
11497 }
11498 }
11499
11500 self.language_server_statuses.insert(
11501 server_id,
11502 LanguageServerStatus {
11503 name: language_server.name(),
11504 server_version: language_server.version(),
11505 server_readable_version: language_server.readable_version(),
11506 pending_work: Default::default(),
11507 has_pending_diagnostic_updates: false,
11508 progress_tokens: Default::default(),
11509 worktree: Some(key.worktree_id),
11510 binary: Some(language_server.binary().clone()),
11511 configuration: Some(language_server.configuration().clone()),
11512 workspace_folders: language_server.workspace_folders(),
11513 process_id: language_server.process_id(),
11514 },
11515 );
11516
11517 cx.emit(LspStoreEvent::LanguageServerAdded(
11518 server_id,
11519 language_server.name(),
11520 Some(key.worktree_id),
11521 ));
11522
11523 let server_capabilities = language_server.capabilities();
11524 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11525 downstream_client
11526 .send(proto::StartLanguageServer {
11527 project_id: *project_id,
11528 server: Some(proto::LanguageServer {
11529 id: server_id.to_proto(),
11530 name: language_server.name().to_string(),
11531 worktree_id: Some(key.worktree_id.to_proto()),
11532 }),
11533 capabilities: serde_json::to_string(&server_capabilities)
11534 .expect("serializing server LSP capabilities"),
11535 })
11536 .log_err();
11537 }
11538 self.lsp_server_capabilities
11539 .insert(server_id, server_capabilities);
11540
11541 // Tell the language server about every open buffer in the worktree that matches the language.
11542 // Also check for buffers in worktrees that reused this server
11543 let mut worktrees_using_server = vec![key.worktree_id];
11544 if let Some(local) = self.as_local() {
11545 // Find all worktrees that have this server in their language server tree
11546 for (worktree_id, servers) in &local.lsp_tree.instances {
11547 if *worktree_id != key.worktree_id {
11548 for server_map in servers.roots.values() {
11549 if server_map
11550 .values()
11551 .any(|(node, _)| node.id() == Some(server_id))
11552 {
11553 worktrees_using_server.push(*worktree_id);
11554 }
11555 }
11556 }
11557 }
11558 }
11559
11560 let mut buffer_paths_registered = Vec::new();
11561 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11562 let mut lsp_adapters = HashMap::default();
11563 for buffer_handle in buffer_store.buffers() {
11564 let buffer = buffer_handle.read(cx);
11565 let file = match File::from_dyn(buffer.file()) {
11566 Some(file) => file,
11567 None => continue,
11568 };
11569 let language = match buffer.language() {
11570 Some(language) => language,
11571 None => continue,
11572 };
11573
11574 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11575 || !lsp_adapters
11576 .entry(language.name())
11577 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11578 .iter()
11579 .any(|a| a.name == key.name)
11580 {
11581 continue;
11582 }
11583 // didOpen
11584 let file = match file.as_local() {
11585 Some(file) => file,
11586 None => continue,
11587 };
11588
11589 let local = self.as_local_mut().unwrap();
11590
11591 let buffer_id = buffer.remote_id();
11592 if local.registered_buffers.contains_key(&buffer_id) {
11593 let abs_path = file.abs_path(cx);
11594 let uri = match lsp::Uri::from_file_path(&abs_path) {
11595 Ok(uri) => uri,
11596 Err(()) => {
11597 log::error!("failed to convert path to URI: {:?}", abs_path);
11598 continue;
11599 }
11600 };
11601
11602 let versions = local
11603 .buffer_snapshots
11604 .entry(buffer_id)
11605 .or_default()
11606 .entry(server_id)
11607 .and_modify(|_| {
11608 assert!(
11609 false,
11610 "There should not be an existing snapshot for a newly inserted buffer"
11611 )
11612 })
11613 .or_insert_with(|| {
11614 vec![LspBufferSnapshot {
11615 version: 0,
11616 snapshot: buffer.text_snapshot(),
11617 }]
11618 });
11619
11620 let snapshot = versions.last().unwrap();
11621 let version = snapshot.version;
11622 let initial_snapshot = &snapshot.snapshot;
11623 language_server.register_buffer(
11624 uri,
11625 adapter.language_id(&language.name()),
11626 version,
11627 initial_snapshot.text(),
11628 );
11629 buffer_paths_registered.push((buffer_id, abs_path));
11630 local
11631 .buffers_opened_in_servers
11632 .entry(buffer_id)
11633 .or_default()
11634 .insert(server_id);
11635 }
11636 buffer_handle.update(cx, |buffer, cx| {
11637 buffer.set_completion_triggers(
11638 server_id,
11639 language_server
11640 .capabilities()
11641 .completion_provider
11642 .as_ref()
11643 .and_then(|provider| {
11644 provider
11645 .trigger_characters
11646 .as_ref()
11647 .map(|characters| characters.iter().cloned().collect())
11648 })
11649 .unwrap_or_default(),
11650 cx,
11651 )
11652 });
11653 }
11654 });
11655
11656 for (buffer_id, abs_path) in buffer_paths_registered {
11657 cx.emit(LspStoreEvent::LanguageServerUpdate {
11658 language_server_id: server_id,
11659 name: Some(adapter.name()),
11660 message: proto::update_language_server::Variant::RegisteredForBuffer(
11661 proto::RegisteredForBuffer {
11662 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11663 buffer_id: buffer_id.to_proto(),
11664 },
11665 ),
11666 });
11667 }
11668
11669 cx.notify();
11670 }
11671
11672 pub fn language_servers_running_disk_based_diagnostics(
11673 &self,
11674 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11675 self.language_server_statuses
11676 .iter()
11677 .filter_map(|(id, status)| {
11678 if status.has_pending_diagnostic_updates {
11679 Some(*id)
11680 } else {
11681 None
11682 }
11683 })
11684 }
11685
11686 pub(crate) fn cancel_language_server_work_for_buffers(
11687 &mut self,
11688 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11689 cx: &mut Context<Self>,
11690 ) {
11691 if let Some((client, project_id)) = self.upstream_client() {
11692 let request = client.request(proto::CancelLanguageServerWork {
11693 project_id,
11694 work: Some(proto::cancel_language_server_work::Work::Buffers(
11695 proto::cancel_language_server_work::Buffers {
11696 buffer_ids: buffers
11697 .into_iter()
11698 .map(|b| b.read(cx).remote_id().to_proto())
11699 .collect(),
11700 },
11701 )),
11702 });
11703 cx.background_spawn(request).detach_and_log_err(cx);
11704 } else if let Some(local) = self.as_local() {
11705 let servers = buffers
11706 .into_iter()
11707 .flat_map(|buffer| {
11708 buffer.update(cx, |buffer, cx| {
11709 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11710 })
11711 })
11712 .collect::<HashSet<_>>();
11713 for server_id in servers {
11714 self.cancel_language_server_work(server_id, None, cx);
11715 }
11716 }
11717 }
11718
11719 pub(crate) fn cancel_language_server_work(
11720 &mut self,
11721 server_id: LanguageServerId,
11722 token_to_cancel: Option<ProgressToken>,
11723 cx: &mut Context<Self>,
11724 ) {
11725 if let Some(local) = self.as_local() {
11726 let status = self.language_server_statuses.get(&server_id);
11727 let server = local.language_servers.get(&server_id);
11728 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11729 {
11730 for (token, progress) in &status.pending_work {
11731 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11732 && token != token_to_cancel
11733 {
11734 continue;
11735 }
11736 if progress.is_cancellable {
11737 server
11738 .notify::<lsp::notification::WorkDoneProgressCancel>(
11739 WorkDoneProgressCancelParams {
11740 token: token.to_lsp(),
11741 },
11742 )
11743 .ok();
11744 }
11745 }
11746 }
11747 } else if let Some((client, project_id)) = self.upstream_client() {
11748 let request = client.request(proto::CancelLanguageServerWork {
11749 project_id,
11750 work: Some(
11751 proto::cancel_language_server_work::Work::LanguageServerWork(
11752 proto::cancel_language_server_work::LanguageServerWork {
11753 language_server_id: server_id.to_proto(),
11754 token: token_to_cancel.map(|token| token.to_proto()),
11755 },
11756 ),
11757 ),
11758 });
11759 cx.background_spawn(request).detach_and_log_err(cx);
11760 }
11761 }
11762
11763 fn register_supplementary_language_server(
11764 &mut self,
11765 id: LanguageServerId,
11766 name: LanguageServerName,
11767 server: Arc<LanguageServer>,
11768 cx: &mut Context<Self>,
11769 ) {
11770 if let Some(local) = self.as_local_mut() {
11771 local
11772 .supplementary_language_servers
11773 .insert(id, (name.clone(), server));
11774 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11775 }
11776 }
11777
11778 fn unregister_supplementary_language_server(
11779 &mut self,
11780 id: LanguageServerId,
11781 cx: &mut Context<Self>,
11782 ) {
11783 if let Some(local) = self.as_local_mut() {
11784 local.supplementary_language_servers.remove(&id);
11785 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11786 }
11787 }
11788
11789 pub(crate) fn supplementary_language_servers(
11790 &self,
11791 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11792 self.as_local().into_iter().flat_map(|local| {
11793 local
11794 .supplementary_language_servers
11795 .iter()
11796 .map(|(id, (name, _))| (*id, name.clone()))
11797 })
11798 }
11799
11800 pub fn language_server_adapter_for_id(
11801 &self,
11802 id: LanguageServerId,
11803 ) -> Option<Arc<CachedLspAdapter>> {
11804 self.as_local()
11805 .and_then(|local| local.language_servers.get(&id))
11806 .and_then(|language_server_state| match language_server_state {
11807 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11808 _ => None,
11809 })
11810 }
11811
11812 pub(super) fn update_local_worktree_language_servers(
11813 &mut self,
11814 worktree_handle: &Entity<Worktree>,
11815 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11816 cx: &mut Context<Self>,
11817 ) {
11818 if changes.is_empty() {
11819 return;
11820 }
11821
11822 let Some(local) = self.as_local() else { return };
11823
11824 local.prettier_store.update(cx, |prettier_store, cx| {
11825 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11826 });
11827
11828 let worktree_id = worktree_handle.read(cx).id();
11829 let mut language_server_ids = local
11830 .language_server_ids
11831 .iter()
11832 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11833 .collect::<Vec<_>>();
11834 language_server_ids.sort();
11835 language_server_ids.dedup();
11836
11837 // let abs_path = worktree_handle.read(cx).abs_path();
11838 for server_id in &language_server_ids {
11839 if let Some(LanguageServerState::Running { server, .. }) =
11840 local.language_servers.get(server_id)
11841 && let Some(watched_paths) = local
11842 .language_server_watched_paths
11843 .get(server_id)
11844 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11845 {
11846 let params = lsp::DidChangeWatchedFilesParams {
11847 changes: changes
11848 .iter()
11849 .filter_map(|(path, _, change)| {
11850 if !watched_paths.is_match(path.as_std_path()) {
11851 return None;
11852 }
11853 let typ = match change {
11854 PathChange::Loaded => return None,
11855 PathChange::Added => lsp::FileChangeType::CREATED,
11856 PathChange::Removed => lsp::FileChangeType::DELETED,
11857 PathChange::Updated => lsp::FileChangeType::CHANGED,
11858 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11859 };
11860 let uri = lsp::Uri::from_file_path(
11861 worktree_handle.read(cx).absolutize(&path),
11862 )
11863 .ok()?;
11864 Some(lsp::FileEvent { uri, typ })
11865 })
11866 .collect(),
11867 };
11868 if !params.changes.is_empty() {
11869 server
11870 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11871 .ok();
11872 }
11873 }
11874 }
11875 for (path, _, _) in changes {
11876 if let Some(file_name) = path.file_name()
11877 && local.watched_manifest_filenames.contains(file_name)
11878 {
11879 self.request_workspace_config_refresh();
11880 break;
11881 }
11882 }
11883 }
11884
11885 pub fn wait_for_remote_buffer(
11886 &mut self,
11887 id: BufferId,
11888 cx: &mut Context<Self>,
11889 ) -> Task<Result<Entity<Buffer>>> {
11890 self.buffer_store.update(cx, |buffer_store, cx| {
11891 buffer_store.wait_for_remote_buffer(id, cx)
11892 })
11893 }
11894
11895 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11896 let mut result = proto::Symbol {
11897 language_server_name: symbol.language_server_name.0.to_string(),
11898 source_worktree_id: symbol.source_worktree_id.to_proto(),
11899 language_server_id: symbol.source_language_server_id.to_proto(),
11900 name: symbol.name.clone(),
11901 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11902 start: Some(proto::PointUtf16 {
11903 row: symbol.range.start.0.row,
11904 column: symbol.range.start.0.column,
11905 }),
11906 end: Some(proto::PointUtf16 {
11907 row: symbol.range.end.0.row,
11908 column: symbol.range.end.0.column,
11909 }),
11910 worktree_id: Default::default(),
11911 path: Default::default(),
11912 signature: Default::default(),
11913 container_name: symbol.container_name.clone(),
11914 };
11915 match &symbol.path {
11916 SymbolLocation::InProject(path) => {
11917 result.worktree_id = path.worktree_id.to_proto();
11918 result.path = path.path.to_proto();
11919 }
11920 SymbolLocation::OutsideProject {
11921 abs_path,
11922 signature,
11923 } => {
11924 result.path = abs_path.to_string_lossy().into_owned();
11925 result.signature = signature.to_vec();
11926 }
11927 }
11928 result
11929 }
11930
11931 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11932 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11933 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11934 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11935
11936 let path = if serialized_symbol.signature.is_empty() {
11937 SymbolLocation::InProject(ProjectPath {
11938 worktree_id,
11939 path: RelPath::from_proto(&serialized_symbol.path)
11940 .context("invalid symbol path")?,
11941 })
11942 } else {
11943 SymbolLocation::OutsideProject {
11944 abs_path: Path::new(&serialized_symbol.path).into(),
11945 signature: serialized_symbol
11946 .signature
11947 .try_into()
11948 .map_err(|_| anyhow!("invalid signature"))?,
11949 }
11950 };
11951
11952 let start = serialized_symbol.start.context("invalid start")?;
11953 let end = serialized_symbol.end.context("invalid end")?;
11954 Ok(CoreSymbol {
11955 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11956 source_worktree_id,
11957 source_language_server_id: LanguageServerId::from_proto(
11958 serialized_symbol.language_server_id,
11959 ),
11960 path,
11961 name: serialized_symbol.name,
11962 range: Unclipped(PointUtf16::new(start.row, start.column))
11963 ..Unclipped(PointUtf16::new(end.row, end.column)),
11964 kind,
11965 container_name: serialized_symbol.container_name,
11966 })
11967 }
11968
11969 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11970 let mut serialized_completion = proto::Completion {
11971 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11972 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11973 new_text: completion.new_text.clone(),
11974 ..proto::Completion::default()
11975 };
11976 match &completion.source {
11977 CompletionSource::Lsp {
11978 insert_range,
11979 server_id,
11980 lsp_completion,
11981 lsp_defaults,
11982 resolved,
11983 } => {
11984 let (old_insert_start, old_insert_end) = insert_range
11985 .as_ref()
11986 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11987 .unzip();
11988
11989 serialized_completion.old_insert_start = old_insert_start;
11990 serialized_completion.old_insert_end = old_insert_end;
11991 serialized_completion.source = proto::completion::Source::Lsp as i32;
11992 serialized_completion.server_id = server_id.0 as u64;
11993 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11994 serialized_completion.lsp_defaults = lsp_defaults
11995 .as_deref()
11996 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11997 serialized_completion.resolved = *resolved;
11998 }
11999 CompletionSource::BufferWord {
12000 word_range,
12001 resolved,
12002 } => {
12003 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12004 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12005 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12006 serialized_completion.resolved = *resolved;
12007 }
12008 CompletionSource::Custom => {
12009 serialized_completion.source = proto::completion::Source::Custom as i32;
12010 serialized_completion.resolved = true;
12011 }
12012 CompletionSource::Dap { sort_text } => {
12013 serialized_completion.source = proto::completion::Source::Dap as i32;
12014 serialized_completion.sort_text = Some(sort_text.clone());
12015 }
12016 }
12017
12018 serialized_completion
12019 }
12020
12021 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12022 let old_replace_start = completion
12023 .old_replace_start
12024 .and_then(deserialize_anchor)
12025 .context("invalid old start")?;
12026 let old_replace_end = completion
12027 .old_replace_end
12028 .and_then(deserialize_anchor)
12029 .context("invalid old end")?;
12030 let insert_range = {
12031 match completion.old_insert_start.zip(completion.old_insert_end) {
12032 Some((start, end)) => {
12033 let start = deserialize_anchor(start).context("invalid insert old start")?;
12034 let end = deserialize_anchor(end).context("invalid insert old end")?;
12035 Some(start..end)
12036 }
12037 None => None,
12038 }
12039 };
12040 Ok(CoreCompletion {
12041 replace_range: old_replace_start..old_replace_end,
12042 new_text: completion.new_text,
12043 source: match proto::completion::Source::from_i32(completion.source) {
12044 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12045 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12046 insert_range,
12047 server_id: LanguageServerId::from_proto(completion.server_id),
12048 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12049 lsp_defaults: completion
12050 .lsp_defaults
12051 .as_deref()
12052 .map(serde_json::from_slice)
12053 .transpose()?,
12054 resolved: completion.resolved,
12055 },
12056 Some(proto::completion::Source::BufferWord) => {
12057 let word_range = completion
12058 .buffer_word_start
12059 .and_then(deserialize_anchor)
12060 .context("invalid buffer word start")?
12061 ..completion
12062 .buffer_word_end
12063 .and_then(deserialize_anchor)
12064 .context("invalid buffer word end")?;
12065 CompletionSource::BufferWord {
12066 word_range,
12067 resolved: completion.resolved,
12068 }
12069 }
12070 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12071 sort_text: completion
12072 .sort_text
12073 .context("expected sort text to exist")?,
12074 },
12075 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12076 },
12077 })
12078 }
12079
12080 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12081 let (kind, lsp_action) = match &action.lsp_action {
12082 LspAction::Action(code_action) => (
12083 proto::code_action::Kind::Action as i32,
12084 serde_json::to_vec(code_action).unwrap(),
12085 ),
12086 LspAction::Command(command) => (
12087 proto::code_action::Kind::Command as i32,
12088 serde_json::to_vec(command).unwrap(),
12089 ),
12090 LspAction::CodeLens(code_lens) => (
12091 proto::code_action::Kind::CodeLens as i32,
12092 serde_json::to_vec(code_lens).unwrap(),
12093 ),
12094 };
12095
12096 proto::CodeAction {
12097 server_id: action.server_id.0 as u64,
12098 start: Some(serialize_anchor(&action.range.start)),
12099 end: Some(serialize_anchor(&action.range.end)),
12100 lsp_action,
12101 kind,
12102 resolved: action.resolved,
12103 }
12104 }
12105
12106 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12107 let start = action
12108 .start
12109 .and_then(deserialize_anchor)
12110 .context("invalid start")?;
12111 let end = action
12112 .end
12113 .and_then(deserialize_anchor)
12114 .context("invalid end")?;
12115 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12116 Some(proto::code_action::Kind::Action) => {
12117 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12118 }
12119 Some(proto::code_action::Kind::Command) => {
12120 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12121 }
12122 Some(proto::code_action::Kind::CodeLens) => {
12123 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12124 }
12125 None => anyhow::bail!("Unknown action kind {}", action.kind),
12126 };
12127 Ok(CodeAction {
12128 server_id: LanguageServerId(action.server_id as usize),
12129 range: start..end,
12130 resolved: action.resolved,
12131 lsp_action,
12132 })
12133 }
12134
12135 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12136 match &formatting_result {
12137 Ok(_) => self.last_formatting_failure = None,
12138 Err(error) => {
12139 let error_string = format!("{error:#}");
12140 log::error!("Formatting failed: {error_string}");
12141 self.last_formatting_failure
12142 .replace(error_string.lines().join(" "));
12143 }
12144 }
12145 }
12146
12147 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12148 self.lsp_server_capabilities.remove(&for_server);
12149 self.semantic_token_config.remove_server_data(for_server);
12150 for lsp_data in self.lsp_data.values_mut() {
12151 lsp_data.remove_server_data(for_server);
12152 }
12153 if let Some(local) = self.as_local_mut() {
12154 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12155 local
12156 .workspace_pull_diagnostics_result_ids
12157 .remove(&for_server);
12158 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12159 buffer_servers.remove(&for_server);
12160 }
12161 }
12162 }
12163
12164 pub fn result_id_for_buffer_pull(
12165 &self,
12166 server_id: LanguageServerId,
12167 buffer_id: BufferId,
12168 registration_id: &Option<SharedString>,
12169 cx: &App,
12170 ) -> Option<SharedString> {
12171 let abs_path = self
12172 .buffer_store
12173 .read(cx)
12174 .get(buffer_id)
12175 .and_then(|b| File::from_dyn(b.read(cx).file()))
12176 .map(|f| f.abs_path(cx))?;
12177 self.as_local()?
12178 .buffer_pull_diagnostics_result_ids
12179 .get(&server_id)?
12180 .get(registration_id)?
12181 .get(&abs_path)?
12182 .clone()
12183 }
12184
12185 /// Gets all result_ids for a workspace diagnostics pull request.
12186 /// 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.
12187 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12188 pub fn result_ids_for_workspace_refresh(
12189 &self,
12190 server_id: LanguageServerId,
12191 registration_id: &Option<SharedString>,
12192 ) -> HashMap<PathBuf, SharedString> {
12193 let Some(local) = self.as_local() else {
12194 return HashMap::default();
12195 };
12196 local
12197 .workspace_pull_diagnostics_result_ids
12198 .get(&server_id)
12199 .into_iter()
12200 .filter_map(|diagnostics| diagnostics.get(registration_id))
12201 .flatten()
12202 .filter_map(|(abs_path, result_id)| {
12203 let result_id = local
12204 .buffer_pull_diagnostics_result_ids
12205 .get(&server_id)
12206 .and_then(|buffer_ids_result_ids| {
12207 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12208 })
12209 .cloned()
12210 .flatten()
12211 .or_else(|| result_id.clone())?;
12212 Some((abs_path.clone(), result_id))
12213 })
12214 .collect()
12215 }
12216
12217 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12218 if let Some(LanguageServerState::Running {
12219 workspace_diagnostics_refresh_tasks,
12220 ..
12221 }) = self
12222 .as_local_mut()
12223 .and_then(|local| local.language_servers.get_mut(&server_id))
12224 {
12225 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12226 diagnostics.refresh_tx.try_send(()).ok();
12227 }
12228 }
12229 }
12230
12231 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12232 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12233 /// which requires refreshing both workspace and document diagnostics.
12234 pub fn pull_document_diagnostics_for_server(
12235 &mut self,
12236 server_id: LanguageServerId,
12237 source_buffer_id: Option<BufferId>,
12238 cx: &mut Context<Self>,
12239 ) -> Shared<Task<()>> {
12240 let Some(local) = self.as_local_mut() else {
12241 return Task::ready(()).shared();
12242 };
12243 let mut buffers_to_refresh = HashSet::default();
12244 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12245 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12246 buffers_to_refresh.insert(*buffer_id);
12247 }
12248 }
12249
12250 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12251 }
12252
12253 pub fn pull_document_diagnostics_for_buffer_edit(
12254 &mut self,
12255 buffer_id: BufferId,
12256 cx: &mut Context<Self>,
12257 ) {
12258 let Some(local) = self.as_local_mut() else {
12259 return;
12260 };
12261 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12262 else {
12263 return;
12264 };
12265 for server_id in languages_servers {
12266 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12267 }
12268 }
12269
12270 fn apply_workspace_diagnostic_report(
12271 &mut self,
12272 server_id: LanguageServerId,
12273 report: lsp::WorkspaceDiagnosticReportResult,
12274 registration_id: Option<SharedString>,
12275 cx: &mut Context<Self>,
12276 ) {
12277 let mut workspace_diagnostics =
12278 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12279 report,
12280 server_id,
12281 registration_id,
12282 );
12283 workspace_diagnostics.retain(|d| match &d.diagnostics {
12284 LspPullDiagnostics::Response {
12285 server_id,
12286 registration_id,
12287 ..
12288 } => self.diagnostic_registration_exists(*server_id, registration_id),
12289 LspPullDiagnostics::Default => false,
12290 });
12291 let mut unchanged_buffers = HashMap::default();
12292 let workspace_diagnostics_updates = workspace_diagnostics
12293 .into_iter()
12294 .filter_map(
12295 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12296 LspPullDiagnostics::Response {
12297 server_id,
12298 uri,
12299 diagnostics,
12300 registration_id,
12301 } => Some((
12302 server_id,
12303 uri,
12304 diagnostics,
12305 workspace_diagnostics.version,
12306 registration_id,
12307 )),
12308 LspPullDiagnostics::Default => None,
12309 },
12310 )
12311 .fold(
12312 HashMap::default(),
12313 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12314 let (result_id, diagnostics) = match diagnostics {
12315 PulledDiagnostics::Unchanged { result_id } => {
12316 unchanged_buffers
12317 .entry(new_registration_id.clone())
12318 .or_insert_with(HashSet::default)
12319 .insert(uri.clone());
12320 (Some(result_id), Vec::new())
12321 }
12322 PulledDiagnostics::Changed {
12323 result_id,
12324 diagnostics,
12325 } => (result_id, diagnostics),
12326 };
12327 let disk_based_sources = Cow::Owned(
12328 self.language_server_adapter_for_id(server_id)
12329 .as_ref()
12330 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12331 .unwrap_or(&[])
12332 .to_vec(),
12333 );
12334
12335 let Some(abs_path) = uri.to_file_path().ok() else {
12336 return acc;
12337 };
12338 let Some((worktree, relative_path)) =
12339 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12340 else {
12341 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12342 return acc;
12343 };
12344 let worktree_id = worktree.read(cx).id();
12345 let project_path = ProjectPath {
12346 worktree_id,
12347 path: relative_path,
12348 };
12349 if let Some(local_lsp_store) = self.as_local_mut() {
12350 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12351 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12352 }
12353 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12354 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12355 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12356 acc.entry(server_id)
12357 .or_insert_with(HashMap::default)
12358 .entry(new_registration_id.clone())
12359 .or_insert_with(Vec::new)
12360 .push(DocumentDiagnosticsUpdate {
12361 server_id,
12362 diagnostics: lsp::PublishDiagnosticsParams {
12363 uri,
12364 diagnostics,
12365 version,
12366 },
12367 result_id: result_id.map(SharedString::new),
12368 disk_based_sources,
12369 registration_id: new_registration_id,
12370 });
12371 }
12372 acc
12373 },
12374 );
12375
12376 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12377 for (registration_id, diagnostic_updates) in diagnostic_updates {
12378 self.merge_lsp_diagnostics(
12379 DiagnosticSourceKind::Pulled,
12380 diagnostic_updates,
12381 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12382 DiagnosticSourceKind::Pulled => {
12383 old_diagnostic.registration_id != registration_id
12384 || unchanged_buffers
12385 .get(&old_diagnostic.registration_id)
12386 .is_some_and(|unchanged_buffers| {
12387 unchanged_buffers.contains(&document_uri)
12388 })
12389 }
12390 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12391 },
12392 cx,
12393 )
12394 .log_err();
12395 }
12396 }
12397 }
12398
12399 fn register_server_capabilities(
12400 &mut self,
12401 server_id: LanguageServerId,
12402 params: lsp::RegistrationParams,
12403 cx: &mut Context<Self>,
12404 ) -> anyhow::Result<()> {
12405 let server = self
12406 .language_server_for_id(server_id)
12407 .with_context(|| format!("no server {server_id} found"))?;
12408 for reg in params.registrations {
12409 match reg.method.as_str() {
12410 "workspace/didChangeWatchedFiles" => {
12411 if let Some(options) = reg.register_options {
12412 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12413 let caps = serde_json::from_value(options)?;
12414 local_lsp_store
12415 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12416 true
12417 } else {
12418 false
12419 };
12420 if notify {
12421 notify_server_capabilities_updated(&server, cx);
12422 }
12423 }
12424 }
12425 "workspace/didChangeConfiguration" => {
12426 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12427 }
12428 "workspace/didChangeWorkspaceFolders" => {
12429 // In this case register options is an empty object, we can ignore it
12430 let caps = lsp::WorkspaceFoldersServerCapabilities {
12431 supported: Some(true),
12432 change_notifications: Some(OneOf::Right(reg.id)),
12433 };
12434 server.update_capabilities(|capabilities| {
12435 capabilities
12436 .workspace
12437 .get_or_insert_default()
12438 .workspace_folders = Some(caps);
12439 });
12440 notify_server_capabilities_updated(&server, cx);
12441 }
12442 "workspace/symbol" => {
12443 let options = parse_register_capabilities(reg)?;
12444 server.update_capabilities(|capabilities| {
12445 capabilities.workspace_symbol_provider = Some(options);
12446 });
12447 notify_server_capabilities_updated(&server, cx);
12448 }
12449 "workspace/fileOperations" => {
12450 if let Some(options) = reg.register_options {
12451 let caps = serde_json::from_value(options)?;
12452 server.update_capabilities(|capabilities| {
12453 capabilities
12454 .workspace
12455 .get_or_insert_default()
12456 .file_operations = Some(caps);
12457 });
12458 notify_server_capabilities_updated(&server, cx);
12459 }
12460 }
12461 "workspace/executeCommand" => {
12462 if let Some(options) = reg.register_options {
12463 let options = serde_json::from_value(options)?;
12464 server.update_capabilities(|capabilities| {
12465 capabilities.execute_command_provider = Some(options);
12466 });
12467 notify_server_capabilities_updated(&server, cx);
12468 }
12469 }
12470 "textDocument/rangeFormatting" => {
12471 let options = parse_register_capabilities(reg)?;
12472 server.update_capabilities(|capabilities| {
12473 capabilities.document_range_formatting_provider = Some(options);
12474 });
12475 notify_server_capabilities_updated(&server, cx);
12476 }
12477 "textDocument/onTypeFormatting" => {
12478 if let Some(options) = reg
12479 .register_options
12480 .map(serde_json::from_value)
12481 .transpose()?
12482 {
12483 server.update_capabilities(|capabilities| {
12484 capabilities.document_on_type_formatting_provider = Some(options);
12485 });
12486 notify_server_capabilities_updated(&server, cx);
12487 }
12488 }
12489 "textDocument/formatting" => {
12490 let options = parse_register_capabilities(reg)?;
12491 server.update_capabilities(|capabilities| {
12492 capabilities.document_formatting_provider = Some(options);
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 "textDocument/rename" => {
12497 let options = parse_register_capabilities(reg)?;
12498 server.update_capabilities(|capabilities| {
12499 capabilities.rename_provider = Some(options);
12500 });
12501 notify_server_capabilities_updated(&server, cx);
12502 }
12503 "textDocument/inlayHint" => {
12504 let options = parse_register_capabilities(reg)?;
12505 server.update_capabilities(|capabilities| {
12506 capabilities.inlay_hint_provider = Some(options);
12507 });
12508 notify_server_capabilities_updated(&server, cx);
12509 }
12510 "textDocument/documentSymbol" => {
12511 let options = parse_register_capabilities(reg)?;
12512 server.update_capabilities(|capabilities| {
12513 capabilities.document_symbol_provider = Some(options);
12514 });
12515 notify_server_capabilities_updated(&server, cx);
12516 }
12517 "textDocument/codeAction" => {
12518 let options = parse_register_capabilities(reg)?;
12519 let provider = match options {
12520 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12521 OneOf::Right(caps) => caps,
12522 };
12523 server.update_capabilities(|capabilities| {
12524 capabilities.code_action_provider = Some(provider);
12525 });
12526 notify_server_capabilities_updated(&server, cx);
12527 }
12528 "textDocument/definition" => {
12529 let options = parse_register_capabilities(reg)?;
12530 server.update_capabilities(|capabilities| {
12531 capabilities.definition_provider = Some(options);
12532 });
12533 notify_server_capabilities_updated(&server, cx);
12534 }
12535 "textDocument/completion" => {
12536 if let Some(caps) = reg
12537 .register_options
12538 .map(serde_json::from_value::<CompletionOptions>)
12539 .transpose()?
12540 {
12541 server.update_capabilities(|capabilities| {
12542 capabilities.completion_provider = Some(caps.clone());
12543 });
12544
12545 if let Some(local) = self.as_local() {
12546 let mut buffers_with_language_server = Vec::new();
12547 for handle in self.buffer_store.read(cx).buffers() {
12548 let buffer_id = handle.read(cx).remote_id();
12549 if local
12550 .buffers_opened_in_servers
12551 .get(&buffer_id)
12552 .filter(|s| s.contains(&server_id))
12553 .is_some()
12554 {
12555 buffers_with_language_server.push(handle);
12556 }
12557 }
12558 let triggers = caps
12559 .trigger_characters
12560 .unwrap_or_default()
12561 .into_iter()
12562 .collect::<BTreeSet<_>>();
12563 for handle in buffers_with_language_server {
12564 let triggers = triggers.clone();
12565 let _ = handle.update(cx, move |buffer, cx| {
12566 buffer.set_completion_triggers(server_id, triggers, cx);
12567 });
12568 }
12569 }
12570 notify_server_capabilities_updated(&server, cx);
12571 }
12572 }
12573 "textDocument/hover" => {
12574 let options = parse_register_capabilities(reg)?;
12575 let provider = match options {
12576 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12577 OneOf::Right(caps) => caps,
12578 };
12579 server.update_capabilities(|capabilities| {
12580 capabilities.hover_provider = Some(provider);
12581 });
12582 notify_server_capabilities_updated(&server, cx);
12583 }
12584 "textDocument/signatureHelp" => {
12585 if let Some(caps) = reg
12586 .register_options
12587 .map(serde_json::from_value)
12588 .transpose()?
12589 {
12590 server.update_capabilities(|capabilities| {
12591 capabilities.signature_help_provider = Some(caps);
12592 });
12593 notify_server_capabilities_updated(&server, cx);
12594 }
12595 }
12596 "textDocument/didChange" => {
12597 if let Some(sync_kind) = reg
12598 .register_options
12599 .and_then(|opts| opts.get("syncKind").cloned())
12600 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12601 .transpose()?
12602 {
12603 server.update_capabilities(|capabilities| {
12604 let mut sync_options =
12605 Self::take_text_document_sync_options(capabilities);
12606 sync_options.change = Some(sync_kind);
12607 capabilities.text_document_sync =
12608 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12609 });
12610 notify_server_capabilities_updated(&server, cx);
12611 }
12612 }
12613 "textDocument/didSave" => {
12614 if let Some(include_text) = reg
12615 .register_options
12616 .map(|opts| {
12617 let transpose = opts
12618 .get("includeText")
12619 .cloned()
12620 .map(serde_json::from_value::<Option<bool>>)
12621 .transpose();
12622 match transpose {
12623 Ok(value) => Ok(value.flatten()),
12624 Err(e) => Err(e),
12625 }
12626 })
12627 .transpose()?
12628 {
12629 server.update_capabilities(|capabilities| {
12630 let mut sync_options =
12631 Self::take_text_document_sync_options(capabilities);
12632 sync_options.save =
12633 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12634 include_text,
12635 }));
12636 capabilities.text_document_sync =
12637 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12638 });
12639 notify_server_capabilities_updated(&server, cx);
12640 }
12641 }
12642 "textDocument/codeLens" => {
12643 if let Some(caps) = reg
12644 .register_options
12645 .map(serde_json::from_value)
12646 .transpose()?
12647 {
12648 server.update_capabilities(|capabilities| {
12649 capabilities.code_lens_provider = Some(caps);
12650 });
12651 notify_server_capabilities_updated(&server, cx);
12652 }
12653 }
12654 "textDocument/diagnostic" => {
12655 if let Some(caps) = reg
12656 .register_options
12657 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12658 .transpose()?
12659 {
12660 let local = self
12661 .as_local_mut()
12662 .context("Expected LSP Store to be local")?;
12663 let state = local
12664 .language_servers
12665 .get_mut(&server_id)
12666 .context("Could not obtain Language Servers state")?;
12667 local
12668 .language_server_dynamic_registrations
12669 .entry(server_id)
12670 .or_default()
12671 .diagnostics
12672 .insert(Some(reg.id.clone()), caps.clone());
12673
12674 let supports_workspace_diagnostics =
12675 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12676 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12677 diagnostic_options.workspace_diagnostics
12678 }
12679 DiagnosticServerCapabilities::RegistrationOptions(
12680 diagnostic_registration_options,
12681 ) => {
12682 diagnostic_registration_options
12683 .diagnostic_options
12684 .workspace_diagnostics
12685 }
12686 };
12687
12688 if supports_workspace_diagnostics(&caps) {
12689 if let LanguageServerState::Running {
12690 workspace_diagnostics_refresh_tasks,
12691 ..
12692 } = state
12693 && let Some(task) = lsp_workspace_diagnostics_refresh(
12694 Some(reg.id.clone()),
12695 caps.clone(),
12696 server.clone(),
12697 cx,
12698 )
12699 {
12700 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12701 }
12702 }
12703
12704 server.update_capabilities(|capabilities| {
12705 capabilities.diagnostic_provider = Some(caps);
12706 });
12707
12708 notify_server_capabilities_updated(&server, cx);
12709
12710 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12711 }
12712 }
12713 "textDocument/documentColor" => {
12714 let options = parse_register_capabilities(reg)?;
12715 let provider = match options {
12716 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12717 OneOf::Right(caps) => caps,
12718 };
12719 server.update_capabilities(|capabilities| {
12720 capabilities.color_provider = Some(provider);
12721 });
12722 notify_server_capabilities_updated(&server, cx);
12723 }
12724 "textDocument/foldingRange" => {
12725 let options = parse_register_capabilities(reg)?;
12726 let provider = match options {
12727 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12728 OneOf::Right(caps) => caps,
12729 };
12730 server.update_capabilities(|capabilities| {
12731 capabilities.folding_range_provider = Some(provider);
12732 });
12733 notify_server_capabilities_updated(&server, cx);
12734 }
12735 _ => log::warn!("unhandled capability registration: {reg:?}"),
12736 }
12737 }
12738
12739 Ok(())
12740 }
12741
12742 fn unregister_server_capabilities(
12743 &mut self,
12744 server_id: LanguageServerId,
12745 params: lsp::UnregistrationParams,
12746 cx: &mut Context<Self>,
12747 ) -> anyhow::Result<()> {
12748 let server = self
12749 .language_server_for_id(server_id)
12750 .with_context(|| format!("no server {server_id} found"))?;
12751 for unreg in params.unregisterations.iter() {
12752 match unreg.method.as_str() {
12753 "workspace/didChangeWatchedFiles" => {
12754 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12755 local_lsp_store
12756 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12757 true
12758 } else {
12759 false
12760 };
12761 if notify {
12762 notify_server_capabilities_updated(&server, cx);
12763 }
12764 }
12765 "workspace/didChangeConfiguration" => {
12766 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12767 }
12768 "workspace/didChangeWorkspaceFolders" => {
12769 server.update_capabilities(|capabilities| {
12770 capabilities
12771 .workspace
12772 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12773 workspace_folders: None,
12774 file_operations: None,
12775 })
12776 .workspace_folders = None;
12777 });
12778 notify_server_capabilities_updated(&server, cx);
12779 }
12780 "workspace/symbol" => {
12781 server.update_capabilities(|capabilities| {
12782 capabilities.workspace_symbol_provider = None
12783 });
12784 notify_server_capabilities_updated(&server, cx);
12785 }
12786 "workspace/fileOperations" => {
12787 server.update_capabilities(|capabilities| {
12788 capabilities
12789 .workspace
12790 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12791 workspace_folders: None,
12792 file_operations: None,
12793 })
12794 .file_operations = None;
12795 });
12796 notify_server_capabilities_updated(&server, cx);
12797 }
12798 "workspace/executeCommand" => {
12799 server.update_capabilities(|capabilities| {
12800 capabilities.execute_command_provider = None;
12801 });
12802 notify_server_capabilities_updated(&server, cx);
12803 }
12804 "textDocument/rangeFormatting" => {
12805 server.update_capabilities(|capabilities| {
12806 capabilities.document_range_formatting_provider = None
12807 });
12808 notify_server_capabilities_updated(&server, cx);
12809 }
12810 "textDocument/onTypeFormatting" => {
12811 server.update_capabilities(|capabilities| {
12812 capabilities.document_on_type_formatting_provider = None;
12813 });
12814 notify_server_capabilities_updated(&server, cx);
12815 }
12816 "textDocument/formatting" => {
12817 server.update_capabilities(|capabilities| {
12818 capabilities.document_formatting_provider = None;
12819 });
12820 notify_server_capabilities_updated(&server, cx);
12821 }
12822 "textDocument/rename" => {
12823 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12824 notify_server_capabilities_updated(&server, cx);
12825 }
12826 "textDocument/codeAction" => {
12827 server.update_capabilities(|capabilities| {
12828 capabilities.code_action_provider = None;
12829 });
12830 notify_server_capabilities_updated(&server, cx);
12831 }
12832 "textDocument/definition" => {
12833 server.update_capabilities(|capabilities| {
12834 capabilities.definition_provider = None;
12835 });
12836 notify_server_capabilities_updated(&server, cx);
12837 }
12838 "textDocument/completion" => {
12839 server.update_capabilities(|capabilities| {
12840 capabilities.completion_provider = None;
12841 });
12842 notify_server_capabilities_updated(&server, cx);
12843 }
12844 "textDocument/hover" => {
12845 server.update_capabilities(|capabilities| {
12846 capabilities.hover_provider = None;
12847 });
12848 notify_server_capabilities_updated(&server, cx);
12849 }
12850 "textDocument/signatureHelp" => {
12851 server.update_capabilities(|capabilities| {
12852 capabilities.signature_help_provider = None;
12853 });
12854 notify_server_capabilities_updated(&server, cx);
12855 }
12856 "textDocument/didChange" => {
12857 server.update_capabilities(|capabilities| {
12858 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12859 sync_options.change = None;
12860 capabilities.text_document_sync =
12861 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12862 });
12863 notify_server_capabilities_updated(&server, cx);
12864 }
12865 "textDocument/didSave" => {
12866 server.update_capabilities(|capabilities| {
12867 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12868 sync_options.save = None;
12869 capabilities.text_document_sync =
12870 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12871 });
12872 notify_server_capabilities_updated(&server, cx);
12873 }
12874 "textDocument/codeLens" => {
12875 server.update_capabilities(|capabilities| {
12876 capabilities.code_lens_provider = None;
12877 });
12878 notify_server_capabilities_updated(&server, cx);
12879 }
12880 "textDocument/diagnostic" => {
12881 let local = self
12882 .as_local_mut()
12883 .context("Expected LSP Store to be local")?;
12884
12885 let state = local
12886 .language_servers
12887 .get_mut(&server_id)
12888 .context("Could not obtain Language Servers state")?;
12889 let registrations = local
12890 .language_server_dynamic_registrations
12891 .get_mut(&server_id)
12892 .with_context(|| {
12893 format!("Expected dynamic registration to exist for server {server_id}")
12894 })?;
12895 registrations.diagnostics
12896 .remove(&Some(unreg.id.clone()))
12897 .with_context(|| format!(
12898 "Attempted to unregister non-existent diagnostic registration with ID {}",
12899 unreg.id)
12900 )?;
12901 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12902
12903 if let LanguageServerState::Running {
12904 workspace_diagnostics_refresh_tasks,
12905 ..
12906 } = state
12907 {
12908 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12909 }
12910
12911 self.clear_unregistered_diagnostics(
12912 server_id,
12913 SharedString::from(unreg.id.clone()),
12914 cx,
12915 )?;
12916
12917 if removed_last_diagnostic_provider {
12918 server.update_capabilities(|capabilities| {
12919 debug_assert!(capabilities.diagnostic_provider.is_some());
12920 capabilities.diagnostic_provider = None;
12921 });
12922 }
12923
12924 notify_server_capabilities_updated(&server, cx);
12925 }
12926 "textDocument/documentColor" => {
12927 server.update_capabilities(|capabilities| {
12928 capabilities.color_provider = None;
12929 });
12930 notify_server_capabilities_updated(&server, cx);
12931 }
12932 "textDocument/foldingRange" => {
12933 server.update_capabilities(|capabilities| {
12934 capabilities.folding_range_provider = None;
12935 });
12936 notify_server_capabilities_updated(&server, cx);
12937 }
12938 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12939 }
12940 }
12941
12942 Ok(())
12943 }
12944
12945 fn clear_unregistered_diagnostics(
12946 &mut self,
12947 server_id: LanguageServerId,
12948 cleared_registration_id: SharedString,
12949 cx: &mut Context<Self>,
12950 ) -> anyhow::Result<()> {
12951 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12952
12953 self.buffer_store.update(cx, |buffer_store, cx| {
12954 for buffer_handle in buffer_store.buffers() {
12955 let buffer = buffer_handle.read(cx);
12956 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12957 let Some(abs_path) = abs_path else {
12958 continue;
12959 };
12960 affected_abs_paths.insert(abs_path);
12961 }
12962 });
12963
12964 let local = self.as_local().context("Expected LSP Store to be local")?;
12965 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12966 let Some(worktree) = self
12967 .worktree_store
12968 .read(cx)
12969 .worktree_for_id(*worktree_id, cx)
12970 else {
12971 continue;
12972 };
12973
12974 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12975 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12976 let has_matching_registration =
12977 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12978 entry.diagnostic.registration_id.as_ref()
12979 == Some(&cleared_registration_id)
12980 });
12981 if has_matching_registration {
12982 let abs_path = worktree.read(cx).absolutize(rel_path);
12983 affected_abs_paths.insert(abs_path);
12984 }
12985 }
12986 }
12987 }
12988
12989 if affected_abs_paths.is_empty() {
12990 return Ok(());
12991 }
12992
12993 // Send a fake diagnostic update which clears the state for the registration ID
12994 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12995 affected_abs_paths
12996 .into_iter()
12997 .map(|abs_path| DocumentDiagnosticsUpdate {
12998 diagnostics: DocumentDiagnostics {
12999 diagnostics: Vec::new(),
13000 document_abs_path: abs_path,
13001 version: None,
13002 },
13003 result_id: None,
13004 registration_id: Some(cleared_registration_id.clone()),
13005 server_id,
13006 disk_based_sources: Cow::Borrowed(&[]),
13007 })
13008 .collect();
13009
13010 let merge_registration_id = cleared_registration_id.clone();
13011 self.merge_diagnostic_entries(
13012 clears,
13013 move |_, diagnostic, _| {
13014 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13015 diagnostic.registration_id != Some(merge_registration_id.clone())
13016 } else {
13017 true
13018 }
13019 },
13020 cx,
13021 )?;
13022
13023 Ok(())
13024 }
13025
13026 async fn deduplicate_range_based_lsp_requests<T>(
13027 lsp_store: &Entity<Self>,
13028 server_id: Option<LanguageServerId>,
13029 lsp_request_id: LspRequestId,
13030 proto_request: &T::ProtoRequest,
13031 range: Range<Anchor>,
13032 cx: &mut AsyncApp,
13033 ) -> Result<()>
13034 where
13035 T: LspCommand,
13036 T::ProtoRequest: proto::LspRequestMessage,
13037 {
13038 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13039 let version = deserialize_version(proto_request.buffer_version());
13040 let buffer = lsp_store.update(cx, |this, cx| {
13041 this.buffer_store.read(cx).get_existing(buffer_id)
13042 })?;
13043 buffer
13044 .update(cx, |buffer, _| buffer.wait_for_version(version))
13045 .await?;
13046 lsp_store.update(cx, |lsp_store, cx| {
13047 let buffer_snapshot = buffer.read(cx).snapshot();
13048 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13049 let chunks_queried_for = lsp_data
13050 .inlay_hints
13051 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13052 .collect::<Vec<_>>();
13053 match chunks_queried_for.as_slice() {
13054 &[chunk] => {
13055 let key = LspKey {
13056 request_type: TypeId::of::<T>(),
13057 server_queried: server_id,
13058 };
13059 let previous_request = lsp_data
13060 .chunk_lsp_requests
13061 .entry(key)
13062 .or_default()
13063 .insert(chunk, lsp_request_id);
13064 if let Some((previous_request, running_requests)) =
13065 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13066 {
13067 running_requests.remove(&previous_request);
13068 }
13069 }
13070 _ambiguous_chunks => {
13071 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13072 // there, a buffer version-based check will be performed and outdated requests discarded.
13073 }
13074 }
13075 anyhow::Ok(())
13076 })?;
13077
13078 Ok(())
13079 }
13080
13081 async fn query_lsp_locally<T>(
13082 lsp_store: Entity<Self>,
13083 for_server_id: Option<LanguageServerId>,
13084 sender_id: proto::PeerId,
13085 lsp_request_id: LspRequestId,
13086 proto_request: T::ProtoRequest,
13087 position: Option<Anchor>,
13088 cx: &mut AsyncApp,
13089 ) -> Result<()>
13090 where
13091 T: LspCommand + Clone,
13092 T::ProtoRequest: proto::LspRequestMessage,
13093 <T::ProtoRequest as proto::RequestMessage>::Response:
13094 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13095 {
13096 let (buffer_version, buffer) =
13097 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13098 let request =
13099 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13100 let key = LspKey {
13101 request_type: TypeId::of::<T>(),
13102 server_queried: for_server_id,
13103 };
13104 lsp_store.update(cx, |lsp_store, cx| {
13105 let request_task = match for_server_id {
13106 Some(server_id) => {
13107 let server_task = lsp_store.request_lsp(
13108 buffer.clone(),
13109 LanguageServerToQuery::Other(server_id),
13110 request.clone(),
13111 cx,
13112 );
13113 cx.background_spawn(async move {
13114 let mut responses = Vec::new();
13115 match server_task.await {
13116 Ok(response) => responses.push((server_id, response)),
13117 // rust-analyzer likes to error with this when its still loading up
13118 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13119 Err(e) => log::error!(
13120 "Error handling response for request {request:?}: {e:#}"
13121 ),
13122 }
13123 responses
13124 })
13125 }
13126 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13127 };
13128 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13129 if T::ProtoRequest::stop_previous_requests() {
13130 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13131 lsp_requests.clear();
13132 }
13133 }
13134 lsp_data.lsp_requests.entry(key).or_default().insert(
13135 lsp_request_id,
13136 cx.spawn(async move |lsp_store, cx| {
13137 let response = request_task.await;
13138 lsp_store
13139 .update(cx, |lsp_store, cx| {
13140 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13141 {
13142 let response = response
13143 .into_iter()
13144 .map(|(server_id, response)| {
13145 (
13146 server_id.to_proto(),
13147 T::response_to_proto(
13148 response,
13149 lsp_store,
13150 sender_id,
13151 &buffer_version,
13152 cx,
13153 )
13154 .into(),
13155 )
13156 })
13157 .collect::<HashMap<_, _>>();
13158 match client.send_lsp_response::<T::ProtoRequest>(
13159 project_id,
13160 lsp_request_id,
13161 response,
13162 ) {
13163 Ok(()) => {}
13164 Err(e) => {
13165 log::error!("Failed to send LSP response: {e:#}",)
13166 }
13167 }
13168 }
13169 })
13170 .ok();
13171 }),
13172 );
13173 });
13174 Ok(())
13175 }
13176
13177 async fn wait_for_buffer_version<T>(
13178 lsp_store: &Entity<Self>,
13179 proto_request: &T::ProtoRequest,
13180 cx: &mut AsyncApp,
13181 ) -> Result<(Global, Entity<Buffer>)>
13182 where
13183 T: LspCommand,
13184 T::ProtoRequest: proto::LspRequestMessage,
13185 {
13186 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13187 let version = deserialize_version(proto_request.buffer_version());
13188 let buffer = lsp_store.update(cx, |this, cx| {
13189 this.buffer_store.read(cx).get_existing(buffer_id)
13190 })?;
13191 buffer
13192 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13193 .await?;
13194 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13195 Ok((buffer_version, buffer))
13196 }
13197
13198 fn take_text_document_sync_options(
13199 capabilities: &mut lsp::ServerCapabilities,
13200 ) -> lsp::TextDocumentSyncOptions {
13201 match capabilities.text_document_sync.take() {
13202 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13203 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13204 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13205 sync_options.change = Some(sync_kind);
13206 sync_options
13207 }
13208 None => lsp::TextDocumentSyncOptions::default(),
13209 }
13210 }
13211
13212 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13213 self.downstream_client.clone()
13214 }
13215
13216 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13217 self.worktree_store.clone()
13218 }
13219
13220 /// Gets what's stored in the LSP data for the given buffer.
13221 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13222 self.lsp_data.get_mut(&buffer_id)
13223 }
13224
13225 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13226 /// new [`BufferLspData`] will be created to replace the previous state.
13227 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13228 let (buffer_id, buffer_version) =
13229 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13230 let lsp_data = self
13231 .lsp_data
13232 .entry(buffer_id)
13233 .or_insert_with(|| BufferLspData::new(buffer, cx));
13234 if buffer_version.changed_since(&lsp_data.buffer_version) {
13235 // To send delta requests for semantic tokens, the previous tokens
13236 // need to be kept between buffer changes.
13237 let semantic_tokens = lsp_data.semantic_tokens.take();
13238 *lsp_data = BufferLspData::new(buffer, cx);
13239 lsp_data.semantic_tokens = semantic_tokens;
13240 }
13241 lsp_data
13242 }
13243}
13244
13245// Registration with registerOptions as null, should fallback to true.
13246// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13247fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13248 reg: lsp::Registration,
13249) -> Result<OneOf<bool, T>> {
13250 Ok(match reg.register_options {
13251 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13252 None => OneOf::Left(true),
13253 })
13254}
13255
13256fn subscribe_to_binary_statuses(
13257 languages: &Arc<LanguageRegistry>,
13258 cx: &mut Context<'_, LspStore>,
13259) -> Task<()> {
13260 let mut server_statuses = languages.language_server_binary_statuses();
13261 cx.spawn(async move |lsp_store, cx| {
13262 while let Some((server_name, binary_status)) = server_statuses.next().await {
13263 if lsp_store
13264 .update(cx, |_, cx| {
13265 let mut message = None;
13266 let binary_status = match binary_status {
13267 BinaryStatus::None => proto::ServerBinaryStatus::None,
13268 BinaryStatus::CheckingForUpdate => {
13269 proto::ServerBinaryStatus::CheckingForUpdate
13270 }
13271 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13272 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13273 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13274 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13275 BinaryStatus::Failed { error } => {
13276 message = Some(error);
13277 proto::ServerBinaryStatus::Failed
13278 }
13279 };
13280 cx.emit(LspStoreEvent::LanguageServerUpdate {
13281 // Binary updates are about the binary that might not have any language server id at that point.
13282 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13283 language_server_id: LanguageServerId(0),
13284 name: Some(server_name),
13285 message: proto::update_language_server::Variant::StatusUpdate(
13286 proto::StatusUpdate {
13287 message,
13288 status: Some(proto::status_update::Status::Binary(
13289 binary_status as i32,
13290 )),
13291 },
13292 ),
13293 });
13294 })
13295 .is_err()
13296 {
13297 break;
13298 }
13299 }
13300 })
13301}
13302
13303fn lsp_workspace_diagnostics_refresh(
13304 registration_id: Option<String>,
13305 options: DiagnosticServerCapabilities,
13306 server: Arc<LanguageServer>,
13307 cx: &mut Context<'_, LspStore>,
13308) -> Option<WorkspaceRefreshTask> {
13309 let identifier = workspace_diagnostic_identifier(&options)?;
13310 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13311
13312 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13313 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13314 refresh_tx.try_send(()).ok();
13315
13316 let request_timeout = ProjectSettings::get_global(cx)
13317 .global_lsp_settings
13318 .get_request_timeout();
13319
13320 // 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.
13321 // This allows users to increase the duration if need be
13322 let timeout = if request_timeout != Duration::ZERO {
13323 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13324 } else {
13325 request_timeout
13326 };
13327
13328 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13329 let mut attempts = 0;
13330 let max_attempts = 50;
13331 let mut requests = 0;
13332
13333 loop {
13334 let Some(()) = refresh_rx.recv().await else {
13335 return;
13336 };
13337
13338 'request: loop {
13339 requests += 1;
13340 if attempts > max_attempts {
13341 log::error!(
13342 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13343 );
13344 return;
13345 }
13346 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13347 cx.background_executor()
13348 .timer(Duration::from_millis(backoff_millis))
13349 .await;
13350 attempts += 1;
13351
13352 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13353 lsp_store
13354 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13355 .into_iter()
13356 .filter_map(|(abs_path, result_id)| {
13357 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13358 Some(lsp::PreviousResultId {
13359 uri,
13360 value: result_id.to_string(),
13361 })
13362 })
13363 .collect()
13364 }) else {
13365 return;
13366 };
13367
13368 let token = if let Some(registration_id) = ®istration_id {
13369 format!(
13370 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13371 server.server_id(),
13372 )
13373 } else {
13374 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13375 };
13376
13377 progress_rx.try_recv().ok();
13378 let timer = server.request_timer(timeout).fuse();
13379 let progress = pin!(progress_rx.recv().fuse());
13380 let response_result = server
13381 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13382 lsp::WorkspaceDiagnosticParams {
13383 previous_result_ids,
13384 identifier: identifier.clone(),
13385 work_done_progress_params: Default::default(),
13386 partial_result_params: lsp::PartialResultParams {
13387 partial_result_token: Some(lsp::ProgressToken::String(token)),
13388 },
13389 },
13390 select(timer, progress).then(|either| match either {
13391 Either::Left((message, ..)) => ready(message).left_future(),
13392 Either::Right(..) => pending::<String>().right_future(),
13393 }),
13394 )
13395 .await;
13396
13397 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13398 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13399 match response_result {
13400 ConnectionResult::Timeout => {
13401 log::error!("Timeout during workspace diagnostics pull");
13402 continue 'request;
13403 }
13404 ConnectionResult::ConnectionReset => {
13405 log::error!("Server closed a workspace diagnostics pull request");
13406 continue 'request;
13407 }
13408 ConnectionResult::Result(Err(e)) => {
13409 log::error!("Error during workspace diagnostics pull: {e:#}");
13410 break 'request;
13411 }
13412 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13413 attempts = 0;
13414 if lsp_store
13415 .update(cx, |lsp_store, cx| {
13416 lsp_store.apply_workspace_diagnostic_report(
13417 server.server_id(),
13418 pulled_diagnostics,
13419 registration_id_shared.clone(),
13420 cx,
13421 )
13422 })
13423 .is_err()
13424 {
13425 return;
13426 }
13427 break 'request;
13428 }
13429 }
13430 }
13431 }
13432 });
13433
13434 Some(WorkspaceRefreshTask {
13435 refresh_tx,
13436 progress_tx,
13437 task: workspace_query_language_server,
13438 })
13439}
13440
13441fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13442 match &options {
13443 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13444 .identifier
13445 .as_deref()
13446 .map(SharedString::new),
13447 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13448 let diagnostic_options = ®istration_options.diagnostic_options;
13449 diagnostic_options
13450 .identifier
13451 .as_deref()
13452 .map(SharedString::new)
13453 }
13454 }
13455}
13456
13457fn workspace_diagnostic_identifier(
13458 options: &DiagnosticServerCapabilities,
13459) -> Option<Option<String>> {
13460 match &options {
13461 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13462 if !diagnostic_options.workspace_diagnostics {
13463 return None;
13464 }
13465 Some(diagnostic_options.identifier.clone())
13466 }
13467 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13468 let diagnostic_options = ®istration_options.diagnostic_options;
13469 if !diagnostic_options.workspace_diagnostics {
13470 return None;
13471 }
13472 Some(diagnostic_options.identifier.clone())
13473 }
13474 }
13475}
13476
13477fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13478 let CompletionSource::BufferWord {
13479 word_range,
13480 resolved,
13481 } = &mut completion.source
13482 else {
13483 return;
13484 };
13485 if *resolved {
13486 return;
13487 }
13488
13489 if completion.new_text
13490 != snapshot
13491 .text_for_range(word_range.clone())
13492 .collect::<String>()
13493 {
13494 return;
13495 }
13496
13497 let mut offset = 0;
13498 for chunk in snapshot.chunks(word_range.clone(), true) {
13499 let end_offset = offset + chunk.text.len();
13500 if let Some(highlight_id) = chunk.syntax_highlight_id {
13501 completion
13502 .label
13503 .runs
13504 .push((offset..end_offset, highlight_id));
13505 }
13506 offset = end_offset;
13507 }
13508 *resolved = true;
13509}
13510
13511impl EventEmitter<LspStoreEvent> for LspStore {}
13512
13513fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13514 hover
13515 .contents
13516 .retain(|hover_block| !hover_block.text.trim().is_empty());
13517 if hover.contents.is_empty() {
13518 None
13519 } else {
13520 Some(hover)
13521 }
13522}
13523
13524async fn populate_labels_for_completions(
13525 new_completions: Vec<CoreCompletion>,
13526 language: Option<Arc<Language>>,
13527 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13528) -> Vec<Completion> {
13529 let lsp_completions = new_completions
13530 .iter()
13531 .filter_map(|new_completion| {
13532 new_completion
13533 .source
13534 .lsp_completion(true)
13535 .map(|lsp_completion| lsp_completion.into_owned())
13536 })
13537 .collect::<Vec<_>>();
13538
13539 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13540 lsp_adapter
13541 .labels_for_completions(&lsp_completions, language)
13542 .await
13543 .log_err()
13544 .unwrap_or_default()
13545 } else {
13546 Vec::new()
13547 }
13548 .into_iter()
13549 .fuse();
13550
13551 let mut completions = Vec::new();
13552 for completion in new_completions {
13553 match completion.source.lsp_completion(true) {
13554 Some(lsp_completion) => {
13555 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13556
13557 let mut label = labels.next().flatten().unwrap_or_else(|| {
13558 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13559 });
13560 ensure_uniform_list_compatible_label(&mut label);
13561 completions.push(Completion {
13562 label,
13563 documentation,
13564 replace_range: completion.replace_range,
13565 new_text: completion.new_text,
13566 insert_text_mode: lsp_completion.insert_text_mode,
13567 source: completion.source,
13568 icon_path: None,
13569 confirm: None,
13570 match_start: None,
13571 snippet_deduplication_key: None,
13572 });
13573 }
13574 None => {
13575 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13576 ensure_uniform_list_compatible_label(&mut label);
13577 completions.push(Completion {
13578 label,
13579 documentation: None,
13580 replace_range: completion.replace_range,
13581 new_text: completion.new_text,
13582 source: completion.source,
13583 insert_text_mode: None,
13584 icon_path: None,
13585 confirm: None,
13586 match_start: None,
13587 snippet_deduplication_key: None,
13588 });
13589 }
13590 }
13591 }
13592 completions
13593}
13594
13595#[derive(Debug)]
13596pub enum LanguageServerToQuery {
13597 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13598 FirstCapable,
13599 /// Query a specific language server.
13600 Other(LanguageServerId),
13601}
13602
13603#[derive(Default)]
13604struct RenamePathsWatchedForServer {
13605 did_rename: Vec<RenameActionPredicate>,
13606 will_rename: Vec<RenameActionPredicate>,
13607}
13608
13609impl RenamePathsWatchedForServer {
13610 fn with_did_rename_patterns(
13611 mut self,
13612 did_rename: Option<&FileOperationRegistrationOptions>,
13613 ) -> Self {
13614 if let Some(did_rename) = did_rename {
13615 self.did_rename = did_rename
13616 .filters
13617 .iter()
13618 .filter_map(|filter| filter.try_into().log_err())
13619 .collect();
13620 }
13621 self
13622 }
13623 fn with_will_rename_patterns(
13624 mut self,
13625 will_rename: Option<&FileOperationRegistrationOptions>,
13626 ) -> Self {
13627 if let Some(will_rename) = will_rename {
13628 self.will_rename = will_rename
13629 .filters
13630 .iter()
13631 .filter_map(|filter| filter.try_into().log_err())
13632 .collect();
13633 }
13634 self
13635 }
13636
13637 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13638 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13639 }
13640 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13641 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13642 }
13643}
13644
13645impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13646 type Error = globset::Error;
13647 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13648 Ok(Self {
13649 kind: ops.pattern.matches.clone(),
13650 glob: GlobBuilder::new(&ops.pattern.glob)
13651 .case_insensitive(
13652 ops.pattern
13653 .options
13654 .as_ref()
13655 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13656 )
13657 .build()?
13658 .compile_matcher(),
13659 })
13660 }
13661}
13662struct RenameActionPredicate {
13663 glob: GlobMatcher,
13664 kind: Option<FileOperationPatternKind>,
13665}
13666
13667impl RenameActionPredicate {
13668 // Returns true if language server should be notified
13669 fn eval(&self, path: &str, is_dir: bool) -> bool {
13670 self.kind.as_ref().is_none_or(|kind| {
13671 let expected_kind = if is_dir {
13672 FileOperationPatternKind::Folder
13673 } else {
13674 FileOperationPatternKind::File
13675 };
13676 kind == &expected_kind
13677 }) && self.glob.is_match(path)
13678 }
13679}
13680
13681#[derive(Default)]
13682struct LanguageServerWatchedPaths {
13683 worktree_paths: HashMap<WorktreeId, GlobSet>,
13684 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13685}
13686
13687#[derive(Default)]
13688struct LanguageServerWatchedPathsBuilder {
13689 worktree_paths: HashMap<WorktreeId, GlobSet>,
13690 abs_paths: HashMap<Arc<Path>, GlobSet>,
13691}
13692
13693impl LanguageServerWatchedPathsBuilder {
13694 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13695 self.worktree_paths.insert(worktree_id, glob_set);
13696 }
13697 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13698 self.abs_paths.insert(path, glob_set);
13699 }
13700 fn build(
13701 self,
13702 fs: Arc<dyn Fs>,
13703 language_server_id: LanguageServerId,
13704 cx: &mut Context<LspStore>,
13705 ) -> LanguageServerWatchedPaths {
13706 let lsp_store = cx.weak_entity();
13707
13708 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13709 let abs_paths = self
13710 .abs_paths
13711 .into_iter()
13712 .map(|(abs_path, globset)| {
13713 let task = cx.spawn({
13714 let abs_path = abs_path.clone();
13715 let fs = fs.clone();
13716
13717 let lsp_store = lsp_store.clone();
13718 async move |_, cx| {
13719 maybe!(async move {
13720 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13721 while let Some(update) = push_updates.0.next().await {
13722 let action = lsp_store
13723 .update(cx, |this, _| {
13724 let Some(local) = this.as_local() else {
13725 return ControlFlow::Break(());
13726 };
13727 let Some(watcher) = local
13728 .language_server_watched_paths
13729 .get(&language_server_id)
13730 else {
13731 return ControlFlow::Break(());
13732 };
13733 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13734 "Watched abs path is not registered with a watcher",
13735 );
13736 let matching_entries = update
13737 .into_iter()
13738 .filter(|event| globs.is_match(&event.path))
13739 .collect::<Vec<_>>();
13740 this.lsp_notify_abs_paths_changed(
13741 language_server_id,
13742 matching_entries,
13743 );
13744 ControlFlow::Continue(())
13745 })
13746 .ok()?;
13747
13748 if action.is_break() {
13749 break;
13750 }
13751 }
13752 Some(())
13753 })
13754 .await;
13755 }
13756 });
13757 (abs_path, (globset, task))
13758 })
13759 .collect();
13760 LanguageServerWatchedPaths {
13761 worktree_paths: self.worktree_paths,
13762 abs_paths,
13763 }
13764 }
13765}
13766
13767struct LspBufferSnapshot {
13768 version: i32,
13769 snapshot: TextBufferSnapshot,
13770}
13771
13772/// A prompt requested by LSP server.
13773#[derive(Clone, Debug)]
13774pub struct LanguageServerPromptRequest {
13775 pub id: usize,
13776 pub level: PromptLevel,
13777 pub message: String,
13778 pub actions: Vec<MessageActionItem>,
13779 pub lsp_name: String,
13780 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13781}
13782
13783impl LanguageServerPromptRequest {
13784 pub fn new(
13785 level: PromptLevel,
13786 message: String,
13787 actions: Vec<MessageActionItem>,
13788 lsp_name: String,
13789 response_channel: smol::channel::Sender<MessageActionItem>,
13790 ) -> Self {
13791 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13792 LanguageServerPromptRequest {
13793 id,
13794 level,
13795 message,
13796 actions,
13797 lsp_name,
13798 response_channel,
13799 }
13800 }
13801 pub async fn respond(self, index: usize) -> Option<()> {
13802 if let Some(response) = self.actions.into_iter().nth(index) {
13803 self.response_channel.send(response).await.ok()
13804 } else {
13805 None
13806 }
13807 }
13808
13809 #[cfg(any(test, feature = "test-support"))]
13810 pub fn test(
13811 level: PromptLevel,
13812 message: String,
13813 actions: Vec<MessageActionItem>,
13814 lsp_name: String,
13815 ) -> Self {
13816 let (tx, _rx) = smol::channel::unbounded();
13817 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13818 }
13819}
13820impl PartialEq for LanguageServerPromptRequest {
13821 fn eq(&self, other: &Self) -> bool {
13822 self.message == other.message && self.actions == other.actions
13823 }
13824}
13825
13826#[derive(Clone, Debug, PartialEq)]
13827pub enum LanguageServerLogType {
13828 Log(MessageType),
13829 Trace { verbose_info: Option<String> },
13830 Rpc { received: bool },
13831}
13832
13833impl LanguageServerLogType {
13834 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13835 match self {
13836 Self::Log(log_type) => {
13837 use proto::log_message::LogLevel;
13838 let level = match *log_type {
13839 MessageType::ERROR => LogLevel::Error,
13840 MessageType::WARNING => LogLevel::Warning,
13841 MessageType::INFO => LogLevel::Info,
13842 MessageType::LOG => LogLevel::Log,
13843 other => {
13844 log::warn!("Unknown lsp log message type: {other:?}");
13845 LogLevel::Log
13846 }
13847 };
13848 proto::language_server_log::LogType::Log(proto::LogMessage {
13849 level: level as i32,
13850 })
13851 }
13852 Self::Trace { verbose_info } => {
13853 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13854 verbose_info: verbose_info.to_owned(),
13855 })
13856 }
13857 Self::Rpc { received } => {
13858 let kind = if *received {
13859 proto::rpc_message::Kind::Received
13860 } else {
13861 proto::rpc_message::Kind::Sent
13862 };
13863 let kind = kind as i32;
13864 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13865 }
13866 }
13867 }
13868
13869 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13870 use proto::log_message::LogLevel;
13871 use proto::rpc_message;
13872 match log_type {
13873 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13874 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13875 LogLevel::Error => MessageType::ERROR,
13876 LogLevel::Warning => MessageType::WARNING,
13877 LogLevel::Info => MessageType::INFO,
13878 LogLevel::Log => MessageType::LOG,
13879 },
13880 ),
13881 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13882 verbose_info: trace_message.verbose_info,
13883 },
13884 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13885 received: match rpc_message::Kind::from_i32(message.kind)
13886 .unwrap_or(rpc_message::Kind::Received)
13887 {
13888 rpc_message::Kind::Received => true,
13889 rpc_message::Kind::Sent => false,
13890 },
13891 },
13892 }
13893 }
13894}
13895
13896pub struct WorkspaceRefreshTask {
13897 refresh_tx: mpsc::Sender<()>,
13898 progress_tx: mpsc::Sender<()>,
13899 #[allow(dead_code)]
13900 task: Task<()>,
13901}
13902
13903pub enum LanguageServerState {
13904 Starting {
13905 startup: Task<Option<Arc<LanguageServer>>>,
13906 /// List of language servers that will be added to the workspace once it's initialization completes.
13907 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13908 },
13909
13910 Running {
13911 adapter: Arc<CachedLspAdapter>,
13912 server: Arc<LanguageServer>,
13913 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13914 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13915 },
13916}
13917
13918impl LanguageServerState {
13919 fn add_workspace_folder(&self, uri: Uri) {
13920 match self {
13921 LanguageServerState::Starting {
13922 pending_workspace_folders,
13923 ..
13924 } => {
13925 pending_workspace_folders.lock().insert(uri);
13926 }
13927 LanguageServerState::Running { server, .. } => {
13928 server.add_workspace_folder(uri);
13929 }
13930 }
13931 }
13932 fn _remove_workspace_folder(&self, uri: Uri) {
13933 match self {
13934 LanguageServerState::Starting {
13935 pending_workspace_folders,
13936 ..
13937 } => {
13938 pending_workspace_folders.lock().remove(&uri);
13939 }
13940 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13941 }
13942 }
13943}
13944
13945impl std::fmt::Debug for LanguageServerState {
13946 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13947 match self {
13948 LanguageServerState::Starting { .. } => {
13949 f.debug_struct("LanguageServerState::Starting").finish()
13950 }
13951 LanguageServerState::Running { .. } => {
13952 f.debug_struct("LanguageServerState::Running").finish()
13953 }
13954 }
13955 }
13956}
13957
13958#[derive(Clone, Debug, Serialize)]
13959pub struct LanguageServerProgress {
13960 pub is_disk_based_diagnostics_progress: bool,
13961 pub is_cancellable: bool,
13962 pub title: Option<String>,
13963 pub message: Option<String>,
13964 pub percentage: Option<usize>,
13965 #[serde(skip_serializing)]
13966 pub last_update_at: Instant,
13967}
13968
13969#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13970pub struct DiagnosticSummary {
13971 pub error_count: usize,
13972 pub warning_count: usize,
13973}
13974
13975impl DiagnosticSummary {
13976 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13977 let mut this = Self {
13978 error_count: 0,
13979 warning_count: 0,
13980 };
13981
13982 for entry in diagnostics {
13983 if entry.diagnostic.is_primary {
13984 match entry.diagnostic.severity {
13985 DiagnosticSeverity::ERROR => this.error_count += 1,
13986 DiagnosticSeverity::WARNING => this.warning_count += 1,
13987 _ => {}
13988 }
13989 }
13990 }
13991
13992 this
13993 }
13994
13995 pub fn is_empty(&self) -> bool {
13996 self.error_count == 0 && self.warning_count == 0
13997 }
13998
13999 pub fn to_proto(
14000 self,
14001 language_server_id: LanguageServerId,
14002 path: &RelPath,
14003 ) -> proto::DiagnosticSummary {
14004 proto::DiagnosticSummary {
14005 path: path.to_proto(),
14006 language_server_id: language_server_id.0 as u64,
14007 error_count: self.error_count as u32,
14008 warning_count: self.warning_count as u32,
14009 }
14010 }
14011}
14012
14013#[derive(Clone, Debug)]
14014pub enum CompletionDocumentation {
14015 /// There is no documentation for this completion.
14016 Undocumented,
14017 /// A single line of documentation.
14018 SingleLine(SharedString),
14019 /// Multiple lines of plain text documentation.
14020 MultiLinePlainText(SharedString),
14021 /// Markdown documentation.
14022 MultiLineMarkdown(SharedString),
14023 /// Both single line and multiple lines of plain text documentation.
14024 SingleLineAndMultiLinePlainText {
14025 single_line: SharedString,
14026 plain_text: Option<SharedString>,
14027 },
14028}
14029
14030impl CompletionDocumentation {
14031 #[cfg(any(test, feature = "test-support"))]
14032 pub fn text(&self) -> SharedString {
14033 match self {
14034 CompletionDocumentation::Undocumented => "".into(),
14035 CompletionDocumentation::SingleLine(s) => s.clone(),
14036 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14037 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14038 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14039 single_line.clone()
14040 }
14041 }
14042 }
14043}
14044
14045impl From<lsp::Documentation> for CompletionDocumentation {
14046 fn from(docs: lsp::Documentation) -> Self {
14047 match docs {
14048 lsp::Documentation::String(text) => {
14049 if text.lines().count() <= 1 {
14050 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14051 } else {
14052 CompletionDocumentation::MultiLinePlainText(text.into())
14053 }
14054 }
14055
14056 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14057 lsp::MarkupKind::PlainText => {
14058 if value.lines().count() <= 1 {
14059 CompletionDocumentation::SingleLine(value.into())
14060 } else {
14061 CompletionDocumentation::MultiLinePlainText(value.into())
14062 }
14063 }
14064
14065 lsp::MarkupKind::Markdown => {
14066 CompletionDocumentation::MultiLineMarkdown(value.into())
14067 }
14068 },
14069 }
14070 }
14071}
14072
14073pub enum ResolvedHint {
14074 Resolved(InlayHint),
14075 Resolving(Shared<Task<()>>),
14076}
14077
14078pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14079 glob.components()
14080 .take_while(|component| match component {
14081 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14082 _ => true,
14083 })
14084 .collect()
14085}
14086
14087pub struct SshLspAdapter {
14088 name: LanguageServerName,
14089 binary: LanguageServerBinary,
14090 initialization_options: Option<String>,
14091 code_action_kinds: Option<Vec<CodeActionKind>>,
14092}
14093
14094impl SshLspAdapter {
14095 pub fn new(
14096 name: LanguageServerName,
14097 binary: LanguageServerBinary,
14098 initialization_options: Option<String>,
14099 code_action_kinds: Option<String>,
14100 ) -> Self {
14101 Self {
14102 name,
14103 binary,
14104 initialization_options,
14105 code_action_kinds: code_action_kinds
14106 .as_ref()
14107 .and_then(|c| serde_json::from_str(c).ok()),
14108 }
14109 }
14110}
14111
14112impl LspInstaller for SshLspAdapter {
14113 type BinaryVersion = ();
14114 async fn check_if_user_installed(
14115 &self,
14116 _: &dyn LspAdapterDelegate,
14117 _: Option<Toolchain>,
14118 _: &AsyncApp,
14119 ) -> Option<LanguageServerBinary> {
14120 Some(self.binary.clone())
14121 }
14122
14123 async fn cached_server_binary(
14124 &self,
14125 _: PathBuf,
14126 _: &dyn LspAdapterDelegate,
14127 ) -> Option<LanguageServerBinary> {
14128 None
14129 }
14130
14131 async fn fetch_latest_server_version(
14132 &self,
14133 _: &dyn LspAdapterDelegate,
14134 _: bool,
14135 _: &mut AsyncApp,
14136 ) -> Result<()> {
14137 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14138 }
14139
14140 async fn fetch_server_binary(
14141 &self,
14142 _: (),
14143 _: PathBuf,
14144 _: &dyn LspAdapterDelegate,
14145 ) -> Result<LanguageServerBinary> {
14146 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14147 }
14148}
14149
14150#[async_trait(?Send)]
14151impl LspAdapter for SshLspAdapter {
14152 fn name(&self) -> LanguageServerName {
14153 self.name.clone()
14154 }
14155
14156 async fn initialization_options(
14157 self: Arc<Self>,
14158 _: &Arc<dyn LspAdapterDelegate>,
14159 _: &mut AsyncApp,
14160 ) -> Result<Option<serde_json::Value>> {
14161 let Some(options) = &self.initialization_options else {
14162 return Ok(None);
14163 };
14164 let result = serde_json::from_str(options)?;
14165 Ok(result)
14166 }
14167
14168 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14169 self.code_action_kinds.clone()
14170 }
14171}
14172
14173pub fn language_server_settings<'a>(
14174 delegate: &'a dyn LspAdapterDelegate,
14175 language: &LanguageServerName,
14176 cx: &'a App,
14177) -> Option<&'a LspSettings> {
14178 language_server_settings_for(
14179 SettingsLocation {
14180 worktree_id: delegate.worktree_id(),
14181 path: RelPath::empty(),
14182 },
14183 language,
14184 cx,
14185 )
14186}
14187
14188pub fn language_server_settings_for<'a>(
14189 location: SettingsLocation<'a>,
14190 language: &LanguageServerName,
14191 cx: &'a App,
14192) -> Option<&'a LspSettings> {
14193 ProjectSettings::get(Some(location), cx).lsp.get(language)
14194}
14195
14196pub struct LocalLspAdapterDelegate {
14197 lsp_store: WeakEntity<LspStore>,
14198 worktree: worktree::Snapshot,
14199 fs: Arc<dyn Fs>,
14200 http_client: Arc<dyn HttpClient>,
14201 language_registry: Arc<LanguageRegistry>,
14202 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14203}
14204
14205impl LocalLspAdapterDelegate {
14206 pub fn new(
14207 language_registry: Arc<LanguageRegistry>,
14208 environment: &Entity<ProjectEnvironment>,
14209 lsp_store: WeakEntity<LspStore>,
14210 worktree: &Entity<Worktree>,
14211 http_client: Arc<dyn HttpClient>,
14212 fs: Arc<dyn Fs>,
14213 cx: &mut App,
14214 ) -> Arc<Self> {
14215 let load_shell_env_task =
14216 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14217
14218 Arc::new(Self {
14219 lsp_store,
14220 worktree: worktree.read(cx).snapshot(),
14221 fs,
14222 http_client,
14223 language_registry,
14224 load_shell_env_task,
14225 })
14226 }
14227
14228 pub fn from_local_lsp(
14229 local: &LocalLspStore,
14230 worktree: &Entity<Worktree>,
14231 cx: &mut App,
14232 ) -> Arc<Self> {
14233 Self::new(
14234 local.languages.clone(),
14235 &local.environment,
14236 local.weak.clone(),
14237 worktree,
14238 local.http_client.clone(),
14239 local.fs.clone(),
14240 cx,
14241 )
14242 }
14243}
14244
14245#[async_trait]
14246impl LspAdapterDelegate for LocalLspAdapterDelegate {
14247 fn show_notification(&self, message: &str, cx: &mut App) {
14248 self.lsp_store
14249 .update(cx, |_, cx| {
14250 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14251 })
14252 .ok();
14253 }
14254
14255 fn http_client(&self) -> Arc<dyn HttpClient> {
14256 self.http_client.clone()
14257 }
14258
14259 fn worktree_id(&self) -> WorktreeId {
14260 self.worktree.id()
14261 }
14262
14263 fn worktree_root_path(&self) -> &Path {
14264 self.worktree.abs_path().as_ref()
14265 }
14266
14267 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14268 self.worktree.resolve_relative_path(path)
14269 }
14270
14271 async fn shell_env(&self) -> HashMap<String, String> {
14272 let task = self.load_shell_env_task.clone();
14273 task.await.unwrap_or_default()
14274 }
14275
14276 async fn npm_package_installed_version(
14277 &self,
14278 package_name: &str,
14279 ) -> Result<Option<(PathBuf, Version)>> {
14280 let local_package_directory = self.worktree_root_path();
14281 let node_modules_directory = local_package_directory.join("node_modules");
14282
14283 if let Some(version) =
14284 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14285 {
14286 return Ok(Some((node_modules_directory, version)));
14287 }
14288 let Some(npm) = self.which("npm".as_ref()).await else {
14289 log::warn!(
14290 "Failed to find npm executable for {:?}",
14291 local_package_directory
14292 );
14293 return Ok(None);
14294 };
14295
14296 let env = self.shell_env().await;
14297 let output = util::command::new_command(&npm)
14298 .args(["root", "-g"])
14299 .envs(env)
14300 .current_dir(local_package_directory)
14301 .output()
14302 .await?;
14303 let global_node_modules =
14304 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14305
14306 if let Some(version) =
14307 read_package_installed_version(global_node_modules.clone(), package_name).await?
14308 {
14309 return Ok(Some((global_node_modules, version)));
14310 }
14311 return Ok(None);
14312 }
14313
14314 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14315 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14316 if self.fs.is_file(&worktree_abs_path).await {
14317 worktree_abs_path.pop();
14318 }
14319
14320 let env = self.shell_env().await;
14321
14322 let shell_path = env.get("PATH").cloned();
14323
14324 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14325 }
14326
14327 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14328 let mut working_dir = self.worktree_root_path().to_path_buf();
14329 if self.fs.is_file(&working_dir).await {
14330 working_dir.pop();
14331 }
14332 let output = util::command::new_command(&command.path)
14333 .args(command.arguments)
14334 .envs(command.env.clone().unwrap_or_default())
14335 .current_dir(working_dir)
14336 .output()
14337 .await?;
14338
14339 anyhow::ensure!(
14340 output.status.success(),
14341 "{}, stdout: {:?}, stderr: {:?}",
14342 output.status,
14343 String::from_utf8_lossy(&output.stdout),
14344 String::from_utf8_lossy(&output.stderr)
14345 );
14346 Ok(())
14347 }
14348
14349 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14350 self.language_registry
14351 .update_lsp_binary_status(server_name, status);
14352 }
14353
14354 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14355 self.language_registry
14356 .all_lsp_adapters()
14357 .into_iter()
14358 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14359 .collect()
14360 }
14361
14362 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14363 let dir = self.language_registry.language_server_download_dir(name)?;
14364
14365 if !dir.exists() {
14366 smol::fs::create_dir_all(&dir)
14367 .await
14368 .context("failed to create container directory")
14369 .log_err()?;
14370 }
14371
14372 Some(dir)
14373 }
14374
14375 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14376 let entry = self
14377 .worktree
14378 .entry_for_path(path)
14379 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14380 let abs_path = self.worktree.absolutize(&entry.path);
14381 self.fs.load(&abs_path).await
14382 }
14383}
14384
14385async fn populate_labels_for_symbols(
14386 symbols: Vec<CoreSymbol>,
14387 language_registry: &Arc<LanguageRegistry>,
14388 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14389 output: &mut Vec<Symbol>,
14390) {
14391 #[allow(clippy::mutable_key_type)]
14392 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14393
14394 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14395 for symbol in symbols {
14396 let Some(file_name) = symbol.path.file_name() else {
14397 continue;
14398 };
14399 let language = language_registry
14400 .load_language_for_file_path(Path::new(file_name))
14401 .await
14402 .ok()
14403 .or_else(|| {
14404 unknown_paths.insert(file_name.into());
14405 None
14406 });
14407 symbols_by_language
14408 .entry(language)
14409 .or_default()
14410 .push(symbol);
14411 }
14412
14413 for unknown_path in unknown_paths {
14414 log::info!("no language found for symbol in file {unknown_path:?}");
14415 }
14416
14417 let mut label_params = Vec::new();
14418 for (language, mut symbols) in symbols_by_language {
14419 label_params.clear();
14420 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14421 name: mem::take(&mut symbol.name),
14422 kind: symbol.kind,
14423 container_name: symbol.container_name.take(),
14424 }));
14425
14426 let mut labels = Vec::new();
14427 if let Some(language) = language {
14428 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14429 language_registry
14430 .lsp_adapters(&language.name())
14431 .first()
14432 .cloned()
14433 });
14434 if let Some(lsp_adapter) = lsp_adapter {
14435 labels = lsp_adapter
14436 .labels_for_symbols(&label_params, &language)
14437 .await
14438 .log_err()
14439 .unwrap_or_default();
14440 }
14441 }
14442
14443 for (
14444 (
14445 symbol,
14446 language::Symbol {
14447 name,
14448 container_name,
14449 ..
14450 },
14451 ),
14452 label,
14453 ) in symbols
14454 .into_iter()
14455 .zip(label_params.drain(..))
14456 .zip(labels.into_iter().chain(iter::repeat(None)))
14457 {
14458 output.push(Symbol {
14459 language_server_name: symbol.language_server_name,
14460 source_worktree_id: symbol.source_worktree_id,
14461 source_language_server_id: symbol.source_language_server_id,
14462 path: symbol.path,
14463 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14464 name,
14465 kind: symbol.kind,
14466 range: symbol.range,
14467 container_name,
14468 });
14469 }
14470 }
14471}
14472
14473pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14474 text.lines()
14475 .map(|line| line.trim())
14476 .filter(|line| !line.is_empty())
14477 .join(separator)
14478}
14479
14480fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14481 match server.capabilities().text_document_sync.as_ref()? {
14482 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14483 // Server wants didSave but didn't specify includeText.
14484 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14485 // Server doesn't want didSave at all.
14486 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14487 // Server provided SaveOptions.
14488 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14489 Some(save_options.include_text.unwrap_or(false))
14490 }
14491 },
14492 // We do not have any save info. Kind affects didChange only.
14493 lsp::TextDocumentSyncCapability::Kind(_) => None,
14494 }
14495}
14496
14497/// Completion items are displayed in a `UniformList`.
14498/// Usually, those items are single-line strings, but in LSP responses,
14499/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14500/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14501/// 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,
14502/// breaking the completions menu presentation.
14503///
14504/// 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.
14505pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14506 let mut new_text = String::with_capacity(label.text.len());
14507 let mut offset_map = vec![0; label.text.len() + 1];
14508 let mut last_char_was_space = false;
14509 let mut new_idx = 0;
14510 let chars = label.text.char_indices().fuse();
14511 let mut newlines_removed = false;
14512
14513 for (idx, c) in chars {
14514 offset_map[idx] = new_idx;
14515
14516 match c {
14517 '\n' if last_char_was_space => {
14518 newlines_removed = true;
14519 }
14520 '\t' | ' ' if last_char_was_space => {}
14521 '\n' if !last_char_was_space => {
14522 new_text.push(' ');
14523 new_idx += 1;
14524 last_char_was_space = true;
14525 newlines_removed = true;
14526 }
14527 ' ' | '\t' => {
14528 new_text.push(' ');
14529 new_idx += 1;
14530 last_char_was_space = true;
14531 }
14532 _ => {
14533 new_text.push(c);
14534 new_idx += c.len_utf8();
14535 last_char_was_space = false;
14536 }
14537 }
14538 }
14539 offset_map[label.text.len()] = new_idx;
14540
14541 // Only modify the label if newlines were removed.
14542 if !newlines_removed {
14543 return;
14544 }
14545
14546 let last_index = new_idx;
14547 let mut run_ranges_errors = Vec::new();
14548 label.runs.retain_mut(|(range, _)| {
14549 match offset_map.get(range.start) {
14550 Some(&start) => range.start = start,
14551 None => {
14552 run_ranges_errors.push(range.clone());
14553 return false;
14554 }
14555 }
14556
14557 match offset_map.get(range.end) {
14558 Some(&end) => range.end = end,
14559 None => {
14560 run_ranges_errors.push(range.clone());
14561 range.end = last_index;
14562 }
14563 }
14564 true
14565 });
14566 if !run_ranges_errors.is_empty() {
14567 log::error!(
14568 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14569 label.text
14570 );
14571 }
14572
14573 let mut wrong_filter_range = None;
14574 if label.filter_range == (0..label.text.len()) {
14575 label.filter_range = 0..new_text.len();
14576 } else {
14577 let mut original_filter_range = Some(label.filter_range.clone());
14578 match offset_map.get(label.filter_range.start) {
14579 Some(&start) => label.filter_range.start = start,
14580 None => {
14581 wrong_filter_range = original_filter_range.take();
14582 label.filter_range.start = last_index;
14583 }
14584 }
14585
14586 match offset_map.get(label.filter_range.end) {
14587 Some(&end) => label.filter_range.end = end,
14588 None => {
14589 wrong_filter_range = original_filter_range.take();
14590 label.filter_range.end = last_index;
14591 }
14592 }
14593 }
14594 if let Some(wrong_filter_range) = wrong_filter_range {
14595 log::error!(
14596 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14597 label.text
14598 );
14599 }
14600
14601 label.text = new_text;
14602}
14603
14604/// Apply edits to the buffer that will become part of the formatting transaction.
14605/// Fails if the buffer has been edited since the start of that transaction.
14606fn extend_formatting_transaction(
14607 buffer: &FormattableBuffer,
14608 formatting_transaction_id: text::TransactionId,
14609 cx: &mut AsyncApp,
14610 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14611) -> anyhow::Result<()> {
14612 buffer.handle.update(cx, |buffer, cx| {
14613 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14614 if last_transaction_id != Some(formatting_transaction_id) {
14615 anyhow::bail!("Buffer edited while formatting. Aborting")
14616 }
14617 buffer.start_transaction();
14618 operation(buffer, cx);
14619 if let Some(transaction_id) = buffer.end_transaction(cx) {
14620 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14621 }
14622 Ok(())
14623 })
14624}