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