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 folding_ranges;
16mod inlay_hints;
17pub mod json_language_server_ext;
18pub mod log_store;
19pub mod lsp_ext_command;
20pub mod rust_analyzer_ext;
21mod semantic_tokens;
22pub mod vue_language_server_ext;
23
24use self::code_lens::CodeLensData;
25use self::document_colors::DocumentColorData;
26use self::inlay_hints::BufferInlayHints;
27use crate::{
28 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
29 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
30 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
31 PulledDiagnostics, ResolveState, Symbol,
32 buffer_store::{BufferStore, BufferStoreEvent},
33 environment::ProjectEnvironment,
34 lsp_command::{self, *},
35 lsp_store::{
36 self,
37 folding_ranges::FoldingRangeData,
38 log_store::{GlobalLogStore, LanguageServerKind},
39 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
40 },
41 manifest_tree::{
42 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
43 ManifestTree,
44 },
45 prettier_store::{self, PrettierStore, PrettierStoreEvent},
46 project_settings::{BinarySettings, LspSettings, ProjectSettings},
47 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
48 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
49 worktree_store::{WorktreeStore, WorktreeStoreEvent},
50 yarn::YarnPathStore,
51};
52use anyhow::{Context as _, Result, anyhow};
53use async_trait::async_trait;
54use client::{TypedEnvelope, proto};
55use clock::Global;
56use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
57use futures::{
58 AsyncWriteExt, Future, FutureExt, StreamExt,
59 future::{Either, Shared, join_all, pending, select},
60 select, select_biased,
61 stream::FuturesUnordered,
62};
63use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
64use gpui::{
65 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
66 Subscription, Task, WeakEntity,
67};
68use http_client::HttpClient;
69use itertools::Itertools as _;
70use language::{
71 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
72 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
73 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
74 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
75 Toolchain, Transaction, Unclipped,
76 language_settings::{
77 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
78 language_settings,
79 },
80 point_to_lsp,
81 proto::{
82 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
83 serialize_anchor_range, serialize_version,
84 },
85 range_from_lsp, range_to_lsp,
86 row_chunk::RowChunk,
87};
88use lsp::{
89 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
90 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
91 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
92 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
93 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
94 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
95 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
96 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
97};
98use node_runtime::read_package_installed_version;
99use parking_lot::Mutex;
100use postage::{mpsc, sink::Sink, stream::Stream, watch};
101use rand::prelude::*;
102use rpc::{
103 AnyProtoClient, ErrorCode, ErrorExt as _,
104 proto::{LspRequestId, LspRequestMessage as _},
105};
106use semver::Version;
107use serde::Serialize;
108use serde_json::Value;
109use settings::{Settings, SettingsLocation, SettingsStore};
110use sha2::{Digest, Sha256};
111use snippet::Snippet;
112use std::{
113 any::TypeId,
114 borrow::Cow,
115 cell::RefCell,
116 cmp::{Ordering, Reverse},
117 collections::{VecDeque, hash_map},
118 convert::TryInto,
119 ffi::OsStr,
120 future::ready,
121 iter, mem,
122 ops::{ControlFlow, Range},
123 path::{self, Path, PathBuf},
124 pin::pin,
125 rc::Rc,
126 sync::{
127 Arc,
128 atomic::{self, AtomicUsize},
129 },
130 time::{Duration, Instant},
131 vec,
132};
133use sum_tree::Dimensions;
134use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
135
136use util::{
137 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
138 paths::{PathStyle, SanitizedPath, UrlExt},
139 post_inc,
140 redact::redact_command,
141 rel_path::RelPath,
142};
143
144pub use document_colors::DocumentColors;
145pub use folding_ranges::LspFoldingRange;
146pub use fs::*;
147pub use language::Location;
148pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
149#[cfg(any(test, feature = "test-support"))]
150pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
151pub use semantic_tokens::{
152 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
153};
154
155pub use worktree::{
156 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
157 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
158};
159
160const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
161pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
162const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
163const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
164static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
165
166#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
167pub enum ProgressToken {
168 Number(i32),
169 String(SharedString),
170}
171
172impl std::fmt::Display for ProgressToken {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 match self {
175 Self::Number(number) => write!(f, "{number}"),
176 Self::String(string) => write!(f, "{string}"),
177 }
178 }
179}
180
181impl ProgressToken {
182 fn from_lsp(value: lsp::NumberOrString) -> Self {
183 match value {
184 lsp::NumberOrString::Number(number) => Self::Number(number),
185 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
186 }
187 }
188
189 fn to_lsp(&self) -> lsp::NumberOrString {
190 match self {
191 Self::Number(number) => lsp::NumberOrString::Number(*number),
192 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
193 }
194 }
195
196 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
197 Some(match value.value? {
198 proto::progress_token::Value::Number(number) => Self::Number(number),
199 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
200 })
201 }
202
203 fn to_proto(&self) -> proto::ProgressToken {
204 proto::ProgressToken {
205 value: Some(match self {
206 Self::Number(number) => proto::progress_token::Value::Number(*number),
207 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
208 }),
209 }
210 }
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq)]
214pub enum FormatTrigger {
215 Save,
216 Manual,
217}
218
219pub enum LspFormatTarget {
220 Buffers,
221 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
225pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
226
227struct OpenLspBuffer(Entity<Buffer>);
228
229impl FormatTrigger {
230 fn from_proto(value: i32) -> FormatTrigger {
231 match value {
232 0 => FormatTrigger::Save,
233 1 => FormatTrigger::Manual,
234 _ => FormatTrigger::Save,
235 }
236 }
237}
238
239#[derive(Clone)]
240struct UnifiedLanguageServer {
241 id: LanguageServerId,
242 project_roots: HashSet<Arc<RelPath>>,
243}
244
245/// Settings that affect language server identity.
246///
247/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
248/// updated via `workspace/didChangeConfiguration` without restarting the server.
249#[derive(Clone, Debug, Hash, PartialEq, Eq)]
250struct LanguageServerSeedSettings {
251 binary: Option<BinarySettings>,
252 initialization_options: Option<serde_json::Value>,
253}
254
255#[derive(Clone, Debug, Hash, PartialEq, Eq)]
256struct LanguageServerSeed {
257 worktree_id: WorktreeId,
258 name: LanguageServerName,
259 toolchain: Option<Toolchain>,
260 settings: LanguageServerSeedSettings,
261}
262
263#[derive(Debug)]
264pub struct DocumentDiagnosticsUpdate<'a, D> {
265 pub diagnostics: D,
266 pub result_id: Option<SharedString>,
267 pub registration_id: Option<SharedString>,
268 pub server_id: LanguageServerId,
269 pub disk_based_sources: Cow<'a, [String]>,
270}
271
272pub struct DocumentDiagnostics {
273 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
274 document_abs_path: PathBuf,
275 version: Option<i32>,
276}
277
278#[derive(Default, Debug)]
279struct DynamicRegistrations {
280 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
281 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
282}
283
284pub struct LocalLspStore {
285 weak: WeakEntity<LspStore>,
286 pub worktree_store: Entity<WorktreeStore>,
287 toolchain_store: Entity<LocalToolchainStore>,
288 http_client: Arc<dyn HttpClient>,
289 environment: Entity<ProjectEnvironment>,
290 fs: Arc<dyn Fs>,
291 languages: Arc<LanguageRegistry>,
292 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
293 yarn: Entity<YarnPathStore>,
294 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
295 buffers_being_formatted: HashSet<BufferId>,
296 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
297 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
298 watched_manifest_filenames: HashSet<ManifestName>,
299 language_server_paths_watched_for_rename:
300 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
301 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
302 supplementary_language_servers:
303 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
304 prettier_store: Entity<PrettierStore>,
305 next_diagnostic_group_id: usize,
306 diagnostics: HashMap<
307 WorktreeId,
308 HashMap<
309 Arc<RelPath>,
310 Vec<(
311 LanguageServerId,
312 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
313 )>,
314 >,
315 >,
316 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
317 _subscription: gpui::Subscription,
318 lsp_tree: LanguageServerTree,
319 registered_buffers: HashMap<BufferId, usize>,
320 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
321 buffer_pull_diagnostics_result_ids: HashMap<
322 LanguageServerId,
323 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
324 >,
325 workspace_pull_diagnostics_result_ids: HashMap<
326 LanguageServerId,
327 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
328 >,
329 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
330
331 buffers_to_refresh_hash_set: HashSet<BufferId>,
332 buffers_to_refresh_queue: VecDeque<BufferId>,
333 _background_diagnostics_worker: Shared<Task<()>>,
334}
335
336impl LocalLspStore {
337 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
338 pub fn running_language_server_for_id(
339 &self,
340 id: LanguageServerId,
341 ) -> Option<&Arc<LanguageServer>> {
342 let language_server_state = self.language_servers.get(&id)?;
343
344 match language_server_state {
345 LanguageServerState::Running { server, .. } => Some(server),
346 LanguageServerState::Starting { .. } => None,
347 }
348 }
349
350 fn get_or_insert_language_server(
351 &mut self,
352 worktree_handle: &Entity<Worktree>,
353 delegate: Arc<LocalLspAdapterDelegate>,
354 disposition: &Arc<LaunchDisposition>,
355 language_name: &LanguageName,
356 cx: &mut App,
357 ) -> LanguageServerId {
358 let key = LanguageServerSeed {
359 worktree_id: worktree_handle.read(cx).id(),
360 name: disposition.server_name.clone(),
361 settings: LanguageServerSeedSettings {
362 binary: disposition.settings.binary.clone(),
363 initialization_options: disposition.settings.initialization_options.clone(),
364 },
365 toolchain: disposition.toolchain.clone(),
366 };
367 if let Some(state) = self.language_server_ids.get_mut(&key) {
368 state.project_roots.insert(disposition.path.path.clone());
369 state.id
370 } else {
371 let adapter = self
372 .languages
373 .lsp_adapters(language_name)
374 .into_iter()
375 .find(|adapter| adapter.name() == disposition.server_name)
376 .expect("To find LSP adapter");
377 let new_language_server_id = self.start_language_server(
378 worktree_handle,
379 delegate,
380 adapter,
381 disposition.settings.clone(),
382 key.clone(),
383 language_name.clone(),
384 cx,
385 );
386 if let Some(state) = self.language_server_ids.get_mut(&key) {
387 state.project_roots.insert(disposition.path.path.clone());
388 } else {
389 debug_assert!(
390 false,
391 "Expected `start_language_server` to ensure that `key` exists in a map"
392 );
393 }
394 new_language_server_id
395 }
396 }
397
398 fn start_language_server(
399 &mut self,
400 worktree_handle: &Entity<Worktree>,
401 delegate: Arc<LocalLspAdapterDelegate>,
402 adapter: Arc<CachedLspAdapter>,
403 settings: Arc<LspSettings>,
404 key: LanguageServerSeed,
405 language_name: LanguageName,
406 cx: &mut App,
407 ) -> LanguageServerId {
408 let worktree = worktree_handle.read(cx);
409
410 let worktree_id = worktree.id();
411 let worktree_abs_path = worktree.abs_path();
412 let toolchain = key.toolchain.clone();
413 let override_options = settings.initialization_options.clone();
414
415 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
416
417 let server_id = self.languages.next_language_server_id();
418 log::trace!(
419 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
420 adapter.name.0
421 );
422
423 let wait_until_worktree_trust =
424 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
425 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
426 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
427 });
428 if can_trust {
429 self.restricted_worktrees_tasks.remove(&worktree_id);
430 None
431 } else {
432 match self.restricted_worktrees_tasks.entry(worktree_id) {
433 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
434 hash_map::Entry::Vacant(v) => {
435 let (mut tx, rx) = watch::channel::<bool>();
436 let lsp_store = self.weak.clone();
437 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
438 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
439 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
440 tx.blocking_send(true).ok();
441 lsp_store
442 .update(cx, |lsp_store, _| {
443 if let Some(local_lsp_store) =
444 lsp_store.as_local_mut()
445 {
446 local_lsp_store
447 .restricted_worktrees_tasks
448 .remove(&worktree_id);
449 }
450 })
451 .ok();
452 }
453 }
454 });
455 v.insert((subscription, rx.clone()));
456 Some(rx)
457 }
458 }
459 }
460 });
461 let update_binary_status = wait_until_worktree_trust.is_none();
462
463 let binary = self.get_language_server_binary(
464 worktree_abs_path.clone(),
465 adapter.clone(),
466 settings,
467 toolchain.clone(),
468 delegate.clone(),
469 true,
470 wait_until_worktree_trust,
471 cx,
472 );
473 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
474
475 let pending_server = cx.spawn({
476 let adapter = adapter.clone();
477 let server_name = adapter.name.clone();
478 let stderr_capture = stderr_capture.clone();
479 #[cfg(any(test, feature = "test-support"))]
480 let lsp_store = self.weak.clone();
481 let pending_workspace_folders = pending_workspace_folders.clone();
482 async move |cx| {
483 let binary = binary.await?;
484 #[cfg(any(test, feature = "test-support"))]
485 if let Some(server) = lsp_store
486 .update(&mut cx.clone(), |this, cx| {
487 this.languages.create_fake_language_server(
488 server_id,
489 &server_name,
490 binary.clone(),
491 &mut cx.to_async(),
492 )
493 })
494 .ok()
495 .flatten()
496 {
497 return Ok(server);
498 }
499
500 let code_action_kinds = adapter.code_action_kinds();
501 lsp::LanguageServer::new(
502 stderr_capture,
503 server_id,
504 server_name,
505 binary,
506 &worktree_abs_path,
507 code_action_kinds,
508 Some(pending_workspace_folders),
509 cx,
510 )
511 }
512 });
513
514 let startup = {
515 let server_name = adapter.name.0.clone();
516 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
517 let key = key.clone();
518 let adapter = adapter.clone();
519 let lsp_store = self.weak.clone();
520 let pending_workspace_folders = pending_workspace_folders.clone();
521 let pull_diagnostics = ProjectSettings::get_global(cx)
522 .diagnostics
523 .lsp_pull_diagnostics
524 .enabled;
525 let settings_location = SettingsLocation {
526 worktree_id,
527 path: RelPath::empty(),
528 };
529 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
530 .language(Some(settings_location), Some(&language_name), cx)
531 .semantic_tokens
532 .use_tree_sitter();
533 cx.spawn(async move |cx| {
534 let result = async {
535 let language_server = pending_server.await?;
536
537 let workspace_config = Self::workspace_configuration_for_adapter(
538 adapter.adapter.clone(),
539 &delegate,
540 toolchain,
541 None,
542 cx,
543 )
544 .await?;
545
546 let mut initialization_options = Self::initialization_options_for_adapter(
547 adapter.adapter.clone(),
548 &delegate,
549 )
550 .await?;
551
552 match (&mut initialization_options, override_options) {
553 (Some(initialization_options), Some(override_options)) => {
554 merge_json_value_into(override_options, initialization_options);
555 }
556 (None, override_options) => initialization_options = override_options,
557 _ => {}
558 }
559
560 let initialization_params = cx.update(|cx| {
561 let mut params = language_server.default_initialize_params(
562 pull_diagnostics,
563 augments_syntax_tokens,
564 cx,
565 );
566 params.initialization_options = initialization_options;
567 adapter.adapter.prepare_initialize_params(params, cx)
568 })?;
569
570 Self::setup_lsp_messages(
571 lsp_store.clone(),
572 &language_server,
573 delegate.clone(),
574 adapter.clone(),
575 );
576
577 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
578 settings: workspace_config,
579 };
580 let language_server = cx
581 .update(|cx| {
582 let request_timeout = ProjectSettings::get_global(cx)
583 .global_lsp_settings
584 .get_request_timeout();
585
586 language_server.initialize(
587 initialization_params,
588 Arc::new(did_change_configuration_params.clone()),
589 request_timeout,
590 cx,
591 )
592 })
593 .await
594 .inspect_err(|_| {
595 if let Some(lsp_store) = lsp_store.upgrade() {
596 lsp_store.update(cx, |lsp_store, cx| {
597 lsp_store.cleanup_lsp_data(server_id);
598 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
599 });
600 }
601 })?;
602
603 language_server.notify::<lsp::notification::DidChangeConfiguration>(
604 did_change_configuration_params,
605 )?;
606
607 anyhow::Ok(language_server)
608 }
609 .await;
610
611 match result {
612 Ok(server) => {
613 lsp_store
614 .update(cx, |lsp_store, cx| {
615 lsp_store.insert_newly_running_language_server(
616 adapter,
617 server.clone(),
618 server_id,
619 key,
620 pending_workspace_folders,
621 cx,
622 );
623 })
624 .ok();
625 stderr_capture.lock().take();
626 Some(server)
627 }
628
629 Err(err) => {
630 let log = stderr_capture.lock().take().unwrap_or_default();
631 delegate.update_status(
632 adapter.name(),
633 BinaryStatus::Failed {
634 error: if log.is_empty() {
635 format!("{err:#}")
636 } else {
637 format!("{err:#}\n-- stderr --\n{log}")
638 },
639 },
640 );
641 log::error!(
642 "Failed to start language server {server_name:?}: {}",
643 redact_command(&format!("{err:?}"))
644 );
645 if !log.is_empty() {
646 log::error!("server stderr: {}", redact_command(&log));
647 }
648 None
649 }
650 }
651 })
652 };
653 let state = LanguageServerState::Starting {
654 startup,
655 pending_workspace_folders,
656 };
657
658 if update_binary_status {
659 self.languages
660 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
661 }
662
663 self.language_servers.insert(server_id, state);
664 self.language_server_ids
665 .entry(key)
666 .or_insert(UnifiedLanguageServer {
667 id: server_id,
668 project_roots: Default::default(),
669 });
670 server_id
671 }
672
673 fn get_language_server_binary(
674 &self,
675 worktree_abs_path: Arc<Path>,
676 adapter: Arc<CachedLspAdapter>,
677 settings: Arc<LspSettings>,
678 toolchain: Option<Toolchain>,
679 delegate: Arc<dyn LspAdapterDelegate>,
680 allow_binary_download: bool,
681 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
682 cx: &mut App,
683 ) -> Task<Result<LanguageServerBinary>> {
684 if let Some(settings) = &settings.binary
685 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
686 {
687 let settings = settings.clone();
688 let languages = self.languages.clone();
689 return cx.background_spawn(async move {
690 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
691 let already_trusted = *wait_until_worktree_trust.borrow();
692 if !already_trusted {
693 log::info!(
694 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
695 adapter.name(),
696 );
697 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
698 if worktree_trusted {
699 break;
700 }
701 }
702 log::info!(
703 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
704 adapter.name(),
705 );
706 }
707 languages
708 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
709 }
710 let mut env = delegate.shell_env().await;
711 env.extend(settings.env.unwrap_or_default());
712
713 Ok(LanguageServerBinary {
714 path: delegate.resolve_executable_path(path),
715 env: Some(env),
716 arguments: settings
717 .arguments
718 .unwrap_or_default()
719 .iter()
720 .map(Into::into)
721 .collect(),
722 })
723 });
724 }
725 let lsp_binary_options = LanguageServerBinaryOptions {
726 allow_path_lookup: !settings
727 .binary
728 .as_ref()
729 .and_then(|b| b.ignore_system_version)
730 .unwrap_or_default(),
731 allow_binary_download,
732 pre_release: settings
733 .fetch
734 .as_ref()
735 .and_then(|f| f.pre_release)
736 .unwrap_or(false),
737 };
738
739 cx.spawn(async move |cx| {
740 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
741 let already_trusted = *wait_until_worktree_trust.borrow();
742 if !already_trusted {
743 log::info!(
744 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
745 adapter.name(),
746 );
747 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
748 if worktree_trusted {
749 break;
750 }
751 }
752 log::info!(
753 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
754 adapter.name(),
755 );
756 }
757 }
758
759 let (existing_binary, maybe_download_binary) = adapter
760 .clone()
761 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
762 .await
763 .await;
764
765 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
766
767 let mut binary = match (existing_binary, maybe_download_binary) {
768 (binary, None) => binary?,
769 (Err(_), Some(downloader)) => downloader.await?,
770 (Ok(existing_binary), Some(downloader)) => {
771 let mut download_timeout = cx
772 .background_executor()
773 .timer(SERVER_DOWNLOAD_TIMEOUT)
774 .fuse();
775 let mut downloader = downloader.fuse();
776 futures::select! {
777 _ = download_timeout => {
778 // Return existing binary and kick the existing work to the background.
779 cx.spawn(async move |_| downloader.await).detach();
780 Ok(existing_binary)
781 },
782 downloaded_or_existing_binary = downloader => {
783 // If download fails, this results in the existing binary.
784 downloaded_or_existing_binary
785 }
786 }?
787 }
788 };
789 let mut shell_env = delegate.shell_env().await;
790
791 shell_env.extend(binary.env.unwrap_or_default());
792
793 if let Some(settings) = settings.binary.as_ref() {
794 if let Some(arguments) = &settings.arguments {
795 binary.arguments = arguments.iter().map(Into::into).collect();
796 }
797 if let Some(env) = &settings.env {
798 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
799 }
800 }
801
802 binary.env = Some(shell_env);
803 Ok(binary)
804 })
805 }
806
807 fn setup_lsp_messages(
808 lsp_store: WeakEntity<LspStore>,
809 language_server: &LanguageServer,
810 delegate: Arc<dyn LspAdapterDelegate>,
811 adapter: Arc<CachedLspAdapter>,
812 ) {
813 let name = language_server.name();
814 let server_id = language_server.server_id();
815 language_server
816 .on_notification::<lsp::notification::PublishDiagnostics, _>({
817 let adapter = adapter.clone();
818 let this = lsp_store.clone();
819 move |mut params, cx| {
820 let adapter = adapter.clone();
821 if let Some(this) = this.upgrade() {
822 this.update(cx, |this, cx| {
823 {
824 let buffer = params
825 .uri
826 .to_file_path()
827 .map(|file_path| this.get_buffer(&file_path, cx))
828 .ok()
829 .flatten();
830 adapter.process_diagnostics(&mut params, server_id, buffer);
831 }
832
833 this.merge_lsp_diagnostics(
834 DiagnosticSourceKind::Pushed,
835 vec![DocumentDiagnosticsUpdate {
836 server_id,
837 diagnostics: params,
838 result_id: None,
839 disk_based_sources: Cow::Borrowed(
840 &adapter.disk_based_diagnostic_sources,
841 ),
842 registration_id: None,
843 }],
844 |_, diagnostic, cx| match diagnostic.source_kind {
845 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
846 adapter.retain_old_diagnostic(diagnostic, cx)
847 }
848 DiagnosticSourceKind::Pulled => true,
849 },
850 cx,
851 )
852 .log_err();
853 });
854 }
855 }
856 })
857 .detach();
858 language_server
859 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
860 let adapter = adapter.adapter.clone();
861 let delegate = delegate.clone();
862 let this = lsp_store.clone();
863 move |params, cx| {
864 let adapter = adapter.clone();
865 let delegate = delegate.clone();
866 let this = this.clone();
867 let mut cx = cx.clone();
868 async move {
869 let toolchain_for_id = this
870 .update(&mut cx, |this, _| {
871 this.as_local()?.language_server_ids.iter().find_map(
872 |(seed, value)| {
873 (value.id == server_id).then(|| seed.toolchain.clone())
874 },
875 )
876 })?
877 .context("Expected the LSP store to be in a local mode")?;
878
879 let mut scope_uri_to_workspace_config = BTreeMap::new();
880 for item in ¶ms.items {
881 let scope_uri = item.scope_uri.clone();
882 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
883 scope_uri_to_workspace_config.entry(scope_uri.clone())
884 else {
885 // We've already queried workspace configuration of this URI.
886 continue;
887 };
888 let workspace_config = Self::workspace_configuration_for_adapter(
889 adapter.clone(),
890 &delegate,
891 toolchain_for_id.clone(),
892 scope_uri,
893 &mut cx,
894 )
895 .await?;
896 new_scope_uri.insert(workspace_config);
897 }
898
899 Ok(params
900 .items
901 .into_iter()
902 .filter_map(|item| {
903 let workspace_config =
904 scope_uri_to_workspace_config.get(&item.scope_uri)?;
905 if let Some(section) = &item.section {
906 Some(
907 workspace_config
908 .get(section)
909 .cloned()
910 .unwrap_or(serde_json::Value::Null),
911 )
912 } else {
913 Some(workspace_config.clone())
914 }
915 })
916 .collect())
917 }
918 }
919 })
920 .detach();
921
922 language_server
923 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
924 let this = lsp_store.clone();
925 move |_, cx| {
926 let this = this.clone();
927 let cx = cx.clone();
928 async move {
929 let Some(server) =
930 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
931 else {
932 return Ok(None);
933 };
934 let root = server.workspace_folders();
935 Ok(Some(
936 root.into_iter()
937 .map(|uri| WorkspaceFolder {
938 uri,
939 name: Default::default(),
940 })
941 .collect(),
942 ))
943 }
944 }
945 })
946 .detach();
947 // Even though we don't have handling for these requests, respond to them to
948 // avoid stalling any language server like `gopls` which waits for a response
949 // to these requests when initializing.
950 language_server
951 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
952 let this = lsp_store.clone();
953 move |params, cx| {
954 let this = this.clone();
955 let mut cx = cx.clone();
956 async move {
957 this.update(&mut cx, |this, _| {
958 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
959 {
960 status
961 .progress_tokens
962 .insert(ProgressToken::from_lsp(params.token));
963 }
964 })?;
965
966 Ok(())
967 }
968 }
969 })
970 .detach();
971
972 language_server
973 .on_request::<lsp::request::RegisterCapability, _, _>({
974 let lsp_store = lsp_store.clone();
975 move |params, cx| {
976 let lsp_store = lsp_store.clone();
977 let mut cx = cx.clone();
978 async move {
979 lsp_store
980 .update(&mut cx, |lsp_store, cx| {
981 if lsp_store.as_local().is_some() {
982 match lsp_store
983 .register_server_capabilities(server_id, params, cx)
984 {
985 Ok(()) => {}
986 Err(e) => {
987 log::error!(
988 "Failed to register server capabilities: {e:#}"
989 );
990 }
991 };
992 }
993 })
994 .ok();
995 Ok(())
996 }
997 }
998 })
999 .detach();
1000
1001 language_server
1002 .on_request::<lsp::request::UnregisterCapability, _, _>({
1003 let lsp_store = lsp_store.clone();
1004 move |params, cx| {
1005 let lsp_store = lsp_store.clone();
1006 let mut cx = cx.clone();
1007 async move {
1008 lsp_store
1009 .update(&mut cx, |lsp_store, cx| {
1010 if lsp_store.as_local().is_some() {
1011 match lsp_store
1012 .unregister_server_capabilities(server_id, params, cx)
1013 {
1014 Ok(()) => {}
1015 Err(e) => {
1016 log::error!(
1017 "Failed to unregister server capabilities: {e:#}"
1018 );
1019 }
1020 }
1021 }
1022 })
1023 .ok();
1024 Ok(())
1025 }
1026 }
1027 })
1028 .detach();
1029
1030 language_server
1031 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1032 let this = lsp_store.clone();
1033 move |params, cx| {
1034 let mut cx = cx.clone();
1035 let this = this.clone();
1036 async move {
1037 LocalLspStore::on_lsp_workspace_edit(
1038 this.clone(),
1039 params,
1040 server_id,
1041 &mut cx,
1042 )
1043 .await
1044 }
1045 }
1046 })
1047 .detach();
1048
1049 language_server
1050 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1051 let lsp_store = lsp_store.clone();
1052 let request_id = Arc::new(AtomicUsize::new(0));
1053 move |(), cx| {
1054 let lsp_store = lsp_store.clone();
1055 let request_id = request_id.clone();
1056 let mut cx = cx.clone();
1057 async move {
1058 lsp_store
1059 .update(&mut cx, |lsp_store, cx| {
1060 let request_id =
1061 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1062 cx.emit(LspStoreEvent::RefreshInlayHints {
1063 server_id,
1064 request_id,
1065 });
1066 lsp_store
1067 .downstream_client
1068 .as_ref()
1069 .map(|(client, project_id)| {
1070 client.send(proto::RefreshInlayHints {
1071 project_id: *project_id,
1072 server_id: server_id.to_proto(),
1073 request_id: request_id.map(|id| id as u64),
1074 })
1075 })
1076 })?
1077 .transpose()?;
1078 Ok(())
1079 }
1080 }
1081 })
1082 .detach();
1083
1084 language_server
1085 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1086 let this = lsp_store.clone();
1087 move |(), cx| {
1088 let this = this.clone();
1089 let mut cx = cx.clone();
1090 async move {
1091 this.update(&mut cx, |this, cx| {
1092 cx.emit(LspStoreEvent::RefreshCodeLens);
1093 this.downstream_client.as_ref().map(|(client, project_id)| {
1094 client.send(proto::RefreshCodeLens {
1095 project_id: *project_id,
1096 })
1097 })
1098 })?
1099 .transpose()?;
1100 Ok(())
1101 }
1102 }
1103 })
1104 .detach();
1105
1106 language_server
1107 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1108 let lsp_store = lsp_store.clone();
1109 let request_id = Arc::new(AtomicUsize::new(0));
1110 move |(), cx| {
1111 let lsp_store = lsp_store.clone();
1112 let request_id = request_id.clone();
1113 let mut cx = cx.clone();
1114 async move {
1115 lsp_store
1116 .update(&mut cx, |lsp_store, cx| {
1117 let request_id =
1118 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1119 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1120 server_id,
1121 request_id,
1122 });
1123 lsp_store
1124 .downstream_client
1125 .as_ref()
1126 .map(|(client, project_id)| {
1127 client.send(proto::RefreshSemanticTokens {
1128 project_id: *project_id,
1129 server_id: server_id.to_proto(),
1130 request_id: request_id.map(|id| id as u64),
1131 })
1132 })
1133 })?
1134 .transpose()?;
1135 Ok(())
1136 }
1137 }
1138 })
1139 .detach();
1140
1141 language_server
1142 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1143 let this = lsp_store.clone();
1144 move |(), cx| {
1145 let this = this.clone();
1146 let mut cx = cx.clone();
1147 async move {
1148 this.update(&mut cx, |lsp_store, cx| {
1149 lsp_store.pull_workspace_diagnostics(server_id);
1150 lsp_store
1151 .downstream_client
1152 .as_ref()
1153 .map(|(client, project_id)| {
1154 client.send(proto::PullWorkspaceDiagnostics {
1155 project_id: *project_id,
1156 server_id: server_id.to_proto(),
1157 })
1158 })
1159 .transpose()?;
1160 anyhow::Ok(
1161 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1162 )
1163 })??
1164 .await;
1165 Ok(())
1166 }
1167 }
1168 })
1169 .detach();
1170
1171 language_server
1172 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1173 let this = lsp_store.clone();
1174 let name = name.to_string();
1175 let adapter = adapter.clone();
1176 move |params, cx| {
1177 let this = this.clone();
1178 let name = name.to_string();
1179 let adapter = adapter.clone();
1180 let mut cx = cx.clone();
1181 async move {
1182 let actions = params.actions.unwrap_or_default();
1183 let message = params.message.clone();
1184 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1185 let level = match params.typ {
1186 lsp::MessageType::ERROR => PromptLevel::Critical,
1187 lsp::MessageType::WARNING => PromptLevel::Warning,
1188 _ => PromptLevel::Info,
1189 };
1190 let request = LanguageServerPromptRequest::new(
1191 level,
1192 params.message,
1193 actions,
1194 name.clone(),
1195 tx,
1196 );
1197
1198 let did_update = this
1199 .update(&mut cx, |_, cx| {
1200 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1201 })
1202 .is_ok();
1203 if did_update {
1204 let response = rx.recv().await.ok();
1205 if let Some(ref selected_action) = response {
1206 let context = language::PromptResponseContext {
1207 message,
1208 selected_action: selected_action.clone(),
1209 };
1210 adapter.process_prompt_response(&context, &mut cx)
1211 }
1212
1213 Ok(response)
1214 } else {
1215 Ok(None)
1216 }
1217 }
1218 }
1219 })
1220 .detach();
1221 language_server
1222 .on_notification::<lsp::notification::ShowMessage, _>({
1223 let this = lsp_store.clone();
1224 let name = name.to_string();
1225 move |params, cx| {
1226 let this = this.clone();
1227 let name = name.to_string();
1228 let mut cx = cx.clone();
1229
1230 let (tx, _) = smol::channel::bounded(1);
1231 let level = match params.typ {
1232 lsp::MessageType::ERROR => PromptLevel::Critical,
1233 lsp::MessageType::WARNING => PromptLevel::Warning,
1234 _ => PromptLevel::Info,
1235 };
1236 let request =
1237 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1238
1239 let _ = this.update(&mut cx, |_, cx| {
1240 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1241 });
1242 }
1243 })
1244 .detach();
1245
1246 let disk_based_diagnostics_progress_token =
1247 adapter.disk_based_diagnostics_progress_token.clone();
1248
1249 language_server
1250 .on_notification::<lsp::notification::Progress, _>({
1251 let this = lsp_store.clone();
1252 move |params, cx| {
1253 if let Some(this) = this.upgrade() {
1254 this.update(cx, |this, cx| {
1255 this.on_lsp_progress(
1256 params,
1257 server_id,
1258 disk_based_diagnostics_progress_token.clone(),
1259 cx,
1260 );
1261 });
1262 }
1263 }
1264 })
1265 .detach();
1266
1267 language_server
1268 .on_notification::<lsp::notification::LogMessage, _>({
1269 let this = lsp_store.clone();
1270 move |params, cx| {
1271 if let Some(this) = this.upgrade() {
1272 this.update(cx, |_, cx| {
1273 cx.emit(LspStoreEvent::LanguageServerLog(
1274 server_id,
1275 LanguageServerLogType::Log(params.typ),
1276 params.message,
1277 ));
1278 });
1279 }
1280 }
1281 })
1282 .detach();
1283
1284 language_server
1285 .on_notification::<lsp::notification::LogTrace, _>({
1286 let this = lsp_store.clone();
1287 move |params, cx| {
1288 let mut cx = cx.clone();
1289 if let Some(this) = this.upgrade() {
1290 this.update(&mut cx, |_, cx| {
1291 cx.emit(LspStoreEvent::LanguageServerLog(
1292 server_id,
1293 LanguageServerLogType::Trace {
1294 verbose_info: params.verbose,
1295 },
1296 params.message,
1297 ));
1298 });
1299 }
1300 }
1301 })
1302 .detach();
1303
1304 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1305 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1306 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1307 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1308 }
1309
1310 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1311 let shutdown_futures = self
1312 .language_servers
1313 .drain()
1314 .map(|(_, server_state)| Self::shutdown_server(server_state))
1315 .collect::<Vec<_>>();
1316
1317 async move {
1318 join_all(shutdown_futures).await;
1319 }
1320 }
1321
1322 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1323 match server_state {
1324 LanguageServerState::Running { server, .. } => {
1325 if let Some(shutdown) = server.shutdown() {
1326 shutdown.await;
1327 }
1328 }
1329 LanguageServerState::Starting { startup, .. } => {
1330 if let Some(server) = startup.await
1331 && let Some(shutdown) = server.shutdown()
1332 {
1333 shutdown.await;
1334 }
1335 }
1336 }
1337 Ok(())
1338 }
1339
1340 fn language_servers_for_worktree(
1341 &self,
1342 worktree_id: WorktreeId,
1343 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1344 self.language_server_ids
1345 .iter()
1346 .filter_map(move |(seed, state)| {
1347 if seed.worktree_id != worktree_id {
1348 return None;
1349 }
1350
1351 if let Some(LanguageServerState::Running { server, .. }) =
1352 self.language_servers.get(&state.id)
1353 {
1354 Some(server)
1355 } else {
1356 None
1357 }
1358 })
1359 }
1360
1361 fn language_server_ids_for_project_path(
1362 &self,
1363 project_path: ProjectPath,
1364 language: &Language,
1365 cx: &mut App,
1366 ) -> Vec<LanguageServerId> {
1367 let Some(worktree) = self
1368 .worktree_store
1369 .read(cx)
1370 .worktree_for_id(project_path.worktree_id, cx)
1371 else {
1372 return Vec::new();
1373 };
1374 let delegate: Arc<dyn ManifestDelegate> =
1375 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1376
1377 self.lsp_tree
1378 .get(
1379 project_path,
1380 language.name(),
1381 language.manifest(),
1382 &delegate,
1383 cx,
1384 )
1385 .collect::<Vec<_>>()
1386 }
1387
1388 fn language_server_ids_for_buffer(
1389 &self,
1390 buffer: &Buffer,
1391 cx: &mut App,
1392 ) -> Vec<LanguageServerId> {
1393 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1394 let worktree_id = file.worktree_id(cx);
1395
1396 let path: Arc<RelPath> = file
1397 .path()
1398 .parent()
1399 .map(Arc::from)
1400 .unwrap_or_else(|| file.path().clone());
1401 let worktree_path = ProjectPath { worktree_id, path };
1402 self.language_server_ids_for_project_path(worktree_path, language, cx)
1403 } else {
1404 Vec::new()
1405 }
1406 }
1407
1408 fn language_servers_for_buffer<'a>(
1409 &'a self,
1410 buffer: &'a Buffer,
1411 cx: &'a mut App,
1412 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1413 self.language_server_ids_for_buffer(buffer, cx)
1414 .into_iter()
1415 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1416 LanguageServerState::Running {
1417 adapter, server, ..
1418 } => Some((adapter, server)),
1419 _ => None,
1420 })
1421 }
1422
1423 async fn execute_code_action_kind_locally(
1424 lsp_store: WeakEntity<LspStore>,
1425 mut buffers: Vec<Entity<Buffer>>,
1426 kind: CodeActionKind,
1427 push_to_history: bool,
1428 cx: &mut AsyncApp,
1429 ) -> anyhow::Result<ProjectTransaction> {
1430 // Do not allow multiple concurrent code actions requests for the
1431 // same buffer.
1432 lsp_store.update(cx, |this, cx| {
1433 let this = this.as_local_mut().unwrap();
1434 buffers.retain(|buffer| {
1435 this.buffers_being_formatted
1436 .insert(buffer.read(cx).remote_id())
1437 });
1438 })?;
1439 let _cleanup = defer({
1440 let this = lsp_store.clone();
1441 let mut cx = cx.clone();
1442 let buffers = &buffers;
1443 move || {
1444 this.update(&mut cx, |this, cx| {
1445 let this = this.as_local_mut().unwrap();
1446 for buffer in buffers {
1447 this.buffers_being_formatted
1448 .remove(&buffer.read(cx).remote_id());
1449 }
1450 })
1451 .ok();
1452 }
1453 });
1454 let mut project_transaction = ProjectTransaction::default();
1455
1456 for buffer in &buffers {
1457 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1458 buffer.update(cx, |buffer, cx| {
1459 lsp_store
1460 .as_local()
1461 .unwrap()
1462 .language_servers_for_buffer(buffer, cx)
1463 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1464 .collect::<Vec<_>>()
1465 })
1466 })?;
1467 for (_, language_server) in adapters_and_servers.iter() {
1468 let actions = Self::get_server_code_actions_from_action_kinds(
1469 &lsp_store,
1470 language_server.server_id(),
1471 vec![kind.clone()],
1472 buffer,
1473 cx,
1474 )
1475 .await?;
1476 Self::execute_code_actions_on_server(
1477 &lsp_store,
1478 language_server,
1479 actions,
1480 push_to_history,
1481 &mut project_transaction,
1482 cx,
1483 )
1484 .await?;
1485 }
1486 }
1487 Ok(project_transaction)
1488 }
1489
1490 async fn format_locally(
1491 lsp_store: WeakEntity<LspStore>,
1492 mut buffers: Vec<FormattableBuffer>,
1493 push_to_history: bool,
1494 trigger: FormatTrigger,
1495 logger: zlog::Logger,
1496 cx: &mut AsyncApp,
1497 ) -> anyhow::Result<ProjectTransaction> {
1498 // Do not allow multiple concurrent formatting requests for the
1499 // same buffer.
1500 lsp_store.update(cx, |this, cx| {
1501 let this = this.as_local_mut().unwrap();
1502 buffers.retain(|buffer| {
1503 this.buffers_being_formatted
1504 .insert(buffer.handle.read(cx).remote_id())
1505 });
1506 })?;
1507
1508 let _cleanup = defer({
1509 let this = lsp_store.clone();
1510 let mut cx = cx.clone();
1511 let buffers = &buffers;
1512 move || {
1513 this.update(&mut cx, |this, cx| {
1514 let this = this.as_local_mut().unwrap();
1515 for buffer in buffers {
1516 this.buffers_being_formatted
1517 .remove(&buffer.handle.read(cx).remote_id());
1518 }
1519 })
1520 .ok();
1521 }
1522 });
1523
1524 let mut project_transaction = ProjectTransaction::default();
1525
1526 for buffer in &buffers {
1527 zlog::debug!(
1528 logger =>
1529 "formatting buffer '{:?}'",
1530 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1531 );
1532 // Create an empty transaction to hold all of the formatting edits.
1533 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1534 // ensure no transactions created while formatting are
1535 // grouped with the previous transaction in the history
1536 // based on the transaction group interval
1537 buffer.finalize_last_transaction();
1538 buffer
1539 .start_transaction()
1540 .context("transaction already open")?;
1541 buffer.end_transaction(cx);
1542 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1543 buffer.finalize_last_transaction();
1544 anyhow::Ok(transaction_id)
1545 })?;
1546
1547 let result = Self::format_buffer_locally(
1548 lsp_store.clone(),
1549 buffer,
1550 formatting_transaction_id,
1551 trigger,
1552 logger,
1553 cx,
1554 )
1555 .await;
1556
1557 buffer.handle.update(cx, |buffer, cx| {
1558 let Some(formatting_transaction) =
1559 buffer.get_transaction(formatting_transaction_id).cloned()
1560 else {
1561 zlog::warn!(logger => "no formatting transaction");
1562 return;
1563 };
1564 if formatting_transaction.edit_ids.is_empty() {
1565 zlog::debug!(logger => "no changes made while formatting");
1566 buffer.forget_transaction(formatting_transaction_id);
1567 return;
1568 }
1569 if !push_to_history {
1570 zlog::trace!(logger => "forgetting format transaction");
1571 buffer.forget_transaction(formatting_transaction.id);
1572 }
1573 project_transaction
1574 .0
1575 .insert(cx.entity(), formatting_transaction);
1576 });
1577
1578 result?;
1579 }
1580
1581 Ok(project_transaction)
1582 }
1583
1584 async fn format_buffer_locally(
1585 lsp_store: WeakEntity<LspStore>,
1586 buffer: &FormattableBuffer,
1587 formatting_transaction_id: clock::Lamport,
1588 trigger: FormatTrigger,
1589 logger: zlog::Logger,
1590 cx: &mut AsyncApp,
1591 ) -> Result<()> {
1592 let (adapters_and_servers, settings, request_timeout) =
1593 lsp_store.update(cx, |lsp_store, cx| {
1594 buffer.handle.update(cx, |buffer, cx| {
1595 let adapters_and_servers = lsp_store
1596 .as_local()
1597 .unwrap()
1598 .language_servers_for_buffer(buffer, cx)
1599 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1600 .collect::<Vec<_>>();
1601 let settings =
1602 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1603 .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 => {
1779 adapters_and_servers.first().map(|e| e.1.clone())
1780 }
1781 };
1782
1783 let Some(language_server) = language_server else {
1784 log::debug!(
1785 "No language server found to format buffer '{:?}'. Skipping",
1786 buffer_path_abs.as_path().to_string_lossy()
1787 );
1788 continue;
1789 };
1790
1791 zlog::trace!(
1792 logger =>
1793 "Formatting buffer '{:?}' using language server '{:?}'",
1794 buffer_path_abs.as_path().to_string_lossy(),
1795 language_server.name()
1796 );
1797
1798 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1799 zlog::trace!(logger => "formatting ranges");
1800 Self::format_ranges_via_lsp(
1801 &lsp_store,
1802 &buffer.handle,
1803 ranges,
1804 buffer_path_abs,
1805 &language_server,
1806 &settings,
1807 cx,
1808 )
1809 .await
1810 .context("Failed to format ranges via language server")?
1811 } else {
1812 zlog::trace!(logger => "formatting full");
1813 Self::format_via_lsp(
1814 &lsp_store,
1815 &buffer.handle,
1816 buffer_path_abs,
1817 &language_server,
1818 &settings,
1819 cx,
1820 )
1821 .await
1822 .context("failed to format via language server")?
1823 };
1824
1825 if edits.is_empty() {
1826 zlog::trace!(logger => "No changes");
1827 continue;
1828 }
1829 extend_formatting_transaction(
1830 buffer,
1831 formatting_transaction_id,
1832 cx,
1833 |buffer, cx| {
1834 buffer.edit(edits, None, cx);
1835 },
1836 )?;
1837 }
1838 Formatter::CodeAction(code_action_name) => {
1839 let logger = zlog::scoped!(logger => "code-actions");
1840 zlog::trace!(logger => "formatting");
1841 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1842
1843 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1844 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1845 continue;
1846 };
1847
1848 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1849 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1850
1851 let mut actions_and_servers = Vec::new();
1852
1853 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1854 let actions_result = Self::get_server_code_actions_from_action_kinds(
1855 &lsp_store,
1856 language_server.server_id(),
1857 vec![code_action_kind.clone()],
1858 &buffer.handle,
1859 cx,
1860 )
1861 .await
1862 .with_context(|| {
1863 format!(
1864 "Failed to resolve code action {:?} with language server {}",
1865 code_action_kind,
1866 language_server.name()
1867 )
1868 });
1869 let Ok(actions) = actions_result else {
1870 // note: it may be better to set result to the error and break formatters here
1871 // but for now we try to execute the actions that we can resolve and skip the rest
1872 zlog::error!(
1873 logger =>
1874 "Failed to resolve code action {:?} with language server {}",
1875 code_action_kind,
1876 language_server.name()
1877 );
1878 continue;
1879 };
1880 for action in actions {
1881 actions_and_servers.push((action, index));
1882 }
1883 }
1884
1885 if actions_and_servers.is_empty() {
1886 zlog::warn!(logger => "No code actions were resolved, continuing");
1887 continue;
1888 }
1889
1890 'actions: for (mut action, server_index) in actions_and_servers {
1891 let server = &adapters_and_servers[server_index].1;
1892
1893 let describe_code_action = |action: &CodeAction| {
1894 format!(
1895 "code action '{}' with title \"{}\" on server {}",
1896 action
1897 .lsp_action
1898 .action_kind()
1899 .unwrap_or("unknown".into())
1900 .as_str(),
1901 action.lsp_action.title(),
1902 server.name(),
1903 )
1904 };
1905
1906 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1907
1908 if let Err(err) =
1909 Self::try_resolve_code_action(server, &mut action, request_timeout)
1910 .await
1911 {
1912 zlog::error!(
1913 logger =>
1914 "Failed to resolve {}. Error: {}",
1915 describe_code_action(&action),
1916 err
1917 );
1918 continue;
1919 }
1920
1921 if let Some(edit) = action.lsp_action.edit().cloned() {
1922 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1923 // but filters out and logs warnings for code actions that require unreasonably
1924 // difficult handling on our part, such as:
1925 // - applying edits that call commands
1926 // which can result in arbitrary workspace edits being sent from the server that
1927 // have no way of being tied back to the command that initiated them (i.e. we
1928 // can't know which edits are part of the format request, or if the server is done sending
1929 // actions in response to the command)
1930 // - actions that create/delete/modify/rename files other than the one we are formatting
1931 // as we then would need to handle such changes correctly in the local history as well
1932 // as the remote history through the ProjectTransaction
1933 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1934 // Supporting these actions is not impossible, but not supported as of yet.
1935 if edit.changes.is_none() && edit.document_changes.is_none() {
1936 zlog::trace!(
1937 logger =>
1938 "No changes for code action. Skipping {}",
1939 describe_code_action(&action),
1940 );
1941 continue;
1942 }
1943
1944 let mut operations = Vec::new();
1945 if let Some(document_changes) = edit.document_changes {
1946 match document_changes {
1947 lsp::DocumentChanges::Edits(edits) => operations.extend(
1948 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1949 ),
1950 lsp::DocumentChanges::Operations(ops) => operations = ops,
1951 }
1952 } else if let Some(changes) = edit.changes {
1953 operations.extend(changes.into_iter().map(|(uri, edits)| {
1954 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1955 text_document:
1956 lsp::OptionalVersionedTextDocumentIdentifier {
1957 uri,
1958 version: None,
1959 },
1960 edits: edits.into_iter().map(Edit::Plain).collect(),
1961 })
1962 }));
1963 }
1964
1965 let mut edits = Vec::with_capacity(operations.len());
1966
1967 if operations.is_empty() {
1968 zlog::trace!(
1969 logger =>
1970 "No changes for code action. Skipping {}",
1971 describe_code_action(&action),
1972 );
1973 continue;
1974 }
1975 for operation in operations {
1976 let op = match operation {
1977 lsp::DocumentChangeOperation::Edit(op) => op,
1978 lsp::DocumentChangeOperation::Op(_) => {
1979 zlog::warn!(
1980 logger =>
1981 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1982 describe_code_action(&action),
1983 );
1984 continue 'actions;
1985 }
1986 };
1987 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1988 zlog::warn!(
1989 logger =>
1990 "Failed to convert URI '{:?}' to file path. Skipping {}",
1991 &op.text_document.uri,
1992 describe_code_action(&action),
1993 );
1994 continue 'actions;
1995 };
1996 if &file_path != buffer_path_abs {
1997 zlog::warn!(
1998 logger =>
1999 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2000 file_path,
2001 buffer_path_abs,
2002 describe_code_action(&action),
2003 );
2004 continue 'actions;
2005 }
2006
2007 let mut lsp_edits = Vec::new();
2008 for edit in op.edits {
2009 match edit {
2010 Edit::Plain(edit) => {
2011 if !lsp_edits.contains(&edit) {
2012 lsp_edits.push(edit);
2013 }
2014 }
2015 Edit::Annotated(edit) => {
2016 if !lsp_edits.contains(&edit.text_edit) {
2017 lsp_edits.push(edit.text_edit);
2018 }
2019 }
2020 Edit::Snippet(_) => {
2021 zlog::warn!(
2022 logger =>
2023 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2024 describe_code_action(&action),
2025 );
2026 continue 'actions;
2027 }
2028 }
2029 }
2030 let edits_result = lsp_store
2031 .update(cx, |lsp_store, cx| {
2032 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2033 &buffer.handle,
2034 lsp_edits,
2035 server.server_id(),
2036 op.text_document.version,
2037 cx,
2038 )
2039 })?
2040 .await;
2041 let Ok(resolved_edits) = edits_result else {
2042 zlog::warn!(
2043 logger =>
2044 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2045 buffer_path_abs.as_path(),
2046 describe_code_action(&action),
2047 );
2048 continue 'actions;
2049 };
2050 edits.extend(resolved_edits);
2051 }
2052
2053 if edits.is_empty() {
2054 zlog::warn!(logger => "No edits resolved from LSP");
2055 continue;
2056 }
2057
2058 extend_formatting_transaction(
2059 buffer,
2060 formatting_transaction_id,
2061 cx,
2062 |buffer, cx| {
2063 zlog::info!(
2064 "Applying edits {edits:?}. Content: {:?}",
2065 buffer.text()
2066 );
2067 buffer.edit(edits, None, cx);
2068 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2069 },
2070 )?;
2071 }
2072
2073 // bail early if command is invalid
2074 let Some(command) = action.lsp_action.command() else {
2075 continue;
2076 };
2077
2078 zlog::warn!(
2079 logger =>
2080 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2081 &command.command,
2082 );
2083
2084 let server_capabilities = server.capabilities();
2085 let available_commands = server_capabilities
2086 .execute_command_provider
2087 .as_ref()
2088 .map(|options| options.commands.as_slice())
2089 .unwrap_or_default();
2090 if !available_commands.contains(&command.command) {
2091 zlog::warn!(
2092 logger =>
2093 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2094 command.command,
2095 server.name(),
2096 );
2097 continue;
2098 }
2099
2100 // noop so we just ensure buffer hasn't been edited since resolving code actions
2101 extend_formatting_transaction(
2102 buffer,
2103 formatting_transaction_id,
2104 cx,
2105 |_, _| {},
2106 )?;
2107 zlog::info!(logger => "Executing command {}", &command.command);
2108
2109 lsp_store.update(cx, |this, _| {
2110 this.as_local_mut()
2111 .unwrap()
2112 .last_workspace_edits_by_language_server
2113 .remove(&server.server_id());
2114 })?;
2115
2116 let execute_command_result = server
2117 .request::<lsp::request::ExecuteCommand>(
2118 lsp::ExecuteCommandParams {
2119 command: command.command.clone(),
2120 arguments: command.arguments.clone().unwrap_or_default(),
2121 ..Default::default()
2122 },
2123 request_timeout,
2124 )
2125 .await
2126 .into_response();
2127
2128 if execute_command_result.is_err() {
2129 zlog::error!(
2130 logger =>
2131 "Failed to execute command '{}' as part of {}",
2132 &command.command,
2133 describe_code_action(&action),
2134 );
2135 continue 'actions;
2136 }
2137
2138 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2139 this.as_local_mut()
2140 .unwrap()
2141 .last_workspace_edits_by_language_server
2142 .remove(&server.server_id())
2143 .unwrap_or_default()
2144 })?;
2145
2146 if let Some(transaction) =
2147 project_transaction_command.0.remove(&buffer.handle)
2148 {
2149 zlog::trace!(
2150 logger =>
2151 "Successfully captured {} edits that resulted from command {}",
2152 transaction.edit_ids.len(),
2153 &command.command,
2154 );
2155 let transaction_id_project_transaction = transaction.id;
2156 buffer.handle.update(cx, |buffer, _| {
2157 // it may have been removed from history if push_to_history was
2158 // false in deserialize_workspace_edit. If so push it so we
2159 // can merge it with the format transaction
2160 // and pop the combined transaction off the history stack
2161 // later if push_to_history is false
2162 if buffer.get_transaction(transaction.id).is_none() {
2163 buffer.push_transaction(transaction, Instant::now());
2164 }
2165 buffer.merge_transactions(
2166 transaction_id_project_transaction,
2167 formatting_transaction_id,
2168 );
2169 });
2170 }
2171
2172 if project_transaction_command.0.is_empty() {
2173 continue;
2174 }
2175
2176 let mut extra_buffers = String::new();
2177 for buffer in project_transaction_command.0.keys() {
2178 buffer.read_with(cx, |b, cx| {
2179 let Some(path) = b.project_path(cx) else {
2180 return;
2181 };
2182
2183 if !extra_buffers.is_empty() {
2184 extra_buffers.push_str(", ");
2185 }
2186 extra_buffers.push_str(path.path.as_unix_str());
2187 });
2188 }
2189 zlog::warn!(
2190 logger =>
2191 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2192 &command.command,
2193 extra_buffers,
2194 );
2195 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2196 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2197 // add it so it's included, and merge it into the format transaction when its created later
2198 }
2199 }
2200 }
2201 }
2202
2203 Ok(())
2204 }
2205
2206 pub async fn format_ranges_via_lsp(
2207 this: &WeakEntity<LspStore>,
2208 buffer_handle: &Entity<Buffer>,
2209 ranges: &[Range<Anchor>],
2210 abs_path: &Path,
2211 language_server: &Arc<LanguageServer>,
2212 settings: &LanguageSettings,
2213 cx: &mut AsyncApp,
2214 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2215 let capabilities = &language_server.capabilities();
2216 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2217 if range_formatting_provider == Some(&OneOf::Left(false)) {
2218 anyhow::bail!(
2219 "{} language server does not support range formatting",
2220 language_server.name()
2221 );
2222 }
2223
2224 let uri = file_path_to_lsp_url(abs_path)?;
2225 let text_document = lsp::TextDocumentIdentifier::new(uri);
2226
2227 let request_timeout = cx.update(|app| {
2228 ProjectSettings::get_global(app)
2229 .global_lsp_settings
2230 .get_request_timeout()
2231 });
2232 let lsp_edits = {
2233 let mut lsp_ranges = Vec::new();
2234 this.update(cx, |_this, cx| {
2235 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2236 // not have been sent to the language server. This seems like a fairly systemic
2237 // issue, though, the resolution probably is not specific to formatting.
2238 //
2239 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2240 // LSP.
2241 let snapshot = buffer_handle.read(cx).snapshot();
2242 for range in ranges {
2243 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2244 }
2245 anyhow::Ok(())
2246 })??;
2247
2248 let mut edits = None;
2249 for range in lsp_ranges {
2250 if let Some(mut edit) = language_server
2251 .request::<lsp::request::RangeFormatting>(
2252 lsp::DocumentRangeFormattingParams {
2253 text_document: text_document.clone(),
2254 range,
2255 options: lsp_command::lsp_formatting_options(settings),
2256 work_done_progress_params: Default::default(),
2257 },
2258 request_timeout,
2259 )
2260 .await
2261 .into_response()?
2262 {
2263 edits.get_or_insert_with(Vec::new).append(&mut edit);
2264 }
2265 }
2266 edits
2267 };
2268
2269 if let Some(lsp_edits) = lsp_edits {
2270 this.update(cx, |this, cx| {
2271 this.as_local_mut().unwrap().edits_from_lsp(
2272 buffer_handle,
2273 lsp_edits,
2274 language_server.server_id(),
2275 None,
2276 cx,
2277 )
2278 })?
2279 .await
2280 } else {
2281 Ok(Vec::with_capacity(0))
2282 }
2283 }
2284
2285 async fn format_via_lsp(
2286 this: &WeakEntity<LspStore>,
2287 buffer: &Entity<Buffer>,
2288 abs_path: &Path,
2289 language_server: &Arc<LanguageServer>,
2290 settings: &LanguageSettings,
2291 cx: &mut AsyncApp,
2292 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2293 let logger = zlog::scoped!("lsp_format");
2294 zlog::debug!(logger => "Formatting via LSP");
2295
2296 let uri = file_path_to_lsp_url(abs_path)?;
2297 let text_document = lsp::TextDocumentIdentifier::new(uri);
2298 let capabilities = &language_server.capabilities();
2299
2300 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2301 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2302
2303 let request_timeout = cx.update(|app| {
2304 ProjectSettings::get_global(app)
2305 .global_lsp_settings
2306 .get_request_timeout()
2307 });
2308
2309 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2310 let _timer = zlog::time!(logger => "format-full");
2311 language_server
2312 .request::<lsp::request::Formatting>(
2313 lsp::DocumentFormattingParams {
2314 text_document,
2315 options: lsp_command::lsp_formatting_options(settings),
2316 work_done_progress_params: Default::default(),
2317 },
2318 request_timeout,
2319 )
2320 .await
2321 .into_response()?
2322 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2323 let _timer = zlog::time!(logger => "format-range");
2324 let buffer_start = lsp::Position::new(0, 0);
2325 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2326 language_server
2327 .request::<lsp::request::RangeFormatting>(
2328 lsp::DocumentRangeFormattingParams {
2329 text_document: text_document.clone(),
2330 range: lsp::Range::new(buffer_start, buffer_end),
2331 options: lsp_command::lsp_formatting_options(settings),
2332 work_done_progress_params: Default::default(),
2333 },
2334 request_timeout,
2335 )
2336 .await
2337 .into_response()?
2338 } else {
2339 None
2340 };
2341
2342 if let Some(lsp_edits) = lsp_edits {
2343 this.update(cx, |this, cx| {
2344 this.as_local_mut().unwrap().edits_from_lsp(
2345 buffer,
2346 lsp_edits,
2347 language_server.server_id(),
2348 None,
2349 cx,
2350 )
2351 })?
2352 .await
2353 } else {
2354 Ok(Vec::with_capacity(0))
2355 }
2356 }
2357
2358 async fn format_via_external_command(
2359 buffer: &FormattableBuffer,
2360 command: &str,
2361 arguments: Option<&[String]>,
2362 cx: &mut AsyncApp,
2363 ) -> Result<Option<Diff>> {
2364 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2365 let file = File::from_dyn(buffer.file())?;
2366 let worktree = file.worktree.read(cx);
2367 let mut worktree_path = worktree.abs_path().to_path_buf();
2368 if worktree.root_entry()?.is_file() {
2369 worktree_path.pop();
2370 }
2371 Some(worktree_path)
2372 });
2373
2374 let mut child = util::command::new_smol_command(command);
2375
2376 if let Some(buffer_env) = buffer.env.as_ref() {
2377 child.envs(buffer_env);
2378 }
2379
2380 if let Some(working_dir_path) = working_dir_path {
2381 child.current_dir(working_dir_path);
2382 }
2383
2384 if let Some(arguments) = arguments {
2385 child.args(arguments.iter().map(|arg| {
2386 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2387 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2388 } else {
2389 arg.replace("{buffer_path}", "Untitled")
2390 }
2391 }));
2392 }
2393
2394 let mut child = child
2395 .stdin(smol::process::Stdio::piped())
2396 .stdout(smol::process::Stdio::piped())
2397 .stderr(smol::process::Stdio::piped())
2398 .spawn()?;
2399
2400 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2401 let text = buffer
2402 .handle
2403 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2404 for chunk in text.chunks() {
2405 stdin.write_all(chunk.as_bytes()).await?;
2406 }
2407 stdin.flush().await?;
2408
2409 let output = child.output().await?;
2410 anyhow::ensure!(
2411 output.status.success(),
2412 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2413 output.status.code(),
2414 String::from_utf8_lossy(&output.stdout),
2415 String::from_utf8_lossy(&output.stderr),
2416 );
2417
2418 let stdout = String::from_utf8(output.stdout)?;
2419 Ok(Some(
2420 buffer
2421 .handle
2422 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2423 .await,
2424 ))
2425 }
2426
2427 async fn try_resolve_code_action(
2428 lang_server: &LanguageServer,
2429 action: &mut CodeAction,
2430 request_timeout: Duration,
2431 ) -> anyhow::Result<()> {
2432 match &mut action.lsp_action {
2433 LspAction::Action(lsp_action) => {
2434 if !action.resolved
2435 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2436 && lsp_action.data.is_some()
2437 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2438 {
2439 **lsp_action = lang_server
2440 .request::<lsp::request::CodeActionResolveRequest>(
2441 *lsp_action.clone(),
2442 request_timeout,
2443 )
2444 .await
2445 .into_response()?;
2446 }
2447 }
2448 LspAction::CodeLens(lens) => {
2449 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2450 *lens = lang_server
2451 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2452 .await
2453 .into_response()?;
2454 }
2455 }
2456 LspAction::Command(_) => {}
2457 }
2458
2459 action.resolved = true;
2460 anyhow::Ok(())
2461 }
2462
2463 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2464 let buffer = buffer_handle.read(cx);
2465
2466 let file = buffer.file().cloned();
2467
2468 let Some(file) = File::from_dyn(file.as_ref()) else {
2469 return;
2470 };
2471 if !file.is_local() {
2472 return;
2473 }
2474 let path = ProjectPath::from_file(file, cx);
2475 let worktree_id = file.worktree_id(cx);
2476 let language = buffer.language().cloned();
2477
2478 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2479 for (server_id, diagnostics) in
2480 diagnostics.get(file.path()).cloned().unwrap_or_default()
2481 {
2482 self.update_buffer_diagnostics(
2483 buffer_handle,
2484 server_id,
2485 None,
2486 None,
2487 None,
2488 Vec::new(),
2489 diagnostics,
2490 cx,
2491 )
2492 .log_err();
2493 }
2494 }
2495 let Some(language) = language else {
2496 return;
2497 };
2498 let Some(snapshot) = self
2499 .worktree_store
2500 .read(cx)
2501 .worktree_for_id(worktree_id, cx)
2502 .map(|worktree| worktree.read(cx).snapshot())
2503 else {
2504 return;
2505 };
2506 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2507
2508 for server_id in
2509 self.lsp_tree
2510 .get(path, language.name(), language.manifest(), &delegate, cx)
2511 {
2512 let server = self
2513 .language_servers
2514 .get(&server_id)
2515 .and_then(|server_state| {
2516 if let LanguageServerState::Running { server, .. } = server_state {
2517 Some(server.clone())
2518 } else {
2519 None
2520 }
2521 });
2522 let server = match server {
2523 Some(server) => server,
2524 None => continue,
2525 };
2526
2527 buffer_handle.update(cx, |buffer, cx| {
2528 buffer.set_completion_triggers(
2529 server.server_id(),
2530 server
2531 .capabilities()
2532 .completion_provider
2533 .as_ref()
2534 .and_then(|provider| {
2535 provider
2536 .trigger_characters
2537 .as_ref()
2538 .map(|characters| characters.iter().cloned().collect())
2539 })
2540 .unwrap_or_default(),
2541 cx,
2542 );
2543 });
2544 }
2545 }
2546
2547 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2548 buffer.update(cx, |buffer, cx| {
2549 let Some(language) = buffer.language() else {
2550 return;
2551 };
2552 let path = ProjectPath {
2553 worktree_id: old_file.worktree_id(cx),
2554 path: old_file.path.clone(),
2555 };
2556 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2557 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2558 buffer.set_completion_triggers(server_id, Default::default(), cx);
2559 }
2560 });
2561 }
2562
2563 fn update_buffer_diagnostics(
2564 &mut self,
2565 buffer: &Entity<Buffer>,
2566 server_id: LanguageServerId,
2567 registration_id: Option<Option<SharedString>>,
2568 result_id: Option<SharedString>,
2569 version: Option<i32>,
2570 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2571 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2572 cx: &mut Context<LspStore>,
2573 ) -> Result<()> {
2574 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2575 Ordering::Equal
2576 .then_with(|| b.is_primary.cmp(&a.is_primary))
2577 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2578 .then_with(|| a.severity.cmp(&b.severity))
2579 .then_with(|| a.message.cmp(&b.message))
2580 }
2581
2582 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2583 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2584 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2585
2586 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2587 Ordering::Equal
2588 .then_with(|| a.range.start.cmp(&b.range.start))
2589 .then_with(|| b.range.end.cmp(&a.range.end))
2590 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2591 });
2592
2593 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2594
2595 let edits_since_save = std::cell::LazyCell::new(|| {
2596 let saved_version = buffer.read(cx).saved_version();
2597 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2598 });
2599
2600 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2601
2602 for (new_diagnostic, entry) in diagnostics {
2603 let start;
2604 let end;
2605 if new_diagnostic && entry.diagnostic.is_disk_based {
2606 // Some diagnostics are based on files on disk instead of buffers'
2607 // current contents. Adjust these diagnostics' ranges to reflect
2608 // any unsaved edits.
2609 // Do not alter the reused ones though, as their coordinates were stored as anchors
2610 // and were properly adjusted on reuse.
2611 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2612 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2613 } else {
2614 start = entry.range.start;
2615 end = entry.range.end;
2616 }
2617
2618 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2619 ..snapshot.clip_point_utf16(end, Bias::Right);
2620
2621 // Expand empty ranges by one codepoint
2622 if range.start == range.end {
2623 // This will be go to the next boundary when being clipped
2624 range.end.column += 1;
2625 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2626 if range.start == range.end && range.end.column > 0 {
2627 range.start.column -= 1;
2628 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2629 }
2630 }
2631
2632 sanitized_diagnostics.push(DiagnosticEntry {
2633 range,
2634 diagnostic: entry.diagnostic,
2635 });
2636 }
2637 drop(edits_since_save);
2638
2639 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2640 buffer.update(cx, |buffer, cx| {
2641 if let Some(registration_id) = registration_id {
2642 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2643 self.buffer_pull_diagnostics_result_ids
2644 .entry(server_id)
2645 .or_default()
2646 .entry(registration_id)
2647 .or_default()
2648 .insert(abs_path, result_id);
2649 }
2650 }
2651
2652 buffer.update_diagnostics(server_id, set, cx)
2653 });
2654
2655 Ok(())
2656 }
2657
2658 fn register_language_server_for_invisible_worktree(
2659 &mut self,
2660 worktree: &Entity<Worktree>,
2661 language_server_id: LanguageServerId,
2662 cx: &mut App,
2663 ) {
2664 let worktree = worktree.read(cx);
2665 let worktree_id = worktree.id();
2666 debug_assert!(!worktree.is_visible());
2667 let Some(mut origin_seed) = self
2668 .language_server_ids
2669 .iter()
2670 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2671 else {
2672 return;
2673 };
2674 origin_seed.worktree_id = worktree_id;
2675 self.language_server_ids
2676 .entry(origin_seed)
2677 .or_insert_with(|| UnifiedLanguageServer {
2678 id: language_server_id,
2679 project_roots: Default::default(),
2680 });
2681 }
2682
2683 fn register_buffer_with_language_servers(
2684 &mut self,
2685 buffer_handle: &Entity<Buffer>,
2686 only_register_servers: HashSet<LanguageServerSelector>,
2687 cx: &mut Context<LspStore>,
2688 ) {
2689 let buffer = buffer_handle.read(cx);
2690 let buffer_id = buffer.remote_id();
2691
2692 let Some(file) = File::from_dyn(buffer.file()) else {
2693 return;
2694 };
2695 if !file.is_local() {
2696 return;
2697 }
2698
2699 let abs_path = file.abs_path(cx);
2700 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2701 return;
2702 };
2703 let initial_snapshot = buffer.text_snapshot();
2704 let worktree_id = file.worktree_id(cx);
2705
2706 let Some(language) = buffer.language().cloned() else {
2707 return;
2708 };
2709 let path: Arc<RelPath> = file
2710 .path()
2711 .parent()
2712 .map(Arc::from)
2713 .unwrap_or_else(|| file.path().clone());
2714 let Some(worktree) = self
2715 .worktree_store
2716 .read(cx)
2717 .worktree_for_id(worktree_id, cx)
2718 else {
2719 return;
2720 };
2721 let language_name = language.name();
2722 let (reused, delegate, servers) = self
2723 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2724 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2725 .unwrap_or_else(|| {
2726 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2727 let delegate: Arc<dyn ManifestDelegate> =
2728 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2729
2730 let servers = self
2731 .lsp_tree
2732 .walk(
2733 ProjectPath { worktree_id, path },
2734 language.name(),
2735 language.manifest(),
2736 &delegate,
2737 cx,
2738 )
2739 .collect::<Vec<_>>();
2740 (false, lsp_delegate, servers)
2741 });
2742 let servers_and_adapters = servers
2743 .into_iter()
2744 .filter_map(|server_node| {
2745 if reused && server_node.server_id().is_none() {
2746 return None;
2747 }
2748 if !only_register_servers.is_empty() {
2749 if let Some(server_id) = server_node.server_id()
2750 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2751 {
2752 return None;
2753 }
2754 if let Some(name) = server_node.name()
2755 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2756 {
2757 return None;
2758 }
2759 }
2760
2761 let server_id = server_node.server_id_or_init(|disposition| {
2762 let path = &disposition.path;
2763
2764 {
2765 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2766
2767 let server_id = self.get_or_insert_language_server(
2768 &worktree,
2769 delegate.clone(),
2770 disposition,
2771 &language_name,
2772 cx,
2773 );
2774
2775 if let Some(state) = self.language_servers.get(&server_id)
2776 && let Ok(uri) = uri
2777 {
2778 state.add_workspace_folder(uri);
2779 };
2780 server_id
2781 }
2782 })?;
2783 let server_state = self.language_servers.get(&server_id)?;
2784 if let LanguageServerState::Running {
2785 server, adapter, ..
2786 } = server_state
2787 {
2788 Some((server.clone(), adapter.clone()))
2789 } else {
2790 None
2791 }
2792 })
2793 .collect::<Vec<_>>();
2794 for (server, adapter) in servers_and_adapters {
2795 buffer_handle.update(cx, |buffer, cx| {
2796 buffer.set_completion_triggers(
2797 server.server_id(),
2798 server
2799 .capabilities()
2800 .completion_provider
2801 .as_ref()
2802 .and_then(|provider| {
2803 provider
2804 .trigger_characters
2805 .as_ref()
2806 .map(|characters| characters.iter().cloned().collect())
2807 })
2808 .unwrap_or_default(),
2809 cx,
2810 );
2811 });
2812
2813 let snapshot = LspBufferSnapshot {
2814 version: 0,
2815 snapshot: initial_snapshot.clone(),
2816 };
2817
2818 let mut registered = false;
2819 self.buffer_snapshots
2820 .entry(buffer_id)
2821 .or_default()
2822 .entry(server.server_id())
2823 .or_insert_with(|| {
2824 registered = true;
2825 server.register_buffer(
2826 uri.clone(),
2827 adapter.language_id(&language.name()),
2828 0,
2829 initial_snapshot.text(),
2830 );
2831
2832 vec![snapshot]
2833 });
2834
2835 self.buffers_opened_in_servers
2836 .entry(buffer_id)
2837 .or_default()
2838 .insert(server.server_id());
2839 if registered {
2840 cx.emit(LspStoreEvent::LanguageServerUpdate {
2841 language_server_id: server.server_id(),
2842 name: None,
2843 message: proto::update_language_server::Variant::RegisteredForBuffer(
2844 proto::RegisteredForBuffer {
2845 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2846 buffer_id: buffer_id.to_proto(),
2847 },
2848 ),
2849 });
2850 }
2851 }
2852 }
2853
2854 fn reuse_existing_language_server<'lang_name>(
2855 &self,
2856 server_tree: &LanguageServerTree,
2857 worktree: &Entity<Worktree>,
2858 language_name: &'lang_name LanguageName,
2859 cx: &mut App,
2860 ) -> Option<(
2861 Arc<LocalLspAdapterDelegate>,
2862 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2863 )> {
2864 if worktree.read(cx).is_visible() {
2865 return None;
2866 }
2867
2868 let worktree_store = self.worktree_store.read(cx);
2869 let servers = server_tree
2870 .instances
2871 .iter()
2872 .filter(|(worktree_id, _)| {
2873 worktree_store
2874 .worktree_for_id(**worktree_id, cx)
2875 .is_some_and(|worktree| worktree.read(cx).is_visible())
2876 })
2877 .flat_map(|(worktree_id, servers)| {
2878 servers
2879 .roots
2880 .iter()
2881 .flat_map(|(_, language_servers)| language_servers)
2882 .map(move |(_, (server_node, server_languages))| {
2883 (worktree_id, server_node, server_languages)
2884 })
2885 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2886 .map(|(worktree_id, server_node, _)| {
2887 (
2888 *worktree_id,
2889 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2890 )
2891 })
2892 })
2893 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2894 acc.entry(worktree_id)
2895 .or_insert_with(Vec::new)
2896 .push(server_node);
2897 acc
2898 })
2899 .into_values()
2900 .max_by_key(|servers| servers.len())?;
2901
2902 let worktree_id = worktree.read(cx).id();
2903 let apply = move |tree: &mut LanguageServerTree| {
2904 for server_node in &servers {
2905 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2906 }
2907 servers
2908 };
2909
2910 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2911 Some((delegate, apply))
2912 }
2913
2914 pub(crate) fn unregister_old_buffer_from_language_servers(
2915 &mut self,
2916 buffer: &Entity<Buffer>,
2917 old_file: &File,
2918 cx: &mut App,
2919 ) {
2920 let old_path = match old_file.as_local() {
2921 Some(local) => local.abs_path(cx),
2922 None => return,
2923 };
2924
2925 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2926 debug_panic!("{old_path:?} is not parseable as an URI");
2927 return;
2928 };
2929 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2930 }
2931
2932 pub(crate) fn unregister_buffer_from_language_servers(
2933 &mut self,
2934 buffer: &Entity<Buffer>,
2935 file_url: &lsp::Uri,
2936 cx: &mut App,
2937 ) {
2938 buffer.update(cx, |buffer, cx| {
2939 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2940
2941 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2942 if snapshots
2943 .as_mut()
2944 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2945 {
2946 language_server.unregister_buffer(file_url.clone());
2947 }
2948 }
2949 });
2950 }
2951
2952 fn buffer_snapshot_for_lsp_version(
2953 &mut self,
2954 buffer: &Entity<Buffer>,
2955 server_id: LanguageServerId,
2956 version: Option<i32>,
2957 cx: &App,
2958 ) -> Result<TextBufferSnapshot> {
2959 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2960
2961 if let Some(version) = version {
2962 let buffer_id = buffer.read(cx).remote_id();
2963 let snapshots = if let Some(snapshots) = self
2964 .buffer_snapshots
2965 .get_mut(&buffer_id)
2966 .and_then(|m| m.get_mut(&server_id))
2967 {
2968 snapshots
2969 } else if version == 0 {
2970 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2971 // We detect this case and treat it as if the version was `None`.
2972 return Ok(buffer.read(cx).text_snapshot());
2973 } else {
2974 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2975 };
2976
2977 let found_snapshot = snapshots
2978 .binary_search_by_key(&version, |e| e.version)
2979 .map(|ix| snapshots[ix].snapshot.clone())
2980 .map_err(|_| {
2981 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2982 })?;
2983
2984 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2985 Ok(found_snapshot)
2986 } else {
2987 Ok((buffer.read(cx)).text_snapshot())
2988 }
2989 }
2990
2991 async fn get_server_code_actions_from_action_kinds(
2992 lsp_store: &WeakEntity<LspStore>,
2993 language_server_id: LanguageServerId,
2994 code_action_kinds: Vec<lsp::CodeActionKind>,
2995 buffer: &Entity<Buffer>,
2996 cx: &mut AsyncApp,
2997 ) -> Result<Vec<CodeAction>> {
2998 let actions = lsp_store
2999 .update(cx, move |this, cx| {
3000 let request = GetCodeActions {
3001 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3002 kinds: Some(code_action_kinds),
3003 };
3004 let server = LanguageServerToQuery::Other(language_server_id);
3005 this.request_lsp(buffer.clone(), server, request, cx)
3006 })?
3007 .await?;
3008 Ok(actions)
3009 }
3010
3011 pub async fn execute_code_actions_on_server(
3012 lsp_store: &WeakEntity<LspStore>,
3013 language_server: &Arc<LanguageServer>,
3014 actions: Vec<CodeAction>,
3015 push_to_history: bool,
3016 project_transaction: &mut ProjectTransaction,
3017 cx: &mut AsyncApp,
3018 ) -> anyhow::Result<()> {
3019 let request_timeout = cx.update(|app| {
3020 ProjectSettings::get_global(app)
3021 .global_lsp_settings
3022 .get_request_timeout()
3023 });
3024
3025 for mut action in actions {
3026 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3027 .await
3028 .context("resolving a formatting code action")?;
3029
3030 if let Some(edit) = action.lsp_action.edit() {
3031 if edit.changes.is_none() && edit.document_changes.is_none() {
3032 continue;
3033 }
3034
3035 let new = Self::deserialize_workspace_edit(
3036 lsp_store.upgrade().context("project dropped")?,
3037 edit.clone(),
3038 push_to_history,
3039 language_server.clone(),
3040 cx,
3041 )
3042 .await?;
3043 project_transaction.0.extend(new.0);
3044 }
3045
3046 let Some(command) = action.lsp_action.command() else {
3047 continue;
3048 };
3049
3050 let server_capabilities = language_server.capabilities();
3051 let available_commands = server_capabilities
3052 .execute_command_provider
3053 .as_ref()
3054 .map(|options| options.commands.as_slice())
3055 .unwrap_or_default();
3056 if !available_commands.contains(&command.command) {
3057 log::warn!(
3058 "Cannot execute a command {} not listed in the language server capabilities",
3059 command.command
3060 );
3061 continue;
3062 }
3063
3064 lsp_store.update(cx, |lsp_store, _| {
3065 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3066 mode.last_workspace_edits_by_language_server
3067 .remove(&language_server.server_id());
3068 }
3069 })?;
3070
3071 language_server
3072 .request::<lsp::request::ExecuteCommand>(
3073 lsp::ExecuteCommandParams {
3074 command: command.command.clone(),
3075 arguments: command.arguments.clone().unwrap_or_default(),
3076 ..Default::default()
3077 },
3078 request_timeout,
3079 )
3080 .await
3081 .into_response()
3082 .context("execute command")?;
3083
3084 lsp_store.update(cx, |this, _| {
3085 if let LspStoreMode::Local(mode) = &mut this.mode {
3086 project_transaction.0.extend(
3087 mode.last_workspace_edits_by_language_server
3088 .remove(&language_server.server_id())
3089 .unwrap_or_default()
3090 .0,
3091 )
3092 }
3093 })?;
3094 }
3095 Ok(())
3096 }
3097
3098 pub async fn deserialize_text_edits(
3099 this: Entity<LspStore>,
3100 buffer_to_edit: Entity<Buffer>,
3101 edits: Vec<lsp::TextEdit>,
3102 push_to_history: bool,
3103 _: Arc<CachedLspAdapter>,
3104 language_server: Arc<LanguageServer>,
3105 cx: &mut AsyncApp,
3106 ) -> Result<Option<Transaction>> {
3107 let edits = this
3108 .update(cx, |this, cx| {
3109 this.as_local_mut().unwrap().edits_from_lsp(
3110 &buffer_to_edit,
3111 edits,
3112 language_server.server_id(),
3113 None,
3114 cx,
3115 )
3116 })
3117 .await?;
3118
3119 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3120 buffer.finalize_last_transaction();
3121 buffer.start_transaction();
3122 for (range, text) in edits {
3123 buffer.edit([(range, text)], None, cx);
3124 }
3125
3126 if buffer.end_transaction(cx).is_some() {
3127 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3128 if !push_to_history {
3129 buffer.forget_transaction(transaction.id);
3130 }
3131 Some(transaction)
3132 } else {
3133 None
3134 }
3135 });
3136
3137 Ok(transaction)
3138 }
3139
3140 #[allow(clippy::type_complexity)]
3141 pub fn edits_from_lsp(
3142 &mut self,
3143 buffer: &Entity<Buffer>,
3144 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3145 server_id: LanguageServerId,
3146 version: Option<i32>,
3147 cx: &mut Context<LspStore>,
3148 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3149 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3150 cx.background_spawn(async move {
3151 let snapshot = snapshot?;
3152 let mut lsp_edits = lsp_edits
3153 .into_iter()
3154 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3155 .collect::<Vec<_>>();
3156
3157 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3158
3159 let mut lsp_edits = lsp_edits.into_iter().peekable();
3160 let mut edits = Vec::new();
3161 while let Some((range, mut new_text)) = lsp_edits.next() {
3162 // Clip invalid ranges provided by the language server.
3163 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3164 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3165
3166 // Combine any LSP edits that are adjacent.
3167 //
3168 // Also, combine LSP edits that are separated from each other by only
3169 // a newline. This is important because for some code actions,
3170 // Rust-analyzer rewrites the entire buffer via a series of edits that
3171 // are separated by unchanged newline characters.
3172 //
3173 // In order for the diffing logic below to work properly, any edits that
3174 // cancel each other out must be combined into one.
3175 while let Some((next_range, next_text)) = lsp_edits.peek() {
3176 if next_range.start.0 > range.end {
3177 if next_range.start.0.row > range.end.row + 1
3178 || next_range.start.0.column > 0
3179 || snapshot.clip_point_utf16(
3180 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3181 Bias::Left,
3182 ) > range.end
3183 {
3184 break;
3185 }
3186 new_text.push('\n');
3187 }
3188 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3189 new_text.push_str(next_text);
3190 lsp_edits.next();
3191 }
3192
3193 // For multiline edits, perform a diff of the old and new text so that
3194 // we can identify the changes more precisely, preserving the locations
3195 // of any anchors positioned in the unchanged regions.
3196 if range.end.row > range.start.row {
3197 let offset = range.start.to_offset(&snapshot);
3198 let old_text = snapshot.text_for_range(range).collect::<String>();
3199 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3200 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3201 (
3202 snapshot.anchor_after(offset + range.start)
3203 ..snapshot.anchor_before(offset + range.end),
3204 replacement,
3205 )
3206 }));
3207 } else if range.end == range.start {
3208 let anchor = snapshot.anchor_after(range.start);
3209 edits.push((anchor..anchor, new_text.into()));
3210 } else {
3211 let edit_start = snapshot.anchor_after(range.start);
3212 let edit_end = snapshot.anchor_before(range.end);
3213 edits.push((edit_start..edit_end, new_text.into()));
3214 }
3215 }
3216
3217 Ok(edits)
3218 })
3219 }
3220
3221 pub(crate) async fn deserialize_workspace_edit(
3222 this: Entity<LspStore>,
3223 edit: lsp::WorkspaceEdit,
3224 push_to_history: bool,
3225 language_server: Arc<LanguageServer>,
3226 cx: &mut AsyncApp,
3227 ) -> Result<ProjectTransaction> {
3228 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3229
3230 let mut operations = Vec::new();
3231 if let Some(document_changes) = edit.document_changes {
3232 match document_changes {
3233 lsp::DocumentChanges::Edits(edits) => {
3234 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3235 }
3236 lsp::DocumentChanges::Operations(ops) => operations = ops,
3237 }
3238 } else if let Some(changes) = edit.changes {
3239 operations.extend(changes.into_iter().map(|(uri, edits)| {
3240 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3241 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3242 uri,
3243 version: None,
3244 },
3245 edits: edits.into_iter().map(Edit::Plain).collect(),
3246 })
3247 }));
3248 }
3249
3250 let mut project_transaction = ProjectTransaction::default();
3251 for operation in operations {
3252 match operation {
3253 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3254 let abs_path = op
3255 .uri
3256 .to_file_path()
3257 .map_err(|()| anyhow!("can't convert URI to path"))?;
3258
3259 if let Some(parent_path) = abs_path.parent() {
3260 fs.create_dir(parent_path).await?;
3261 }
3262 if abs_path.ends_with("/") {
3263 fs.create_dir(&abs_path).await?;
3264 } else {
3265 fs.create_file(
3266 &abs_path,
3267 op.options
3268 .map(|options| fs::CreateOptions {
3269 overwrite: options.overwrite.unwrap_or(false),
3270 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3271 })
3272 .unwrap_or_default(),
3273 )
3274 .await?;
3275 }
3276 }
3277
3278 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3279 let source_abs_path = op
3280 .old_uri
3281 .to_file_path()
3282 .map_err(|()| anyhow!("can't convert URI to path"))?;
3283 let target_abs_path = op
3284 .new_uri
3285 .to_file_path()
3286 .map_err(|()| anyhow!("can't convert URI to path"))?;
3287
3288 let options = fs::RenameOptions {
3289 overwrite: op
3290 .options
3291 .as_ref()
3292 .and_then(|options| options.overwrite)
3293 .unwrap_or(false),
3294 ignore_if_exists: op
3295 .options
3296 .as_ref()
3297 .and_then(|options| options.ignore_if_exists)
3298 .unwrap_or(false),
3299 create_parents: true,
3300 };
3301
3302 fs.rename(&source_abs_path, &target_abs_path, options)
3303 .await?;
3304 }
3305
3306 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3307 let abs_path = op
3308 .uri
3309 .to_file_path()
3310 .map_err(|()| anyhow!("can't convert URI to path"))?;
3311 let options = op
3312 .options
3313 .map(|options| fs::RemoveOptions {
3314 recursive: options.recursive.unwrap_or(false),
3315 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3316 })
3317 .unwrap_or_default();
3318 if abs_path.ends_with("/") {
3319 fs.remove_dir(&abs_path, options).await?;
3320 } else {
3321 fs.remove_file(&abs_path, options).await?;
3322 }
3323 }
3324
3325 lsp::DocumentChangeOperation::Edit(op) => {
3326 let buffer_to_edit = this
3327 .update(cx, |this, cx| {
3328 this.open_local_buffer_via_lsp(
3329 op.text_document.uri.clone(),
3330 language_server.server_id(),
3331 cx,
3332 )
3333 })
3334 .await?;
3335
3336 let edits = this
3337 .update(cx, |this, cx| {
3338 let path = buffer_to_edit.read(cx).project_path(cx);
3339 let active_entry = this.active_entry;
3340 let is_active_entry = path.is_some_and(|project_path| {
3341 this.worktree_store
3342 .read(cx)
3343 .entry_for_path(&project_path, cx)
3344 .is_some_and(|entry| Some(entry.id) == active_entry)
3345 });
3346 let local = this.as_local_mut().unwrap();
3347
3348 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3349 for edit in op.edits {
3350 match edit {
3351 Edit::Plain(edit) => {
3352 if !edits.contains(&edit) {
3353 edits.push(edit)
3354 }
3355 }
3356 Edit::Annotated(edit) => {
3357 if !edits.contains(&edit.text_edit) {
3358 edits.push(edit.text_edit)
3359 }
3360 }
3361 Edit::Snippet(edit) => {
3362 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3363 else {
3364 continue;
3365 };
3366
3367 if is_active_entry {
3368 snippet_edits.push((edit.range, snippet));
3369 } else {
3370 // Since this buffer is not focused, apply a normal edit.
3371 let new_edit = TextEdit {
3372 range: edit.range,
3373 new_text: snippet.text,
3374 };
3375 if !edits.contains(&new_edit) {
3376 edits.push(new_edit);
3377 }
3378 }
3379 }
3380 }
3381 }
3382 if !snippet_edits.is_empty() {
3383 let buffer_id = buffer_to_edit.read(cx).remote_id();
3384 let version = if let Some(buffer_version) = op.text_document.version
3385 {
3386 local
3387 .buffer_snapshot_for_lsp_version(
3388 &buffer_to_edit,
3389 language_server.server_id(),
3390 Some(buffer_version),
3391 cx,
3392 )
3393 .ok()
3394 .map(|snapshot| snapshot.version)
3395 } else {
3396 Some(buffer_to_edit.read(cx).saved_version().clone())
3397 };
3398
3399 let most_recent_edit =
3400 version.and_then(|version| version.most_recent());
3401 // Check if the edit that triggered that edit has been made by this participant.
3402
3403 if let Some(most_recent_edit) = most_recent_edit {
3404 cx.emit(LspStoreEvent::SnippetEdit {
3405 buffer_id,
3406 edits: snippet_edits,
3407 most_recent_edit,
3408 });
3409 }
3410 }
3411
3412 local.edits_from_lsp(
3413 &buffer_to_edit,
3414 edits,
3415 language_server.server_id(),
3416 op.text_document.version,
3417 cx,
3418 )
3419 })
3420 .await?;
3421
3422 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3423 buffer.finalize_last_transaction();
3424 buffer.start_transaction();
3425 for (range, text) in edits {
3426 buffer.edit([(range, text)], None, cx);
3427 }
3428
3429 buffer.end_transaction(cx).and_then(|transaction_id| {
3430 if push_to_history {
3431 buffer.finalize_last_transaction();
3432 buffer.get_transaction(transaction_id).cloned()
3433 } else {
3434 buffer.forget_transaction(transaction_id)
3435 }
3436 })
3437 });
3438 if let Some(transaction) = transaction {
3439 project_transaction.0.insert(buffer_to_edit, transaction);
3440 }
3441 }
3442 }
3443 }
3444
3445 Ok(project_transaction)
3446 }
3447
3448 async fn on_lsp_workspace_edit(
3449 this: WeakEntity<LspStore>,
3450 params: lsp::ApplyWorkspaceEditParams,
3451 server_id: LanguageServerId,
3452 cx: &mut AsyncApp,
3453 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3454 let this = this.upgrade().context("project project closed")?;
3455 let language_server = this
3456 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3457 .context("language server not found")?;
3458 let transaction = Self::deserialize_workspace_edit(
3459 this.clone(),
3460 params.edit,
3461 true,
3462 language_server.clone(),
3463 cx,
3464 )
3465 .await
3466 .log_err();
3467 this.update(cx, |this, cx| {
3468 if let Some(transaction) = transaction {
3469 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3470
3471 this.as_local_mut()
3472 .unwrap()
3473 .last_workspace_edits_by_language_server
3474 .insert(server_id, transaction);
3475 }
3476 });
3477 Ok(lsp::ApplyWorkspaceEditResponse {
3478 applied: true,
3479 failed_change: None,
3480 failure_reason: None,
3481 })
3482 }
3483
3484 fn remove_worktree(
3485 &mut self,
3486 id_to_remove: WorktreeId,
3487 cx: &mut Context<LspStore>,
3488 ) -> Vec<LanguageServerId> {
3489 self.restricted_worktrees_tasks.remove(&id_to_remove);
3490 self.diagnostics.remove(&id_to_remove);
3491 self.prettier_store.update(cx, |prettier_store, cx| {
3492 prettier_store.remove_worktree(id_to_remove, cx);
3493 });
3494
3495 let mut servers_to_remove = BTreeSet::default();
3496 let mut servers_to_preserve = HashSet::default();
3497 for (seed, state) in &self.language_server_ids {
3498 if seed.worktree_id == id_to_remove {
3499 servers_to_remove.insert(state.id);
3500 } else {
3501 servers_to_preserve.insert(state.id);
3502 }
3503 }
3504 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3505 self.language_server_ids
3506 .retain(|_, state| !servers_to_remove.contains(&state.id));
3507 for server_id_to_remove in &servers_to_remove {
3508 self.language_server_watched_paths
3509 .remove(server_id_to_remove);
3510 self.language_server_paths_watched_for_rename
3511 .remove(server_id_to_remove);
3512 self.last_workspace_edits_by_language_server
3513 .remove(server_id_to_remove);
3514 self.language_servers.remove(server_id_to_remove);
3515 self.buffer_pull_diagnostics_result_ids
3516 .remove(server_id_to_remove);
3517 self.workspace_pull_diagnostics_result_ids
3518 .remove(server_id_to_remove);
3519 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3520 buffer_servers.remove(server_id_to_remove);
3521 }
3522 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3523 }
3524 servers_to_remove.into_iter().collect()
3525 }
3526
3527 fn rebuild_watched_paths_inner<'a>(
3528 &'a self,
3529 language_server_id: LanguageServerId,
3530 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3531 cx: &mut Context<LspStore>,
3532 ) -> LanguageServerWatchedPathsBuilder {
3533 let worktrees = self
3534 .worktree_store
3535 .read(cx)
3536 .worktrees()
3537 .filter_map(|worktree| {
3538 self.language_servers_for_worktree(worktree.read(cx).id())
3539 .find(|server| server.server_id() == language_server_id)
3540 .map(|_| worktree)
3541 })
3542 .collect::<Vec<_>>();
3543
3544 let mut worktree_globs = HashMap::default();
3545 let mut abs_globs = HashMap::default();
3546 log::trace!(
3547 "Processing new watcher paths for language server with id {}",
3548 language_server_id
3549 );
3550
3551 for watcher in watchers {
3552 if let Some((worktree, literal_prefix, pattern)) =
3553 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3554 {
3555 worktree.update(cx, |worktree, _| {
3556 if let Some((tree, glob)) =
3557 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3558 {
3559 tree.add_path_prefix_to_scan(literal_prefix);
3560 worktree_globs
3561 .entry(tree.id())
3562 .or_insert_with(GlobSetBuilder::new)
3563 .add(glob);
3564 }
3565 });
3566 } else {
3567 let (path, pattern) = match &watcher.glob_pattern {
3568 lsp::GlobPattern::String(s) => {
3569 let watcher_path = SanitizedPath::new(s);
3570 let path = glob_literal_prefix(watcher_path.as_path());
3571 let pattern = watcher_path
3572 .as_path()
3573 .strip_prefix(&path)
3574 .map(|p| p.to_string_lossy().into_owned())
3575 .unwrap_or_else(|e| {
3576 debug_panic!(
3577 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3578 s,
3579 path.display(),
3580 e
3581 );
3582 watcher_path.as_path().to_string_lossy().into_owned()
3583 });
3584 (path, pattern)
3585 }
3586 lsp::GlobPattern::Relative(rp) => {
3587 let Ok(mut base_uri) = match &rp.base_uri {
3588 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3589 lsp::OneOf::Right(base_uri) => base_uri,
3590 }
3591 .to_file_path() else {
3592 continue;
3593 };
3594
3595 let path = glob_literal_prefix(Path::new(&rp.pattern));
3596 let pattern = Path::new(&rp.pattern)
3597 .strip_prefix(&path)
3598 .map(|p| p.to_string_lossy().into_owned())
3599 .unwrap_or_else(|e| {
3600 debug_panic!(
3601 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3602 rp.pattern,
3603 path.display(),
3604 e
3605 );
3606 rp.pattern.clone()
3607 });
3608 base_uri.push(path);
3609 (base_uri, pattern)
3610 }
3611 };
3612
3613 if let Some(glob) = Glob::new(&pattern).log_err() {
3614 if !path
3615 .components()
3616 .any(|c| matches!(c, path::Component::Normal(_)))
3617 {
3618 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3619 // rather than adding a new watcher for `/`.
3620 for worktree in &worktrees {
3621 worktree_globs
3622 .entry(worktree.read(cx).id())
3623 .or_insert_with(GlobSetBuilder::new)
3624 .add(glob.clone());
3625 }
3626 } else {
3627 abs_globs
3628 .entry(path.into())
3629 .or_insert_with(GlobSetBuilder::new)
3630 .add(glob);
3631 }
3632 }
3633 }
3634 }
3635
3636 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3637 for (worktree_id, builder) in worktree_globs {
3638 if let Ok(globset) = builder.build() {
3639 watch_builder.watch_worktree(worktree_id, globset);
3640 }
3641 }
3642 for (abs_path, builder) in abs_globs {
3643 if let Ok(globset) = builder.build() {
3644 watch_builder.watch_abs_path(abs_path, globset);
3645 }
3646 }
3647 watch_builder
3648 }
3649
3650 fn worktree_and_path_for_file_watcher(
3651 worktrees: &[Entity<Worktree>],
3652 watcher: &FileSystemWatcher,
3653 cx: &App,
3654 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3655 worktrees.iter().find_map(|worktree| {
3656 let tree = worktree.read(cx);
3657 let worktree_root_path = tree.abs_path();
3658 let path_style = tree.path_style();
3659 match &watcher.glob_pattern {
3660 lsp::GlobPattern::String(s) => {
3661 let watcher_path = SanitizedPath::new(s);
3662 let relative = watcher_path
3663 .as_path()
3664 .strip_prefix(&worktree_root_path)
3665 .ok()?;
3666 let literal_prefix = glob_literal_prefix(relative);
3667 Some((
3668 worktree.clone(),
3669 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3670 relative.to_string_lossy().into_owned(),
3671 ))
3672 }
3673 lsp::GlobPattern::Relative(rp) => {
3674 let base_uri = match &rp.base_uri {
3675 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3676 lsp::OneOf::Right(base_uri) => base_uri,
3677 }
3678 .to_file_path()
3679 .ok()?;
3680 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3681 let mut literal_prefix = relative.to_owned();
3682 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3683 Some((
3684 worktree.clone(),
3685 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3686 rp.pattern.clone(),
3687 ))
3688 }
3689 }
3690 })
3691 }
3692
3693 fn rebuild_watched_paths(
3694 &mut self,
3695 language_server_id: LanguageServerId,
3696 cx: &mut Context<LspStore>,
3697 ) {
3698 let Some(registrations) = self
3699 .language_server_dynamic_registrations
3700 .get(&language_server_id)
3701 else {
3702 return;
3703 };
3704
3705 let watch_builder = self.rebuild_watched_paths_inner(
3706 language_server_id,
3707 registrations.did_change_watched_files.values().flatten(),
3708 cx,
3709 );
3710 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3711 self.language_server_watched_paths
3712 .insert(language_server_id, watcher);
3713
3714 cx.notify();
3715 }
3716
3717 fn on_lsp_did_change_watched_files(
3718 &mut self,
3719 language_server_id: LanguageServerId,
3720 registration_id: &str,
3721 params: DidChangeWatchedFilesRegistrationOptions,
3722 cx: &mut Context<LspStore>,
3723 ) {
3724 let registrations = self
3725 .language_server_dynamic_registrations
3726 .entry(language_server_id)
3727 .or_default();
3728
3729 registrations
3730 .did_change_watched_files
3731 .insert(registration_id.to_string(), params.watchers);
3732
3733 self.rebuild_watched_paths(language_server_id, cx);
3734 }
3735
3736 fn on_lsp_unregister_did_change_watched_files(
3737 &mut self,
3738 language_server_id: LanguageServerId,
3739 registration_id: &str,
3740 cx: &mut Context<LspStore>,
3741 ) {
3742 let registrations = self
3743 .language_server_dynamic_registrations
3744 .entry(language_server_id)
3745 .or_default();
3746
3747 if registrations
3748 .did_change_watched_files
3749 .remove(registration_id)
3750 .is_some()
3751 {
3752 log::info!(
3753 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3754 language_server_id,
3755 registration_id
3756 );
3757 } else {
3758 log::warn!(
3759 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3760 language_server_id,
3761 registration_id
3762 );
3763 }
3764
3765 self.rebuild_watched_paths(language_server_id, cx);
3766 }
3767
3768 async fn initialization_options_for_adapter(
3769 adapter: Arc<dyn LspAdapter>,
3770 delegate: &Arc<dyn LspAdapterDelegate>,
3771 ) -> Result<Option<serde_json::Value>> {
3772 let Some(mut initialization_config) =
3773 adapter.clone().initialization_options(delegate).await?
3774 else {
3775 return Ok(None);
3776 };
3777
3778 for other_adapter in delegate.registered_lsp_adapters() {
3779 if other_adapter.name() == adapter.name() {
3780 continue;
3781 }
3782 if let Ok(Some(target_config)) = other_adapter
3783 .clone()
3784 .additional_initialization_options(adapter.name(), delegate)
3785 .await
3786 {
3787 merge_json_value_into(target_config.clone(), &mut initialization_config);
3788 }
3789 }
3790
3791 Ok(Some(initialization_config))
3792 }
3793
3794 async fn workspace_configuration_for_adapter(
3795 adapter: Arc<dyn LspAdapter>,
3796 delegate: &Arc<dyn LspAdapterDelegate>,
3797 toolchain: Option<Toolchain>,
3798 requested_uri: Option<Uri>,
3799 cx: &mut AsyncApp,
3800 ) -> Result<serde_json::Value> {
3801 let mut workspace_config = adapter
3802 .clone()
3803 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3804 .await?;
3805
3806 for other_adapter in delegate.registered_lsp_adapters() {
3807 if other_adapter.name() == adapter.name() {
3808 continue;
3809 }
3810 if let Ok(Some(target_config)) = other_adapter
3811 .clone()
3812 .additional_workspace_configuration(adapter.name(), delegate, cx)
3813 .await
3814 {
3815 merge_json_value_into(target_config.clone(), &mut workspace_config);
3816 }
3817 }
3818
3819 Ok(workspace_config)
3820 }
3821
3822 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3823 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3824 Some(server.clone())
3825 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3826 Some(Arc::clone(server))
3827 } else {
3828 None
3829 }
3830 }
3831}
3832
3833fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3834 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3835 cx.emit(LspStoreEvent::LanguageServerUpdate {
3836 language_server_id: server.server_id(),
3837 name: Some(server.name()),
3838 message: proto::update_language_server::Variant::MetadataUpdated(
3839 proto::ServerMetadataUpdated {
3840 capabilities: Some(capabilities),
3841 binary: Some(proto::LanguageServerBinaryInfo {
3842 path: server.binary().path.to_string_lossy().into_owned(),
3843 arguments: server
3844 .binary()
3845 .arguments
3846 .iter()
3847 .map(|arg| arg.to_string_lossy().into_owned())
3848 .collect(),
3849 }),
3850 configuration: serde_json::to_string(server.configuration()).ok(),
3851 workspace_folders: server
3852 .workspace_folders()
3853 .iter()
3854 .map(|uri| uri.to_string())
3855 .collect(),
3856 },
3857 ),
3858 });
3859 }
3860}
3861
3862#[derive(Debug)]
3863pub struct FormattableBuffer {
3864 handle: Entity<Buffer>,
3865 abs_path: Option<PathBuf>,
3866 env: Option<HashMap<String, String>>,
3867 ranges: Option<Vec<Range<Anchor>>>,
3868}
3869
3870pub struct RemoteLspStore {
3871 upstream_client: Option<AnyProtoClient>,
3872 upstream_project_id: u64,
3873}
3874
3875pub(crate) enum LspStoreMode {
3876 Local(LocalLspStore), // ssh host and collab host
3877 Remote(RemoteLspStore), // collab guest
3878}
3879
3880impl LspStoreMode {
3881 fn is_local(&self) -> bool {
3882 matches!(self, LspStoreMode::Local(_))
3883 }
3884}
3885
3886pub struct LspStore {
3887 mode: LspStoreMode,
3888 last_formatting_failure: Option<String>,
3889 downstream_client: Option<(AnyProtoClient, u64)>,
3890 nonce: u128,
3891 buffer_store: Entity<BufferStore>,
3892 worktree_store: Entity<WorktreeStore>,
3893 pub languages: Arc<LanguageRegistry>,
3894 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3895 active_entry: Option<ProjectEntryId>,
3896 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3897 _maintain_buffer_languages: Task<()>,
3898 diagnostic_summaries:
3899 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3900 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3901 semantic_token_config: SemanticTokenConfig,
3902 lsp_data: HashMap<BufferId, BufferLspData>,
3903 next_hint_id: Arc<AtomicUsize>,
3904}
3905
3906#[derive(Debug)]
3907pub struct BufferLspData {
3908 buffer_version: Global,
3909 document_colors: Option<DocumentColorData>,
3910 code_lens: Option<CodeLensData>,
3911 semantic_tokens: Option<SemanticTokensData>,
3912 folding_ranges: Option<FoldingRangeData>,
3913 inlay_hints: BufferInlayHints,
3914 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3915 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3916}
3917
3918#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3919struct LspKey {
3920 request_type: TypeId,
3921 server_queried: Option<LanguageServerId>,
3922}
3923
3924impl BufferLspData {
3925 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3926 Self {
3927 buffer_version: buffer.read(cx).version(),
3928 document_colors: None,
3929 code_lens: None,
3930 semantic_tokens: None,
3931 folding_ranges: None,
3932 inlay_hints: BufferInlayHints::new(buffer, cx),
3933 lsp_requests: HashMap::default(),
3934 chunk_lsp_requests: HashMap::default(),
3935 }
3936 }
3937
3938 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3939 if let Some(document_colors) = &mut self.document_colors {
3940 document_colors.remove_server_data(for_server);
3941 }
3942
3943 if let Some(code_lens) = &mut self.code_lens {
3944 code_lens.remove_server_data(for_server);
3945 }
3946
3947 self.inlay_hints.remove_server_data(for_server);
3948
3949 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3950 semantic_tokens.raw_tokens.servers.remove(&for_server);
3951 semantic_tokens
3952 .latest_invalidation_requests
3953 .remove(&for_server);
3954 }
3955
3956 if let Some(folding_ranges) = &mut self.folding_ranges {
3957 folding_ranges.ranges.remove(&for_server);
3958 }
3959 }
3960
3961 #[cfg(any(test, feature = "test-support"))]
3962 pub fn inlay_hints(&self) -> &BufferInlayHints {
3963 &self.inlay_hints
3964 }
3965}
3966
3967#[derive(Debug)]
3968pub enum LspStoreEvent {
3969 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3970 LanguageServerRemoved(LanguageServerId),
3971 LanguageServerUpdate {
3972 language_server_id: LanguageServerId,
3973 name: Option<LanguageServerName>,
3974 message: proto::update_language_server::Variant,
3975 },
3976 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3977 LanguageServerPrompt(LanguageServerPromptRequest),
3978 LanguageDetected {
3979 buffer: Entity<Buffer>,
3980 new_language: Option<Arc<Language>>,
3981 },
3982 Notification(String),
3983 RefreshInlayHints {
3984 server_id: LanguageServerId,
3985 request_id: Option<usize>,
3986 },
3987 RefreshSemanticTokens {
3988 server_id: LanguageServerId,
3989 request_id: Option<usize>,
3990 },
3991 RefreshCodeLens,
3992 DiagnosticsUpdated {
3993 server_id: LanguageServerId,
3994 paths: Vec<ProjectPath>,
3995 },
3996 DiskBasedDiagnosticsStarted {
3997 language_server_id: LanguageServerId,
3998 },
3999 DiskBasedDiagnosticsFinished {
4000 language_server_id: LanguageServerId,
4001 },
4002 SnippetEdit {
4003 buffer_id: BufferId,
4004 edits: Vec<(lsp::Range, Snippet)>,
4005 most_recent_edit: clock::Lamport,
4006 },
4007 WorkspaceEditApplied(ProjectTransaction),
4008}
4009
4010#[derive(Clone, Debug, Serialize)]
4011pub struct LanguageServerStatus {
4012 pub name: LanguageServerName,
4013 pub server_version: Option<SharedString>,
4014 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4015 pub has_pending_diagnostic_updates: bool,
4016 pub progress_tokens: HashSet<ProgressToken>,
4017 pub worktree: Option<WorktreeId>,
4018 pub binary: Option<LanguageServerBinary>,
4019 pub configuration: Option<Value>,
4020 pub workspace_folders: BTreeSet<Uri>,
4021 pub process_id: Option<u32>,
4022}
4023
4024#[derive(Clone, Debug)]
4025struct CoreSymbol {
4026 pub language_server_name: LanguageServerName,
4027 pub source_worktree_id: WorktreeId,
4028 pub source_language_server_id: LanguageServerId,
4029 pub path: SymbolLocation,
4030 pub name: String,
4031 pub kind: lsp::SymbolKind,
4032 pub range: Range<Unclipped<PointUtf16>>,
4033 pub container_name: Option<String>,
4034}
4035
4036#[derive(Clone, Debug, PartialEq, Eq)]
4037pub enum SymbolLocation {
4038 InProject(ProjectPath),
4039 OutsideProject {
4040 abs_path: Arc<Path>,
4041 signature: [u8; 32],
4042 },
4043}
4044
4045impl SymbolLocation {
4046 fn file_name(&self) -> Option<&str> {
4047 match self {
4048 Self::InProject(path) => path.path.file_name(),
4049 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4050 }
4051 }
4052}
4053
4054impl LspStore {
4055 pub fn init(client: &AnyProtoClient) {
4056 client.add_entity_request_handler(Self::handle_lsp_query);
4057 client.add_entity_message_handler(Self::handle_lsp_query_response);
4058 client.add_entity_request_handler(Self::handle_restart_language_servers);
4059 client.add_entity_request_handler(Self::handle_stop_language_servers);
4060 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4061 client.add_entity_message_handler(Self::handle_start_language_server);
4062 client.add_entity_message_handler(Self::handle_update_language_server);
4063 client.add_entity_message_handler(Self::handle_language_server_log);
4064 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4065 client.add_entity_request_handler(Self::handle_format_buffers);
4066 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4067 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4068 client.add_entity_request_handler(Self::handle_apply_code_action);
4069 client.add_entity_request_handler(Self::handle_get_project_symbols);
4070 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4071 client.add_entity_request_handler(Self::handle_get_color_presentation);
4072 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4073 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4074 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4075 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4076 client.add_entity_request_handler(Self::handle_on_type_formatting);
4077 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4078 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4079 client.add_entity_request_handler(Self::handle_rename_project_entry);
4080 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4081 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4082 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4083 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4084 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4085 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4086 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4087
4088 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4089 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4090 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4091 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4092 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4093 client.add_entity_request_handler(
4094 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4095 );
4096 client.add_entity_request_handler(
4097 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4098 );
4099 client.add_entity_request_handler(
4100 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4101 );
4102 }
4103
4104 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4105 match &self.mode {
4106 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4107 _ => None,
4108 }
4109 }
4110
4111 pub fn as_local(&self) -> Option<&LocalLspStore> {
4112 match &self.mode {
4113 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4114 _ => None,
4115 }
4116 }
4117
4118 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4119 match &mut self.mode {
4120 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4121 _ => None,
4122 }
4123 }
4124
4125 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4126 match &self.mode {
4127 LspStoreMode::Remote(RemoteLspStore {
4128 upstream_client: Some(upstream_client),
4129 upstream_project_id,
4130 ..
4131 }) => Some((upstream_client.clone(), *upstream_project_id)),
4132
4133 LspStoreMode::Remote(RemoteLspStore {
4134 upstream_client: None,
4135 ..
4136 }) => None,
4137 LspStoreMode::Local(_) => None,
4138 }
4139 }
4140
4141 pub fn new_local(
4142 buffer_store: Entity<BufferStore>,
4143 worktree_store: Entity<WorktreeStore>,
4144 prettier_store: Entity<PrettierStore>,
4145 toolchain_store: Entity<LocalToolchainStore>,
4146 environment: Entity<ProjectEnvironment>,
4147 manifest_tree: Entity<ManifestTree>,
4148 languages: Arc<LanguageRegistry>,
4149 http_client: Arc<dyn HttpClient>,
4150 fs: Arc<dyn Fs>,
4151 cx: &mut Context<Self>,
4152 ) -> Self {
4153 let yarn = YarnPathStore::new(fs.clone(), cx);
4154 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4155 .detach();
4156 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4157 .detach();
4158 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4159 .detach();
4160 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4161 .detach();
4162 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4163 .detach();
4164 subscribe_to_binary_statuses(&languages, cx).detach();
4165
4166 let _maintain_workspace_config = {
4167 let (sender, receiver) = watch::channel();
4168 (Self::maintain_workspace_config(receiver, cx), sender)
4169 };
4170
4171 Self {
4172 mode: LspStoreMode::Local(LocalLspStore {
4173 weak: cx.weak_entity(),
4174 worktree_store: worktree_store.clone(),
4175
4176 supplementary_language_servers: Default::default(),
4177 languages: languages.clone(),
4178 language_server_ids: Default::default(),
4179 language_servers: Default::default(),
4180 last_workspace_edits_by_language_server: Default::default(),
4181 language_server_watched_paths: Default::default(),
4182 language_server_paths_watched_for_rename: Default::default(),
4183 language_server_dynamic_registrations: Default::default(),
4184 buffers_being_formatted: Default::default(),
4185 buffers_to_refresh_hash_set: HashSet::default(),
4186 buffers_to_refresh_queue: VecDeque::new(),
4187 _background_diagnostics_worker: Task::ready(()).shared(),
4188 buffer_snapshots: Default::default(),
4189 prettier_store,
4190 environment,
4191 http_client,
4192 fs,
4193 yarn,
4194 next_diagnostic_group_id: Default::default(),
4195 diagnostics: Default::default(),
4196 _subscription: cx.on_app_quit(|this, _| {
4197 this.as_local_mut()
4198 .unwrap()
4199 .shutdown_language_servers_on_quit()
4200 }),
4201 lsp_tree: LanguageServerTree::new(
4202 manifest_tree,
4203 languages.clone(),
4204 toolchain_store.clone(),
4205 ),
4206 toolchain_store,
4207 registered_buffers: HashMap::default(),
4208 buffers_opened_in_servers: HashMap::default(),
4209 buffer_pull_diagnostics_result_ids: HashMap::default(),
4210 workspace_pull_diagnostics_result_ids: HashMap::default(),
4211 restricted_worktrees_tasks: HashMap::default(),
4212 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4213 .manifest_file_names(),
4214 }),
4215 last_formatting_failure: None,
4216 downstream_client: None,
4217 buffer_store,
4218 worktree_store,
4219 languages: languages.clone(),
4220 language_server_statuses: Default::default(),
4221 nonce: StdRng::from_os_rng().random(),
4222 diagnostic_summaries: HashMap::default(),
4223 lsp_server_capabilities: HashMap::default(),
4224 semantic_token_config: SemanticTokenConfig::new(cx),
4225 lsp_data: HashMap::default(),
4226 next_hint_id: Arc::default(),
4227 active_entry: None,
4228 _maintain_workspace_config,
4229 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4230 }
4231 }
4232
4233 fn send_lsp_proto_request<R: LspCommand>(
4234 &self,
4235 buffer: Entity<Buffer>,
4236 client: AnyProtoClient,
4237 upstream_project_id: u64,
4238 request: R,
4239 cx: &mut Context<LspStore>,
4240 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4241 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4242 return Task::ready(Ok(R::Response::default()));
4243 }
4244 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4245 cx.spawn(async move |this, cx| {
4246 let response = client.request(message).await?;
4247 let this = this.upgrade().context("project dropped")?;
4248 request
4249 .response_from_proto(response, this, buffer, cx.clone())
4250 .await
4251 })
4252 }
4253
4254 pub(super) fn new_remote(
4255 buffer_store: Entity<BufferStore>,
4256 worktree_store: Entity<WorktreeStore>,
4257 languages: Arc<LanguageRegistry>,
4258 upstream_client: AnyProtoClient,
4259 project_id: u64,
4260 cx: &mut Context<Self>,
4261 ) -> Self {
4262 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4263 .detach();
4264 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4265 .detach();
4266 subscribe_to_binary_statuses(&languages, cx).detach();
4267 let _maintain_workspace_config = {
4268 let (sender, receiver) = watch::channel();
4269 (Self::maintain_workspace_config(receiver, cx), sender)
4270 };
4271 Self {
4272 mode: LspStoreMode::Remote(RemoteLspStore {
4273 upstream_client: Some(upstream_client),
4274 upstream_project_id: project_id,
4275 }),
4276 downstream_client: None,
4277 last_formatting_failure: None,
4278 buffer_store,
4279 worktree_store,
4280 languages: languages.clone(),
4281 language_server_statuses: Default::default(),
4282 nonce: StdRng::from_os_rng().random(),
4283 diagnostic_summaries: HashMap::default(),
4284 lsp_server_capabilities: HashMap::default(),
4285 semantic_token_config: SemanticTokenConfig::new(cx),
4286 next_hint_id: Arc::default(),
4287 lsp_data: HashMap::default(),
4288 active_entry: None,
4289
4290 _maintain_workspace_config,
4291 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4292 }
4293 }
4294
4295 fn on_buffer_store_event(
4296 &mut self,
4297 _: Entity<BufferStore>,
4298 event: &BufferStoreEvent,
4299 cx: &mut Context<Self>,
4300 ) {
4301 match event {
4302 BufferStoreEvent::BufferAdded(buffer) => {
4303 self.on_buffer_added(buffer, cx).log_err();
4304 }
4305 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4306 let buffer_id = buffer.read(cx).remote_id();
4307 if let Some(local) = self.as_local_mut()
4308 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4309 {
4310 local.reset_buffer(buffer, old_file, cx);
4311
4312 if local.registered_buffers.contains_key(&buffer_id) {
4313 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4314 }
4315 }
4316
4317 self.detect_language_for_buffer(buffer, cx);
4318 if let Some(local) = self.as_local_mut() {
4319 local.initialize_buffer(buffer, cx);
4320 if local.registered_buffers.contains_key(&buffer_id) {
4321 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4322 }
4323 }
4324 }
4325 _ => {}
4326 }
4327 }
4328
4329 fn on_worktree_store_event(
4330 &mut self,
4331 _: Entity<WorktreeStore>,
4332 event: &WorktreeStoreEvent,
4333 cx: &mut Context<Self>,
4334 ) {
4335 match event {
4336 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4337 if !worktree.read(cx).is_local() {
4338 return;
4339 }
4340 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4341 worktree::Event::UpdatedEntries(changes) => {
4342 this.update_local_worktree_language_servers(&worktree, changes, cx);
4343 }
4344 worktree::Event::UpdatedGitRepositories(_)
4345 | worktree::Event::DeletedEntry(_) => {}
4346 })
4347 .detach()
4348 }
4349 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4350 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4351 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4352 }
4353 WorktreeStoreEvent::WorktreeReleased(..)
4354 | WorktreeStoreEvent::WorktreeOrderChanged
4355 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4356 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4357 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4358 }
4359 }
4360
4361 fn on_prettier_store_event(
4362 &mut self,
4363 _: Entity<PrettierStore>,
4364 event: &PrettierStoreEvent,
4365 cx: &mut Context<Self>,
4366 ) {
4367 match event {
4368 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4369 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4370 }
4371 PrettierStoreEvent::LanguageServerAdded {
4372 new_server_id,
4373 name,
4374 prettier_server,
4375 } => {
4376 self.register_supplementary_language_server(
4377 *new_server_id,
4378 name.clone(),
4379 prettier_server.clone(),
4380 cx,
4381 );
4382 }
4383 }
4384 }
4385
4386 fn on_toolchain_store_event(
4387 &mut self,
4388 _: Entity<LocalToolchainStore>,
4389 event: &ToolchainStoreEvent,
4390 _: &mut Context<Self>,
4391 ) {
4392 if let ToolchainStoreEvent::ToolchainActivated = event {
4393 self.request_workspace_config_refresh()
4394 }
4395 }
4396
4397 fn request_workspace_config_refresh(&mut self) {
4398 *self._maintain_workspace_config.1.borrow_mut() = ();
4399 }
4400
4401 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4402 self.as_local().map(|local| local.prettier_store.clone())
4403 }
4404
4405 fn on_buffer_event(
4406 &mut self,
4407 buffer: Entity<Buffer>,
4408 event: &language::BufferEvent,
4409 cx: &mut Context<Self>,
4410 ) {
4411 match event {
4412 language::BufferEvent::Edited => {
4413 self.on_buffer_edited(buffer, cx);
4414 }
4415
4416 language::BufferEvent::Saved => {
4417 self.on_buffer_saved(buffer, cx);
4418 }
4419
4420 _ => {}
4421 }
4422 }
4423
4424 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4425 buffer
4426 .read(cx)
4427 .set_language_registry(self.languages.clone());
4428
4429 cx.subscribe(buffer, |this, buffer, event, cx| {
4430 this.on_buffer_event(buffer, event, cx);
4431 })
4432 .detach();
4433
4434 self.detect_language_for_buffer(buffer, cx);
4435 if let Some(local) = self.as_local_mut() {
4436 local.initialize_buffer(buffer, cx);
4437 }
4438
4439 Ok(())
4440 }
4441
4442 pub fn refresh_background_diagnostics_for_buffers(
4443 &mut self,
4444 buffers: HashSet<BufferId>,
4445 cx: &mut Context<Self>,
4446 ) -> Shared<Task<()>> {
4447 let Some(local) = self.as_local_mut() else {
4448 return Task::ready(()).shared();
4449 };
4450 for buffer in buffers {
4451 if local.buffers_to_refresh_hash_set.insert(buffer) {
4452 local.buffers_to_refresh_queue.push_back(buffer);
4453 if local.buffers_to_refresh_queue.len() == 1 {
4454 local._background_diagnostics_worker =
4455 Self::background_diagnostics_worker(cx).shared();
4456 }
4457 }
4458 }
4459
4460 local._background_diagnostics_worker.clone()
4461 }
4462
4463 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4464 let buffer_store = self.buffer_store.clone();
4465 let local = self.as_local_mut()?;
4466 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4467 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4468 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4469 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4470 }
4471 }
4472 None
4473 }
4474
4475 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4476 cx.spawn(async move |this, cx| {
4477 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4478 task.await.log_err();
4479 }
4480 })
4481 }
4482
4483 pub(crate) fn register_buffer_with_language_servers(
4484 &mut self,
4485 buffer: &Entity<Buffer>,
4486 only_register_servers: HashSet<LanguageServerSelector>,
4487 ignore_refcounts: bool,
4488 cx: &mut Context<Self>,
4489 ) -> OpenLspBufferHandle {
4490 let buffer_id = buffer.read(cx).remote_id();
4491 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4492 if let Some(local) = self.as_local_mut() {
4493 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4494 if !ignore_refcounts {
4495 *refcount += 1;
4496 }
4497
4498 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4499 // 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
4500 // 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
4501 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4502 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4503 return handle;
4504 };
4505 if !file.is_local() {
4506 return handle;
4507 }
4508
4509 if ignore_refcounts || *refcount == 1 {
4510 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4511 }
4512 if !ignore_refcounts {
4513 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4514 let refcount = {
4515 let local = lsp_store.as_local_mut().unwrap();
4516 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4517 debug_panic!("bad refcounting");
4518 return;
4519 };
4520
4521 *refcount -= 1;
4522 *refcount
4523 };
4524 if refcount == 0 {
4525 lsp_store.lsp_data.remove(&buffer_id);
4526 let local = lsp_store.as_local_mut().unwrap();
4527 local.registered_buffers.remove(&buffer_id);
4528
4529 local.buffers_opened_in_servers.remove(&buffer_id);
4530 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4531 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4532
4533 let buffer_abs_path = file.abs_path(cx);
4534 for (_, buffer_pull_diagnostics_result_ids) in
4535 &mut local.buffer_pull_diagnostics_result_ids
4536 {
4537 buffer_pull_diagnostics_result_ids.retain(
4538 |_, buffer_result_ids| {
4539 buffer_result_ids.remove(&buffer_abs_path);
4540 !buffer_result_ids.is_empty()
4541 },
4542 );
4543 }
4544
4545 let diagnostic_updates = local
4546 .language_servers
4547 .keys()
4548 .cloned()
4549 .map(|server_id| DocumentDiagnosticsUpdate {
4550 diagnostics: DocumentDiagnostics {
4551 document_abs_path: buffer_abs_path.clone(),
4552 version: None,
4553 diagnostics: Vec::new(),
4554 },
4555 result_id: None,
4556 registration_id: None,
4557 server_id,
4558 disk_based_sources: Cow::Borrowed(&[]),
4559 })
4560 .collect::<Vec<_>>();
4561
4562 lsp_store
4563 .merge_diagnostic_entries(
4564 diagnostic_updates,
4565 |_, diagnostic, _| {
4566 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4567 },
4568 cx,
4569 )
4570 .context("Clearing diagnostics for the closed buffer")
4571 .log_err();
4572 }
4573 }
4574 })
4575 .detach();
4576 }
4577 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4578 let buffer_id = buffer.read(cx).remote_id().to_proto();
4579 cx.background_spawn(async move {
4580 upstream_client
4581 .request(proto::RegisterBufferWithLanguageServers {
4582 project_id: upstream_project_id,
4583 buffer_id,
4584 only_servers: only_register_servers
4585 .into_iter()
4586 .map(|selector| {
4587 let selector = match selector {
4588 LanguageServerSelector::Id(language_server_id) => {
4589 proto::language_server_selector::Selector::ServerId(
4590 language_server_id.to_proto(),
4591 )
4592 }
4593 LanguageServerSelector::Name(language_server_name) => {
4594 proto::language_server_selector::Selector::Name(
4595 language_server_name.to_string(),
4596 )
4597 }
4598 };
4599 proto::LanguageServerSelector {
4600 selector: Some(selector),
4601 }
4602 })
4603 .collect(),
4604 })
4605 .await
4606 })
4607 .detach();
4608 } else {
4609 // Our remote connection got closed
4610 }
4611 handle
4612 }
4613
4614 fn maintain_buffer_languages(
4615 languages: Arc<LanguageRegistry>,
4616 cx: &mut Context<Self>,
4617 ) -> Task<()> {
4618 let mut subscription = languages.subscribe();
4619 let mut prev_reload_count = languages.reload_count();
4620 cx.spawn(async move |this, cx| {
4621 while let Some(()) = subscription.next().await {
4622 if let Some(this) = this.upgrade() {
4623 // If the language registry has been reloaded, then remove and
4624 // re-assign the languages on all open buffers.
4625 let reload_count = languages.reload_count();
4626 if reload_count > prev_reload_count {
4627 prev_reload_count = reload_count;
4628 this.update(cx, |this, cx| {
4629 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4630 for buffer in buffer_store.buffers() {
4631 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4632 {
4633 buffer.update(cx, |buffer, cx| {
4634 buffer.set_language_async(None, cx)
4635 });
4636 if let Some(local) = this.as_local_mut() {
4637 local.reset_buffer(&buffer, &f, cx);
4638
4639 if local
4640 .registered_buffers
4641 .contains_key(&buffer.read(cx).remote_id())
4642 && let Some(file_url) =
4643 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4644 {
4645 local.unregister_buffer_from_language_servers(
4646 &buffer, &file_url, cx,
4647 );
4648 }
4649 }
4650 }
4651 }
4652 });
4653 });
4654 }
4655
4656 this.update(cx, |this, cx| {
4657 let mut plain_text_buffers = Vec::new();
4658 let mut buffers_with_unknown_injections = Vec::new();
4659 for handle in this.buffer_store.read(cx).buffers() {
4660 let buffer = handle.read(cx);
4661 if buffer.language().is_none()
4662 || buffer.language() == Some(&*language::PLAIN_TEXT)
4663 {
4664 plain_text_buffers.push(handle);
4665 } else if buffer.contains_unknown_injections() {
4666 buffers_with_unknown_injections.push(handle);
4667 }
4668 }
4669
4670 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4671 // and reused later in the invisible worktrees.
4672 plain_text_buffers.sort_by_key(|buffer| {
4673 Reverse(
4674 File::from_dyn(buffer.read(cx).file())
4675 .map(|file| file.worktree.read(cx).is_visible()),
4676 )
4677 });
4678
4679 for buffer in plain_text_buffers {
4680 this.detect_language_for_buffer(&buffer, cx);
4681 if let Some(local) = this.as_local_mut() {
4682 local.initialize_buffer(&buffer, cx);
4683 if local
4684 .registered_buffers
4685 .contains_key(&buffer.read(cx).remote_id())
4686 {
4687 local.register_buffer_with_language_servers(
4688 &buffer,
4689 HashSet::default(),
4690 cx,
4691 );
4692 }
4693 }
4694 }
4695
4696 for buffer in buffers_with_unknown_injections {
4697 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4698 }
4699 });
4700 }
4701 }
4702 })
4703 }
4704
4705 fn detect_language_for_buffer(
4706 &mut self,
4707 buffer_handle: &Entity<Buffer>,
4708 cx: &mut Context<Self>,
4709 ) -> Option<language::AvailableLanguage> {
4710 // If the buffer has a language, set it and start the language server if we haven't already.
4711 let buffer = buffer_handle.read(cx);
4712 let file = buffer.file()?;
4713
4714 let content = buffer.as_rope();
4715 let available_language = self.languages.language_for_file(file, Some(content), cx);
4716 if let Some(available_language) = &available_language {
4717 if let Some(Ok(Ok(new_language))) = self
4718 .languages
4719 .load_language(available_language)
4720 .now_or_never()
4721 {
4722 self.set_language_for_buffer(buffer_handle, new_language, cx);
4723 }
4724 } else {
4725 cx.emit(LspStoreEvent::LanguageDetected {
4726 buffer: buffer_handle.clone(),
4727 new_language: None,
4728 });
4729 }
4730
4731 available_language
4732 }
4733
4734 pub(crate) fn set_language_for_buffer(
4735 &mut self,
4736 buffer_entity: &Entity<Buffer>,
4737 new_language: Arc<Language>,
4738 cx: &mut Context<Self>,
4739 ) {
4740 let buffer = buffer_entity.read(cx);
4741 let buffer_file = buffer.file().cloned();
4742 let buffer_id = buffer.remote_id();
4743 if let Some(local_store) = self.as_local_mut()
4744 && local_store.registered_buffers.contains_key(&buffer_id)
4745 && let Some(abs_path) =
4746 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4747 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4748 {
4749 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4750 }
4751 buffer_entity.update(cx, |buffer, cx| {
4752 if buffer
4753 .language()
4754 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4755 {
4756 buffer.set_language_async(Some(new_language.clone()), cx);
4757 }
4758 });
4759
4760 let settings =
4761 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4762 let buffer_file = File::from_dyn(buffer_file.as_ref());
4763
4764 let worktree_id = if let Some(file) = buffer_file {
4765 let worktree = file.worktree.clone();
4766
4767 if let Some(local) = self.as_local_mut()
4768 && local.registered_buffers.contains_key(&buffer_id)
4769 {
4770 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4771 }
4772 Some(worktree.read(cx).id())
4773 } else {
4774 None
4775 };
4776
4777 if settings.prettier.allowed
4778 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4779 {
4780 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4781 if let Some(prettier_store) = prettier_store {
4782 prettier_store.update(cx, |prettier_store, cx| {
4783 prettier_store.install_default_prettier(
4784 worktree_id,
4785 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4786 cx,
4787 )
4788 })
4789 }
4790 }
4791
4792 cx.emit(LspStoreEvent::LanguageDetected {
4793 buffer: buffer_entity.clone(),
4794 new_language: Some(new_language),
4795 })
4796 }
4797
4798 pub fn buffer_store(&self) -> Entity<BufferStore> {
4799 self.buffer_store.clone()
4800 }
4801
4802 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4803 self.active_entry = active_entry;
4804 }
4805
4806 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4807 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4808 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4809 {
4810 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4811 summaries
4812 .iter()
4813 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4814 });
4815 if let Some(summary) = summaries.next() {
4816 client
4817 .send(proto::UpdateDiagnosticSummary {
4818 project_id: downstream_project_id,
4819 worktree_id: worktree.id().to_proto(),
4820 summary: Some(summary),
4821 more_summaries: summaries.collect(),
4822 })
4823 .log_err();
4824 }
4825 }
4826 }
4827
4828 fn is_capable_for_proto_request<R>(
4829 &self,
4830 buffer: &Entity<Buffer>,
4831 request: &R,
4832 cx: &App,
4833 ) -> bool
4834 where
4835 R: LspCommand,
4836 {
4837 self.check_if_capable_for_proto_request(
4838 buffer,
4839 |capabilities| {
4840 request.check_capabilities(AdapterServerCapabilities {
4841 server_capabilities: capabilities.clone(),
4842 code_action_kinds: None,
4843 })
4844 },
4845 cx,
4846 )
4847 }
4848
4849 fn check_if_capable_for_proto_request<F>(
4850 &self,
4851 buffer: &Entity<Buffer>,
4852 check: F,
4853 cx: &App,
4854 ) -> bool
4855 where
4856 F: FnMut(&lsp::ServerCapabilities) -> bool,
4857 {
4858 let Some(language) = buffer.read(cx).language().cloned() else {
4859 return false;
4860 };
4861 let registered_language_servers = self
4862 .languages
4863 .lsp_adapters(&language.name())
4864 .into_iter()
4865 .map(|lsp_adapter| lsp_adapter.name())
4866 .collect::<HashSet<_>>();
4867 self.language_server_statuses
4868 .iter()
4869 .filter_map(|(server_id, server_status)| {
4870 // Include servers that are either registered for this language OR
4871 // available to be loaded (for SSH remote mode where adapters like
4872 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4873 // but only loaded on the server side)
4874 let is_relevant = registered_language_servers.contains(&server_status.name)
4875 || self.languages.is_lsp_adapter_available(&server_status.name);
4876 is_relevant.then_some(server_id)
4877 })
4878 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4879 .any(check)
4880 }
4881
4882 fn all_capable_for_proto_request<F>(
4883 &self,
4884 buffer: &Entity<Buffer>,
4885 mut check: F,
4886 cx: &App,
4887 ) -> Vec<lsp::LanguageServerId>
4888 where
4889 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4890 {
4891 let Some(language) = buffer.read(cx).language().cloned() else {
4892 return Vec::default();
4893 };
4894 let registered_language_servers = self
4895 .languages
4896 .lsp_adapters(&language.name())
4897 .into_iter()
4898 .map(|lsp_adapter| lsp_adapter.name())
4899 .collect::<HashSet<_>>();
4900 self.language_server_statuses
4901 .iter()
4902 .filter_map(|(server_id, server_status)| {
4903 // Include servers that are either registered for this language OR
4904 // available to be loaded (for SSH remote mode where adapters like
4905 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4906 // but only loaded on the server side)
4907 let is_relevant = registered_language_servers.contains(&server_status.name)
4908 || self.languages.is_lsp_adapter_available(&server_status.name);
4909 is_relevant.then_some((server_id, &server_status.name))
4910 })
4911 .filter_map(|(server_id, server_name)| {
4912 self.lsp_server_capabilities
4913 .get(server_id)
4914 .map(|c| (server_id, server_name, c))
4915 })
4916 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4917 .map(|(server_id, _, _)| *server_id)
4918 .collect()
4919 }
4920
4921 pub fn request_lsp<R>(
4922 &mut self,
4923 buffer: Entity<Buffer>,
4924 server: LanguageServerToQuery,
4925 request: R,
4926 cx: &mut Context<Self>,
4927 ) -> Task<Result<R::Response>>
4928 where
4929 R: LspCommand,
4930 <R::LspRequest as lsp::request::Request>::Result: Send,
4931 <R::LspRequest as lsp::request::Request>::Params: Send,
4932 {
4933 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4934 return self.send_lsp_proto_request(
4935 buffer,
4936 upstream_client,
4937 upstream_project_id,
4938 request,
4939 cx,
4940 );
4941 }
4942
4943 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4944 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4945 local
4946 .language_servers_for_buffer(buffer, cx)
4947 .find(|(_, server)| {
4948 request.check_capabilities(server.adapter_server_capabilities())
4949 })
4950 .map(|(_, server)| server.clone())
4951 }),
4952 LanguageServerToQuery::Other(id) => self
4953 .language_server_for_local_buffer(buffer, id, cx)
4954 .and_then(|(_, server)| {
4955 request
4956 .check_capabilities(server.adapter_server_capabilities())
4957 .then(|| Arc::clone(server))
4958 }),
4959 }) else {
4960 return Task::ready(Ok(Default::default()));
4961 };
4962
4963 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4964
4965 let Some(file) = file else {
4966 return Task::ready(Ok(Default::default()));
4967 };
4968
4969 let lsp_params = match request.to_lsp_params_or_response(
4970 &file.abs_path(cx),
4971 buffer.read(cx),
4972 &language_server,
4973 cx,
4974 ) {
4975 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4976 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4977 Err(err) => {
4978 let message = format!(
4979 "{} via {} failed: {}",
4980 request.display_name(),
4981 language_server.name(),
4982 err
4983 );
4984 // rust-analyzer likes to error with this when its still loading up
4985 if !message.ends_with("content modified") {
4986 log::warn!("{message}");
4987 }
4988 return Task::ready(Err(anyhow!(message)));
4989 }
4990 };
4991
4992 let status = request.status();
4993 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4994 return Task::ready(Ok(Default::default()));
4995 }
4996
4997 let request_timeout = ProjectSettings::get_global(cx)
4998 .global_lsp_settings
4999 .get_request_timeout();
5000
5001 cx.spawn(async move |this, cx| {
5002 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5003
5004 let id = lsp_request.id();
5005 let _cleanup = if status.is_some() {
5006 cx.update(|cx| {
5007 this.update(cx, |this, cx| {
5008 this.on_lsp_work_start(
5009 language_server.server_id(),
5010 ProgressToken::Number(id),
5011 LanguageServerProgress {
5012 is_disk_based_diagnostics_progress: false,
5013 is_cancellable: false,
5014 title: None,
5015 message: status.clone(),
5016 percentage: None,
5017 last_update_at: cx.background_executor().now(),
5018 },
5019 cx,
5020 );
5021 })
5022 })
5023 .log_err();
5024
5025 Some(defer(|| {
5026 cx.update(|cx| {
5027 this.update(cx, |this, cx| {
5028 this.on_lsp_work_end(
5029 language_server.server_id(),
5030 ProgressToken::Number(id),
5031 cx,
5032 );
5033 })
5034 })
5035 .log_err();
5036 }))
5037 } else {
5038 None
5039 };
5040
5041 let result = lsp_request.await.into_response();
5042
5043 let response = result.map_err(|err| {
5044 let message = format!(
5045 "{} via {} failed: {}",
5046 request.display_name(),
5047 language_server.name(),
5048 err
5049 );
5050 // rust-analyzer likes to error with this when its still loading up
5051 if !message.ends_with("content modified") {
5052 log::warn!("{message}");
5053 }
5054 anyhow::anyhow!(message)
5055 })?;
5056
5057 request
5058 .response_from_lsp(
5059 response,
5060 this.upgrade().context("no app context")?,
5061 buffer,
5062 language_server.server_id(),
5063 cx.clone(),
5064 )
5065 .await
5066 })
5067 }
5068
5069 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5070 let mut language_formatters_to_check = Vec::new();
5071 for buffer in self.buffer_store.read(cx).buffers() {
5072 let buffer = buffer.read(cx);
5073 let buffer_file = File::from_dyn(buffer.file());
5074 let buffer_language = buffer.language();
5075 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5076 if buffer_language.is_some() {
5077 language_formatters_to_check.push((
5078 buffer_file.map(|f| f.worktree_id(cx)),
5079 settings.into_owned(),
5080 ));
5081 }
5082 }
5083
5084 self.request_workspace_config_refresh();
5085
5086 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5087 prettier_store.update(cx, |prettier_store, cx| {
5088 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5089 })
5090 }
5091
5092 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5093 .global_lsp_settings
5094 .semantic_token_rules
5095 .clone();
5096 self.semantic_token_config
5097 .update_rules(new_semantic_token_rules);
5098
5099 let new_global_semantic_tokens_mode =
5100 all_language_settings(None, cx).defaults.semantic_tokens;
5101 if self
5102 .semantic_token_config
5103 .update_global_mode(new_global_semantic_tokens_mode)
5104 {
5105 self.restart_all_language_servers(cx);
5106 }
5107
5108 cx.notify();
5109 }
5110
5111 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5112 let buffer_store = self.buffer_store.clone();
5113 let Some(local) = self.as_local_mut() else {
5114 return;
5115 };
5116 let mut adapters = BTreeMap::default();
5117 let get_adapter = {
5118 let languages = local.languages.clone();
5119 let environment = local.environment.clone();
5120 let weak = local.weak.clone();
5121 let worktree_store = local.worktree_store.clone();
5122 let http_client = local.http_client.clone();
5123 let fs = local.fs.clone();
5124 move |worktree_id, cx: &mut App| {
5125 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5126 Some(LocalLspAdapterDelegate::new(
5127 languages.clone(),
5128 &environment,
5129 weak.clone(),
5130 &worktree,
5131 http_client.clone(),
5132 fs.clone(),
5133 cx,
5134 ))
5135 }
5136 };
5137
5138 let mut messages_to_report = Vec::new();
5139 let (new_tree, to_stop) = {
5140 let mut rebase = local.lsp_tree.rebase();
5141 let buffers = buffer_store
5142 .read(cx)
5143 .buffers()
5144 .filter_map(|buffer| {
5145 let raw_buffer = buffer.read(cx);
5146 if !local
5147 .registered_buffers
5148 .contains_key(&raw_buffer.remote_id())
5149 {
5150 return None;
5151 }
5152 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5153 let language = raw_buffer.language().cloned()?;
5154 Some((file, language, raw_buffer.remote_id()))
5155 })
5156 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5157 for (file, language, buffer_id) in buffers {
5158 let worktree_id = file.worktree_id(cx);
5159 let Some(worktree) = local
5160 .worktree_store
5161 .read(cx)
5162 .worktree_for_id(worktree_id, cx)
5163 else {
5164 continue;
5165 };
5166
5167 if let Some((_, apply)) = local.reuse_existing_language_server(
5168 rebase.server_tree(),
5169 &worktree,
5170 &language.name(),
5171 cx,
5172 ) {
5173 (apply)(rebase.server_tree());
5174 } else if let Some(lsp_delegate) = adapters
5175 .entry(worktree_id)
5176 .or_insert_with(|| get_adapter(worktree_id, cx))
5177 .clone()
5178 {
5179 let delegate =
5180 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5181 let path = file
5182 .path()
5183 .parent()
5184 .map(Arc::from)
5185 .unwrap_or_else(|| file.path().clone());
5186 let worktree_path = ProjectPath { worktree_id, path };
5187 let abs_path = file.abs_path(cx);
5188 let nodes = rebase
5189 .walk(
5190 worktree_path,
5191 language.name(),
5192 language.manifest(),
5193 delegate.clone(),
5194 cx,
5195 )
5196 .collect::<Vec<_>>();
5197 for node in nodes {
5198 let server_id = node.server_id_or_init(|disposition| {
5199 let path = &disposition.path;
5200 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5201 let key = LanguageServerSeed {
5202 worktree_id,
5203 name: disposition.server_name.clone(),
5204 settings: LanguageServerSeedSettings {
5205 binary: disposition.settings.binary.clone(),
5206 initialization_options: disposition
5207 .settings
5208 .initialization_options
5209 .clone(),
5210 },
5211 toolchain: local.toolchain_store.read(cx).active_toolchain(
5212 path.worktree_id,
5213 &path.path,
5214 language.name(),
5215 ),
5216 };
5217 local.language_server_ids.remove(&key);
5218
5219 let server_id = local.get_or_insert_language_server(
5220 &worktree,
5221 lsp_delegate.clone(),
5222 disposition,
5223 &language.name(),
5224 cx,
5225 );
5226 if let Some(state) = local.language_servers.get(&server_id)
5227 && let Ok(uri) = uri
5228 {
5229 state.add_workspace_folder(uri);
5230 };
5231 server_id
5232 });
5233
5234 if let Some(language_server_id) = server_id {
5235 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5236 language_server_id,
5237 name: node.name(),
5238 message:
5239 proto::update_language_server::Variant::RegisteredForBuffer(
5240 proto::RegisteredForBuffer {
5241 buffer_abs_path: abs_path
5242 .to_string_lossy()
5243 .into_owned(),
5244 buffer_id: buffer_id.to_proto(),
5245 },
5246 ),
5247 });
5248 }
5249 }
5250 } else {
5251 continue;
5252 }
5253 }
5254 rebase.finish()
5255 };
5256 for message in messages_to_report {
5257 cx.emit(message);
5258 }
5259 local.lsp_tree = new_tree;
5260 for (id, _) in to_stop {
5261 self.stop_local_language_server(id, cx).detach();
5262 }
5263 }
5264
5265 pub fn apply_code_action(
5266 &self,
5267 buffer_handle: Entity<Buffer>,
5268 mut action: CodeAction,
5269 push_to_history: bool,
5270 cx: &mut Context<Self>,
5271 ) -> Task<Result<ProjectTransaction>> {
5272 if let Some((upstream_client, project_id)) = self.upstream_client() {
5273 let request = proto::ApplyCodeAction {
5274 project_id,
5275 buffer_id: buffer_handle.read(cx).remote_id().into(),
5276 action: Some(Self::serialize_code_action(&action)),
5277 };
5278 let buffer_store = self.buffer_store();
5279 cx.spawn(async move |_, cx| {
5280 let response = upstream_client
5281 .request(request)
5282 .await?
5283 .transaction
5284 .context("missing transaction")?;
5285
5286 buffer_store
5287 .update(cx, |buffer_store, cx| {
5288 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5289 })
5290 .await
5291 })
5292 } else if self.mode.is_local() {
5293 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5294 let request_timeout = ProjectSettings::get_global(cx)
5295 .global_lsp_settings
5296 .get_request_timeout();
5297 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5298 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5299 }) else {
5300 return Task::ready(Ok(ProjectTransaction::default()));
5301 };
5302
5303 cx.spawn(async move |this, cx| {
5304 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5305 .await
5306 .context("resolving a code action")?;
5307 if let Some(edit) = action.lsp_action.edit()
5308 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5309 return LocalLspStore::deserialize_workspace_edit(
5310 this.upgrade().context("no app present")?,
5311 edit.clone(),
5312 push_to_history,
5313
5314 lang_server.clone(),
5315 cx,
5316 )
5317 .await;
5318 }
5319
5320 let Some(command) = action.lsp_action.command() else {
5321 return Ok(ProjectTransaction::default())
5322 };
5323
5324 let server_capabilities = lang_server.capabilities();
5325 let available_commands = server_capabilities
5326 .execute_command_provider
5327 .as_ref()
5328 .map(|options| options.commands.as_slice())
5329 .unwrap_or_default();
5330
5331 if !available_commands.contains(&command.command) {
5332 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5333 return Ok(ProjectTransaction::default())
5334 }
5335
5336 let request_timeout = cx.update(|app|
5337 ProjectSettings::get_global(app)
5338 .global_lsp_settings
5339 .get_request_timeout()
5340 );
5341
5342 this.update(cx, |this, _| {
5343 this.as_local_mut()
5344 .unwrap()
5345 .last_workspace_edits_by_language_server
5346 .remove(&lang_server.server_id());
5347 })?;
5348
5349 let _result = lang_server
5350 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5351 command: command.command.clone(),
5352 arguments: command.arguments.clone().unwrap_or_default(),
5353 ..lsp::ExecuteCommandParams::default()
5354 }, request_timeout)
5355 .await.into_response()
5356 .context("execute command")?;
5357
5358 return this.update(cx, |this, _| {
5359 this.as_local_mut()
5360 .unwrap()
5361 .last_workspace_edits_by_language_server
5362 .remove(&lang_server.server_id())
5363 .unwrap_or_default()
5364 });
5365 })
5366 } else {
5367 Task::ready(Err(anyhow!("no upstream client and not local")))
5368 }
5369 }
5370
5371 pub fn apply_code_action_kind(
5372 &mut self,
5373 buffers: HashSet<Entity<Buffer>>,
5374 kind: CodeActionKind,
5375 push_to_history: bool,
5376 cx: &mut Context<Self>,
5377 ) -> Task<anyhow::Result<ProjectTransaction>> {
5378 if self.as_local().is_some() {
5379 cx.spawn(async move |lsp_store, cx| {
5380 let buffers = buffers.into_iter().collect::<Vec<_>>();
5381 let result = LocalLspStore::execute_code_action_kind_locally(
5382 lsp_store.clone(),
5383 buffers,
5384 kind,
5385 push_to_history,
5386 cx,
5387 )
5388 .await;
5389 lsp_store.update(cx, |lsp_store, _| {
5390 lsp_store.update_last_formatting_failure(&result);
5391 })?;
5392 result
5393 })
5394 } else if let Some((client, project_id)) = self.upstream_client() {
5395 let buffer_store = self.buffer_store();
5396 cx.spawn(async move |lsp_store, cx| {
5397 let result = client
5398 .request(proto::ApplyCodeActionKind {
5399 project_id,
5400 kind: kind.as_str().to_owned(),
5401 buffer_ids: buffers
5402 .iter()
5403 .map(|buffer| {
5404 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5405 })
5406 .collect(),
5407 })
5408 .await
5409 .and_then(|result| result.transaction.context("missing transaction"));
5410 lsp_store.update(cx, |lsp_store, _| {
5411 lsp_store.update_last_formatting_failure(&result);
5412 })?;
5413
5414 let transaction_response = result?;
5415 buffer_store
5416 .update(cx, |buffer_store, cx| {
5417 buffer_store.deserialize_project_transaction(
5418 transaction_response,
5419 push_to_history,
5420 cx,
5421 )
5422 })
5423 .await
5424 })
5425 } else {
5426 Task::ready(Ok(ProjectTransaction::default()))
5427 }
5428 }
5429
5430 pub fn resolved_hint(
5431 &mut self,
5432 buffer_id: BufferId,
5433 id: InlayId,
5434 cx: &mut Context<Self>,
5435 ) -> Option<ResolvedHint> {
5436 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5437
5438 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5439 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5440 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5441 let (server_id, resolve_data) = match &hint.resolve_state {
5442 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5443 ResolveState::Resolving => {
5444 return Some(ResolvedHint::Resolving(
5445 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5446 ));
5447 }
5448 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5449 };
5450
5451 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5452 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5453 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5454 id,
5455 cx.spawn(async move |lsp_store, cx| {
5456 let resolved_hint = resolve_task.await;
5457 lsp_store
5458 .update(cx, |lsp_store, _| {
5459 if let Some(old_inlay_hint) = lsp_store
5460 .lsp_data
5461 .get_mut(&buffer_id)
5462 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5463 {
5464 match resolved_hint {
5465 Ok(resolved_hint) => {
5466 *old_inlay_hint = resolved_hint;
5467 }
5468 Err(e) => {
5469 old_inlay_hint.resolve_state =
5470 ResolveState::CanResolve(server_id, resolve_data);
5471 log::error!("Inlay hint resolve failed: {e:#}");
5472 }
5473 }
5474 }
5475 })
5476 .ok();
5477 })
5478 .shared(),
5479 );
5480 debug_assert!(
5481 previous_task.is_none(),
5482 "Did not change hint's resolve state after spawning its resolve"
5483 );
5484 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5485 None
5486 }
5487
5488 pub(crate) fn linked_edits(
5489 &mut self,
5490 buffer: &Entity<Buffer>,
5491 position: Anchor,
5492 cx: &mut Context<Self>,
5493 ) -> Task<Result<Vec<Range<Anchor>>>> {
5494 let snapshot = buffer.read(cx).snapshot();
5495 let scope = snapshot.language_scope_at(position);
5496 let Some(server_id) = self
5497 .as_local()
5498 .and_then(|local| {
5499 buffer.update(cx, |buffer, cx| {
5500 local
5501 .language_servers_for_buffer(buffer, cx)
5502 .filter(|(_, server)| {
5503 LinkedEditingRange::check_server_capabilities(server.capabilities())
5504 })
5505 .filter(|(adapter, _)| {
5506 scope
5507 .as_ref()
5508 .map(|scope| scope.language_allowed(&adapter.name))
5509 .unwrap_or(true)
5510 })
5511 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5512 .next()
5513 })
5514 })
5515 .or_else(|| {
5516 self.upstream_client()
5517 .is_some()
5518 .then_some(LanguageServerToQuery::FirstCapable)
5519 })
5520 .filter(|_| {
5521 maybe!({
5522 let language = buffer.read(cx).language_at(position)?;
5523 Some(
5524 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5525 .linked_edits,
5526 )
5527 }) == Some(true)
5528 })
5529 else {
5530 return Task::ready(Ok(Vec::new()));
5531 };
5532
5533 self.request_lsp(
5534 buffer.clone(),
5535 server_id,
5536 LinkedEditingRange { position },
5537 cx,
5538 )
5539 }
5540
5541 fn apply_on_type_formatting(
5542 &mut self,
5543 buffer: Entity<Buffer>,
5544 position: Anchor,
5545 trigger: String,
5546 cx: &mut Context<Self>,
5547 ) -> Task<Result<Option<Transaction>>> {
5548 if let Some((client, project_id)) = self.upstream_client() {
5549 if !self.check_if_capable_for_proto_request(
5550 &buffer,
5551 |capabilities| {
5552 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5553 },
5554 cx,
5555 ) {
5556 return Task::ready(Ok(None));
5557 }
5558 let request = proto::OnTypeFormatting {
5559 project_id,
5560 buffer_id: buffer.read(cx).remote_id().into(),
5561 position: Some(serialize_anchor(&position)),
5562 trigger,
5563 version: serialize_version(&buffer.read(cx).version()),
5564 };
5565 cx.background_spawn(async move {
5566 client
5567 .request(request)
5568 .await?
5569 .transaction
5570 .map(language::proto::deserialize_transaction)
5571 .transpose()
5572 })
5573 } else if let Some(local) = self.as_local_mut() {
5574 let buffer_id = buffer.read(cx).remote_id();
5575 local.buffers_being_formatted.insert(buffer_id);
5576 cx.spawn(async move |this, cx| {
5577 let _cleanup = defer({
5578 let this = this.clone();
5579 let mut cx = cx.clone();
5580 move || {
5581 this.update(&mut cx, |this, _| {
5582 if let Some(local) = this.as_local_mut() {
5583 local.buffers_being_formatted.remove(&buffer_id);
5584 }
5585 })
5586 .ok();
5587 }
5588 });
5589
5590 buffer
5591 .update(cx, |buffer, _| {
5592 buffer.wait_for_edits(Some(position.timestamp))
5593 })
5594 .await?;
5595 this.update(cx, |this, cx| {
5596 let position = position.to_point_utf16(buffer.read(cx));
5597 this.on_type_format(buffer, position, trigger, false, cx)
5598 })?
5599 .await
5600 })
5601 } else {
5602 Task::ready(Err(anyhow!("No upstream client or local language server")))
5603 }
5604 }
5605
5606 pub fn on_type_format<T: ToPointUtf16>(
5607 &mut self,
5608 buffer: Entity<Buffer>,
5609 position: T,
5610 trigger: String,
5611 push_to_history: bool,
5612 cx: &mut Context<Self>,
5613 ) -> Task<Result<Option<Transaction>>> {
5614 let position = position.to_point_utf16(buffer.read(cx));
5615 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5616 }
5617
5618 fn on_type_format_impl(
5619 &mut self,
5620 buffer: Entity<Buffer>,
5621 position: PointUtf16,
5622 trigger: String,
5623 push_to_history: bool,
5624 cx: &mut Context<Self>,
5625 ) -> Task<Result<Option<Transaction>>> {
5626 let options = buffer.update(cx, |buffer, cx| {
5627 lsp_command::lsp_formatting_options(
5628 language_settings(
5629 buffer.language_at(position).map(|l| l.name()),
5630 buffer.file(),
5631 cx,
5632 )
5633 .as_ref(),
5634 )
5635 });
5636
5637 cx.spawn(async move |this, cx| {
5638 if let Some(waiter) =
5639 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5640 {
5641 waiter.await?;
5642 }
5643 cx.update(|cx| {
5644 this.update(cx, |this, cx| {
5645 this.request_lsp(
5646 buffer.clone(),
5647 LanguageServerToQuery::FirstCapable,
5648 OnTypeFormatting {
5649 position,
5650 trigger,
5651 options,
5652 push_to_history,
5653 },
5654 cx,
5655 )
5656 })
5657 })?
5658 .await
5659 })
5660 }
5661
5662 pub fn definitions(
5663 &mut self,
5664 buffer: &Entity<Buffer>,
5665 position: PointUtf16,
5666 cx: &mut Context<Self>,
5667 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5668 if let Some((upstream_client, project_id)) = self.upstream_client() {
5669 let request = GetDefinitions { position };
5670 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5671 return Task::ready(Ok(None));
5672 }
5673
5674 let request_timeout = ProjectSettings::get_global(cx)
5675 .global_lsp_settings
5676 .get_request_timeout();
5677
5678 let request_task = upstream_client.request_lsp(
5679 project_id,
5680 None,
5681 request_timeout,
5682 cx.background_executor().clone(),
5683 request.to_proto(project_id, buffer.read(cx)),
5684 );
5685 let buffer = buffer.clone();
5686 cx.spawn(async move |weak_lsp_store, cx| {
5687 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5688 return Ok(None);
5689 };
5690 let Some(responses) = request_task.await? else {
5691 return Ok(None);
5692 };
5693 let actions = join_all(responses.payload.into_iter().map(|response| {
5694 GetDefinitions { position }.response_from_proto(
5695 response.response,
5696 lsp_store.clone(),
5697 buffer.clone(),
5698 cx.clone(),
5699 )
5700 }))
5701 .await;
5702
5703 Ok(Some(
5704 actions
5705 .into_iter()
5706 .collect::<Result<Vec<Vec<_>>>>()?
5707 .into_iter()
5708 .flatten()
5709 .dedup()
5710 .collect(),
5711 ))
5712 })
5713 } else {
5714 let definitions_task = self.request_multiple_lsp_locally(
5715 buffer,
5716 Some(position),
5717 GetDefinitions { position },
5718 cx,
5719 );
5720 cx.background_spawn(async move {
5721 Ok(Some(
5722 definitions_task
5723 .await
5724 .into_iter()
5725 .flat_map(|(_, definitions)| definitions)
5726 .dedup()
5727 .collect(),
5728 ))
5729 })
5730 }
5731 }
5732
5733 pub fn declarations(
5734 &mut self,
5735 buffer: &Entity<Buffer>,
5736 position: PointUtf16,
5737 cx: &mut Context<Self>,
5738 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5739 if let Some((upstream_client, project_id)) = self.upstream_client() {
5740 let request = GetDeclarations { position };
5741 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5742 return Task::ready(Ok(None));
5743 }
5744 let request_timeout = ProjectSettings::get_global(cx)
5745 .global_lsp_settings
5746 .get_request_timeout();
5747 let request_task = upstream_client.request_lsp(
5748 project_id,
5749 None,
5750 request_timeout,
5751 cx.background_executor().clone(),
5752 request.to_proto(project_id, buffer.read(cx)),
5753 );
5754 let buffer = buffer.clone();
5755 cx.spawn(async move |weak_lsp_store, cx| {
5756 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5757 return Ok(None);
5758 };
5759 let Some(responses) = request_task.await? else {
5760 return Ok(None);
5761 };
5762 let actions = join_all(responses.payload.into_iter().map(|response| {
5763 GetDeclarations { position }.response_from_proto(
5764 response.response,
5765 lsp_store.clone(),
5766 buffer.clone(),
5767 cx.clone(),
5768 )
5769 }))
5770 .await;
5771
5772 Ok(Some(
5773 actions
5774 .into_iter()
5775 .collect::<Result<Vec<Vec<_>>>>()?
5776 .into_iter()
5777 .flatten()
5778 .dedup()
5779 .collect(),
5780 ))
5781 })
5782 } else {
5783 let declarations_task = self.request_multiple_lsp_locally(
5784 buffer,
5785 Some(position),
5786 GetDeclarations { position },
5787 cx,
5788 );
5789 cx.background_spawn(async move {
5790 Ok(Some(
5791 declarations_task
5792 .await
5793 .into_iter()
5794 .flat_map(|(_, declarations)| declarations)
5795 .dedup()
5796 .collect(),
5797 ))
5798 })
5799 }
5800 }
5801
5802 pub fn type_definitions(
5803 &mut self,
5804 buffer: &Entity<Buffer>,
5805 position: PointUtf16,
5806 cx: &mut Context<Self>,
5807 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5808 if let Some((upstream_client, project_id)) = self.upstream_client() {
5809 let request = GetTypeDefinitions { position };
5810 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5811 return Task::ready(Ok(None));
5812 }
5813 let request_timeout = ProjectSettings::get_global(cx)
5814 .global_lsp_settings
5815 .get_request_timeout();
5816 let request_task = upstream_client.request_lsp(
5817 project_id,
5818 None,
5819 request_timeout,
5820 cx.background_executor().clone(),
5821 request.to_proto(project_id, buffer.read(cx)),
5822 );
5823 let buffer = buffer.clone();
5824 cx.spawn(async move |weak_lsp_store, cx| {
5825 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5826 return Ok(None);
5827 };
5828 let Some(responses) = request_task.await? else {
5829 return Ok(None);
5830 };
5831 let actions = join_all(responses.payload.into_iter().map(|response| {
5832 GetTypeDefinitions { position }.response_from_proto(
5833 response.response,
5834 lsp_store.clone(),
5835 buffer.clone(),
5836 cx.clone(),
5837 )
5838 }))
5839 .await;
5840
5841 Ok(Some(
5842 actions
5843 .into_iter()
5844 .collect::<Result<Vec<Vec<_>>>>()?
5845 .into_iter()
5846 .flatten()
5847 .dedup()
5848 .collect(),
5849 ))
5850 })
5851 } else {
5852 let type_definitions_task = self.request_multiple_lsp_locally(
5853 buffer,
5854 Some(position),
5855 GetTypeDefinitions { position },
5856 cx,
5857 );
5858 cx.background_spawn(async move {
5859 Ok(Some(
5860 type_definitions_task
5861 .await
5862 .into_iter()
5863 .flat_map(|(_, type_definitions)| type_definitions)
5864 .dedup()
5865 .collect(),
5866 ))
5867 })
5868 }
5869 }
5870
5871 pub fn implementations(
5872 &mut self,
5873 buffer: &Entity<Buffer>,
5874 position: PointUtf16,
5875 cx: &mut Context<Self>,
5876 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5877 if let Some((upstream_client, project_id)) = self.upstream_client() {
5878 let request = GetImplementations { position };
5879 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5880 return Task::ready(Ok(None));
5881 }
5882
5883 let request_timeout = ProjectSettings::get_global(cx)
5884 .global_lsp_settings
5885 .get_request_timeout();
5886 let request_task = upstream_client.request_lsp(
5887 project_id,
5888 None,
5889 request_timeout,
5890 cx.background_executor().clone(),
5891 request.to_proto(project_id, buffer.read(cx)),
5892 );
5893 let buffer = buffer.clone();
5894 cx.spawn(async move |weak_lsp_store, cx| {
5895 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5896 return Ok(None);
5897 };
5898 let Some(responses) = request_task.await? else {
5899 return Ok(None);
5900 };
5901 let actions = join_all(responses.payload.into_iter().map(|response| {
5902 GetImplementations { position }.response_from_proto(
5903 response.response,
5904 lsp_store.clone(),
5905 buffer.clone(),
5906 cx.clone(),
5907 )
5908 }))
5909 .await;
5910
5911 Ok(Some(
5912 actions
5913 .into_iter()
5914 .collect::<Result<Vec<Vec<_>>>>()?
5915 .into_iter()
5916 .flatten()
5917 .dedup()
5918 .collect(),
5919 ))
5920 })
5921 } else {
5922 let implementations_task = self.request_multiple_lsp_locally(
5923 buffer,
5924 Some(position),
5925 GetImplementations { position },
5926 cx,
5927 );
5928 cx.background_spawn(async move {
5929 Ok(Some(
5930 implementations_task
5931 .await
5932 .into_iter()
5933 .flat_map(|(_, implementations)| implementations)
5934 .dedup()
5935 .collect(),
5936 ))
5937 })
5938 }
5939 }
5940
5941 pub fn references(
5942 &mut self,
5943 buffer: &Entity<Buffer>,
5944 position: PointUtf16,
5945 cx: &mut Context<Self>,
5946 ) -> Task<Result<Option<Vec<Location>>>> {
5947 if let Some((upstream_client, project_id)) = self.upstream_client() {
5948 let request = GetReferences { position };
5949 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5950 return Task::ready(Ok(None));
5951 }
5952
5953 let request_timeout = ProjectSettings::get_global(cx)
5954 .global_lsp_settings
5955 .get_request_timeout();
5956 let request_task = upstream_client.request_lsp(
5957 project_id,
5958 None,
5959 request_timeout,
5960 cx.background_executor().clone(),
5961 request.to_proto(project_id, buffer.read(cx)),
5962 );
5963 let buffer = buffer.clone();
5964 cx.spawn(async move |weak_lsp_store, cx| {
5965 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5966 return Ok(None);
5967 };
5968 let Some(responses) = request_task.await? else {
5969 return Ok(None);
5970 };
5971
5972 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5973 GetReferences { position }.response_from_proto(
5974 lsp_response.response,
5975 lsp_store.clone(),
5976 buffer.clone(),
5977 cx.clone(),
5978 )
5979 }))
5980 .await
5981 .into_iter()
5982 .collect::<Result<Vec<Vec<_>>>>()?
5983 .into_iter()
5984 .flatten()
5985 .dedup()
5986 .collect();
5987 Ok(Some(locations))
5988 })
5989 } else {
5990 let references_task = self.request_multiple_lsp_locally(
5991 buffer,
5992 Some(position),
5993 GetReferences { position },
5994 cx,
5995 );
5996 cx.background_spawn(async move {
5997 Ok(Some(
5998 references_task
5999 .await
6000 .into_iter()
6001 .flat_map(|(_, references)| references)
6002 .dedup()
6003 .collect(),
6004 ))
6005 })
6006 }
6007 }
6008
6009 pub fn code_actions(
6010 &mut self,
6011 buffer: &Entity<Buffer>,
6012 range: Range<Anchor>,
6013 kinds: Option<Vec<CodeActionKind>>,
6014 cx: &mut Context<Self>,
6015 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6016 if let Some((upstream_client, project_id)) = self.upstream_client() {
6017 let request = GetCodeActions {
6018 range: range.clone(),
6019 kinds: kinds.clone(),
6020 };
6021 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6022 return Task::ready(Ok(None));
6023 }
6024 let request_timeout = ProjectSettings::get_global(cx)
6025 .global_lsp_settings
6026 .get_request_timeout();
6027 let request_task = upstream_client.request_lsp(
6028 project_id,
6029 None,
6030 request_timeout,
6031 cx.background_executor().clone(),
6032 request.to_proto(project_id, buffer.read(cx)),
6033 );
6034 let buffer = buffer.clone();
6035 cx.spawn(async move |weak_lsp_store, cx| {
6036 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6037 return Ok(None);
6038 };
6039 let Some(responses) = request_task.await? else {
6040 return Ok(None);
6041 };
6042 let actions = join_all(responses.payload.into_iter().map(|response| {
6043 GetCodeActions {
6044 range: range.clone(),
6045 kinds: kinds.clone(),
6046 }
6047 .response_from_proto(
6048 response.response,
6049 lsp_store.clone(),
6050 buffer.clone(),
6051 cx.clone(),
6052 )
6053 }))
6054 .await;
6055
6056 Ok(Some(
6057 actions
6058 .into_iter()
6059 .collect::<Result<Vec<Vec<_>>>>()?
6060 .into_iter()
6061 .flatten()
6062 .collect(),
6063 ))
6064 })
6065 } else {
6066 let all_actions_task = self.request_multiple_lsp_locally(
6067 buffer,
6068 Some(range.start),
6069 GetCodeActions { range, kinds },
6070 cx,
6071 );
6072 cx.background_spawn(async move {
6073 Ok(Some(
6074 all_actions_task
6075 .await
6076 .into_iter()
6077 .flat_map(|(_, actions)| actions)
6078 .collect(),
6079 ))
6080 })
6081 }
6082 }
6083
6084 #[inline(never)]
6085 pub fn completions(
6086 &self,
6087 buffer: &Entity<Buffer>,
6088 position: PointUtf16,
6089 context: CompletionContext,
6090 cx: &mut Context<Self>,
6091 ) -> Task<Result<Vec<CompletionResponse>>> {
6092 let language_registry = self.languages.clone();
6093
6094 if let Some((upstream_client, project_id)) = self.upstream_client() {
6095 let snapshot = buffer.read(cx).snapshot();
6096 let offset = position.to_offset(&snapshot);
6097 let scope = snapshot.language_scope_at(offset);
6098 let capable_lsps = self.all_capable_for_proto_request(
6099 buffer,
6100 |server_name, capabilities| {
6101 capabilities.completion_provider.is_some()
6102 && scope
6103 .as_ref()
6104 .map(|scope| scope.language_allowed(server_name))
6105 .unwrap_or(true)
6106 },
6107 cx,
6108 );
6109 if capable_lsps.is_empty() {
6110 return Task::ready(Ok(Vec::new()));
6111 }
6112
6113 let language = buffer.read(cx).language().cloned();
6114
6115 // In the future, we should provide project guests with the names of LSP adapters,
6116 // so that they can use the correct LSP adapter when computing labels. For now,
6117 // guests just use the first LSP adapter associated with the buffer's language.
6118 let lsp_adapter = language.as_ref().and_then(|language| {
6119 language_registry
6120 .lsp_adapters(&language.name())
6121 .first()
6122 .cloned()
6123 });
6124
6125 let buffer = buffer.clone();
6126
6127 cx.spawn(async move |this, cx| {
6128 let requests = join_all(
6129 capable_lsps
6130 .into_iter()
6131 .map(|id| {
6132 let request = GetCompletions {
6133 position,
6134 context: context.clone(),
6135 server_id: Some(id),
6136 };
6137 let buffer = buffer.clone();
6138 let language = language.clone();
6139 let lsp_adapter = lsp_adapter.clone();
6140 let upstream_client = upstream_client.clone();
6141 let response = this
6142 .update(cx, |this, cx| {
6143 this.send_lsp_proto_request(
6144 buffer,
6145 upstream_client,
6146 project_id,
6147 request,
6148 cx,
6149 )
6150 })
6151 .log_err();
6152 async move {
6153 let response = response?.await.log_err()?;
6154
6155 let completions = populate_labels_for_completions(
6156 response.completions,
6157 language,
6158 lsp_adapter,
6159 )
6160 .await;
6161
6162 Some(CompletionResponse {
6163 completions,
6164 display_options: CompletionDisplayOptions::default(),
6165 is_incomplete: response.is_incomplete,
6166 })
6167 }
6168 })
6169 .collect::<Vec<_>>(),
6170 );
6171 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6172 })
6173 } else if let Some(local) = self.as_local() {
6174 let snapshot = buffer.read(cx).snapshot();
6175 let offset = position.to_offset(&snapshot);
6176 let scope = snapshot.language_scope_at(offset);
6177 let language = snapshot.language().cloned();
6178 let completion_settings = language_settings(
6179 language.as_ref().map(|language| language.name()),
6180 buffer.read(cx).file(),
6181 cx,
6182 )
6183 .completions
6184 .clone();
6185 if !completion_settings.lsp {
6186 return Task::ready(Ok(Vec::new()));
6187 }
6188
6189 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6190 local
6191 .language_servers_for_buffer(buffer, cx)
6192 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6193 .filter(|(adapter, _)| {
6194 scope
6195 .as_ref()
6196 .map(|scope| scope.language_allowed(&adapter.name))
6197 .unwrap_or(true)
6198 })
6199 .map(|(_, server)| server.server_id())
6200 .collect()
6201 });
6202
6203 let buffer = buffer.clone();
6204 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6205 let lsp_timeout = if lsp_timeout > 0 {
6206 Some(Duration::from_millis(lsp_timeout))
6207 } else {
6208 None
6209 };
6210 cx.spawn(async move |this, cx| {
6211 let mut tasks = Vec::with_capacity(server_ids.len());
6212 this.update(cx, |lsp_store, cx| {
6213 for server_id in server_ids {
6214 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6215 let lsp_timeout = lsp_timeout
6216 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6217 let mut timeout = cx.background_spawn(async move {
6218 match lsp_timeout {
6219 Some(lsp_timeout) => {
6220 lsp_timeout.await;
6221 true
6222 },
6223 None => false,
6224 }
6225 }).fuse();
6226 let mut lsp_request = lsp_store.request_lsp(
6227 buffer.clone(),
6228 LanguageServerToQuery::Other(server_id),
6229 GetCompletions {
6230 position,
6231 context: context.clone(),
6232 server_id: Some(server_id),
6233 },
6234 cx,
6235 ).fuse();
6236 let new_task = cx.background_spawn(async move {
6237 select_biased! {
6238 response = lsp_request => anyhow::Ok(Some(response?)),
6239 timeout_happened = timeout => {
6240 if timeout_happened {
6241 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6242 Ok(None)
6243 } else {
6244 let completions = lsp_request.await?;
6245 Ok(Some(completions))
6246 }
6247 },
6248 }
6249 });
6250 tasks.push((lsp_adapter, new_task));
6251 }
6252 })?;
6253
6254 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6255 let completion_response = task.await.ok()??;
6256 let completions = populate_labels_for_completions(
6257 completion_response.completions,
6258 language.clone(),
6259 lsp_adapter,
6260 )
6261 .await;
6262 Some(CompletionResponse {
6263 completions,
6264 display_options: CompletionDisplayOptions::default(),
6265 is_incomplete: completion_response.is_incomplete,
6266 })
6267 });
6268
6269 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6270
6271 Ok(responses.into_iter().flatten().collect())
6272 })
6273 } else {
6274 Task::ready(Err(anyhow!("No upstream client or local language server")))
6275 }
6276 }
6277
6278 pub fn resolve_completions(
6279 &self,
6280 buffer: Entity<Buffer>,
6281 completion_indices: Vec<usize>,
6282 completions: Rc<RefCell<Box<[Completion]>>>,
6283 cx: &mut Context<Self>,
6284 ) -> Task<Result<bool>> {
6285 let client = self.upstream_client();
6286 let buffer_id = buffer.read(cx).remote_id();
6287 let buffer_snapshot = buffer.read(cx).snapshot();
6288
6289 if !self.check_if_capable_for_proto_request(
6290 &buffer,
6291 GetCompletions::can_resolve_completions,
6292 cx,
6293 ) {
6294 return Task::ready(Ok(false));
6295 }
6296 cx.spawn(async move |lsp_store, cx| {
6297 let request_timeout = cx.update(|app| {
6298 ProjectSettings::get_global(app)
6299 .global_lsp_settings
6300 .get_request_timeout()
6301 });
6302
6303 let mut did_resolve = false;
6304 if let Some((client, project_id)) = client {
6305 for completion_index in completion_indices {
6306 let server_id = {
6307 let completion = &completions.borrow()[completion_index];
6308 completion.source.server_id()
6309 };
6310 if let Some(server_id) = server_id {
6311 if Self::resolve_completion_remote(
6312 project_id,
6313 server_id,
6314 buffer_id,
6315 completions.clone(),
6316 completion_index,
6317 client.clone(),
6318 )
6319 .await
6320 .log_err()
6321 .is_some()
6322 {
6323 did_resolve = true;
6324 }
6325 } else {
6326 resolve_word_completion(
6327 &buffer_snapshot,
6328 &mut completions.borrow_mut()[completion_index],
6329 );
6330 }
6331 }
6332 } else {
6333 for completion_index in completion_indices {
6334 let server_id = {
6335 let completion = &completions.borrow()[completion_index];
6336 completion.source.server_id()
6337 };
6338 if let Some(server_id) = server_id {
6339 let server_and_adapter = lsp_store
6340 .read_with(cx, |lsp_store, _| {
6341 let server = lsp_store.language_server_for_id(server_id)?;
6342 let adapter =
6343 lsp_store.language_server_adapter_for_id(server.server_id())?;
6344 Some((server, adapter))
6345 })
6346 .ok()
6347 .flatten();
6348 let Some((server, adapter)) = server_and_adapter else {
6349 continue;
6350 };
6351
6352 let resolved = Self::resolve_completion_local(
6353 server,
6354 completions.clone(),
6355 completion_index,
6356 request_timeout,
6357 )
6358 .await
6359 .log_err()
6360 .is_some();
6361 if resolved {
6362 Self::regenerate_completion_labels(
6363 adapter,
6364 &buffer_snapshot,
6365 completions.clone(),
6366 completion_index,
6367 )
6368 .await
6369 .log_err();
6370 did_resolve = true;
6371 }
6372 } else {
6373 resolve_word_completion(
6374 &buffer_snapshot,
6375 &mut completions.borrow_mut()[completion_index],
6376 );
6377 }
6378 }
6379 }
6380
6381 Ok(did_resolve)
6382 })
6383 }
6384
6385 async fn resolve_completion_local(
6386 server: Arc<lsp::LanguageServer>,
6387 completions: Rc<RefCell<Box<[Completion]>>>,
6388 completion_index: usize,
6389 request_timeout: Duration,
6390 ) -> Result<()> {
6391 let server_id = server.server_id();
6392 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6393 return Ok(());
6394 }
6395
6396 let request = {
6397 let completion = &completions.borrow()[completion_index];
6398 match &completion.source {
6399 CompletionSource::Lsp {
6400 lsp_completion,
6401 resolved,
6402 server_id: completion_server_id,
6403 ..
6404 } => {
6405 if *resolved {
6406 return Ok(());
6407 }
6408 anyhow::ensure!(
6409 server_id == *completion_server_id,
6410 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6411 );
6412 server.request::<lsp::request::ResolveCompletionItem>(
6413 *lsp_completion.clone(),
6414 request_timeout,
6415 )
6416 }
6417 CompletionSource::BufferWord { .. }
6418 | CompletionSource::Dap { .. }
6419 | CompletionSource::Custom => {
6420 return Ok(());
6421 }
6422 }
6423 };
6424 let resolved_completion = request
6425 .await
6426 .into_response()
6427 .context("resolve completion")?;
6428
6429 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6430 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6431
6432 let mut completions = completions.borrow_mut();
6433 let completion = &mut completions[completion_index];
6434 if let CompletionSource::Lsp {
6435 lsp_completion,
6436 resolved,
6437 server_id: completion_server_id,
6438 ..
6439 } = &mut completion.source
6440 {
6441 if *resolved {
6442 return Ok(());
6443 }
6444 anyhow::ensure!(
6445 server_id == *completion_server_id,
6446 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6447 );
6448 **lsp_completion = resolved_completion;
6449 *resolved = true;
6450 }
6451 Ok(())
6452 }
6453
6454 async fn regenerate_completion_labels(
6455 adapter: Arc<CachedLspAdapter>,
6456 snapshot: &BufferSnapshot,
6457 completions: Rc<RefCell<Box<[Completion]>>>,
6458 completion_index: usize,
6459 ) -> Result<()> {
6460 let completion_item = completions.borrow()[completion_index]
6461 .source
6462 .lsp_completion(true)
6463 .map(Cow::into_owned);
6464 if let Some(lsp_documentation) = completion_item
6465 .as_ref()
6466 .and_then(|completion_item| completion_item.documentation.clone())
6467 {
6468 let mut completions = completions.borrow_mut();
6469 let completion = &mut completions[completion_index];
6470 completion.documentation = Some(lsp_documentation.into());
6471 } else {
6472 let mut completions = completions.borrow_mut();
6473 let completion = &mut completions[completion_index];
6474 completion.documentation = Some(CompletionDocumentation::Undocumented);
6475 }
6476
6477 let mut new_label = match completion_item {
6478 Some(completion_item) => {
6479 // Some language servers always return `detail` lazily via resolve, regardless of
6480 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6481 // See: https://github.com/yioneko/vtsls/issues/213
6482 let language = snapshot.language();
6483 match language {
6484 Some(language) => {
6485 adapter
6486 .labels_for_completions(
6487 std::slice::from_ref(&completion_item),
6488 language,
6489 )
6490 .await?
6491 }
6492 None => Vec::new(),
6493 }
6494 .pop()
6495 .flatten()
6496 .unwrap_or_else(|| {
6497 CodeLabel::fallback_for_completion(
6498 &completion_item,
6499 language.map(|language| language.as_ref()),
6500 )
6501 })
6502 }
6503 None => CodeLabel::plain(
6504 completions.borrow()[completion_index].new_text.clone(),
6505 None,
6506 ),
6507 };
6508 ensure_uniform_list_compatible_label(&mut new_label);
6509
6510 let mut completions = completions.borrow_mut();
6511 let completion = &mut completions[completion_index];
6512 if completion.label.filter_text() == new_label.filter_text() {
6513 completion.label = new_label;
6514 } else {
6515 log::error!(
6516 "Resolved completion changed display label from {} to {}. \
6517 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6518 completion.label.text(),
6519 new_label.text(),
6520 completion.label.filter_text(),
6521 new_label.filter_text()
6522 );
6523 }
6524
6525 Ok(())
6526 }
6527
6528 async fn resolve_completion_remote(
6529 project_id: u64,
6530 server_id: LanguageServerId,
6531 buffer_id: BufferId,
6532 completions: Rc<RefCell<Box<[Completion]>>>,
6533 completion_index: usize,
6534 client: AnyProtoClient,
6535 ) -> Result<()> {
6536 let lsp_completion = {
6537 let completion = &completions.borrow()[completion_index];
6538 match &completion.source {
6539 CompletionSource::Lsp {
6540 lsp_completion,
6541 resolved,
6542 server_id: completion_server_id,
6543 ..
6544 } => {
6545 anyhow::ensure!(
6546 server_id == *completion_server_id,
6547 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6548 );
6549 if *resolved {
6550 return Ok(());
6551 }
6552 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6553 }
6554 CompletionSource::Custom
6555 | CompletionSource::Dap { .. }
6556 | CompletionSource::BufferWord { .. } => {
6557 return Ok(());
6558 }
6559 }
6560 };
6561 let request = proto::ResolveCompletionDocumentation {
6562 project_id,
6563 language_server_id: server_id.0 as u64,
6564 lsp_completion,
6565 buffer_id: buffer_id.into(),
6566 };
6567
6568 let response = client
6569 .request(request)
6570 .await
6571 .context("completion documentation resolve proto request")?;
6572 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6573
6574 let documentation = if response.documentation.is_empty() {
6575 CompletionDocumentation::Undocumented
6576 } else if response.documentation_is_markdown {
6577 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6578 } else if response.documentation.lines().count() <= 1 {
6579 CompletionDocumentation::SingleLine(response.documentation.into())
6580 } else {
6581 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6582 };
6583
6584 let mut completions = completions.borrow_mut();
6585 let completion = &mut completions[completion_index];
6586 completion.documentation = Some(documentation);
6587 if let CompletionSource::Lsp {
6588 insert_range,
6589 lsp_completion,
6590 resolved,
6591 server_id: completion_server_id,
6592 lsp_defaults: _,
6593 } = &mut completion.source
6594 {
6595 let completion_insert_range = response
6596 .old_insert_start
6597 .and_then(deserialize_anchor)
6598 .zip(response.old_insert_end.and_then(deserialize_anchor));
6599 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6600
6601 if *resolved {
6602 return Ok(());
6603 }
6604 anyhow::ensure!(
6605 server_id == *completion_server_id,
6606 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6607 );
6608 **lsp_completion = resolved_lsp_completion;
6609 *resolved = true;
6610 }
6611
6612 let replace_range = response
6613 .old_replace_start
6614 .and_then(deserialize_anchor)
6615 .zip(response.old_replace_end.and_then(deserialize_anchor));
6616 if let Some((old_replace_start, old_replace_end)) = replace_range
6617 && !response.new_text.is_empty()
6618 {
6619 completion.new_text = response.new_text;
6620 completion.replace_range = old_replace_start..old_replace_end;
6621 }
6622
6623 Ok(())
6624 }
6625
6626 pub fn apply_additional_edits_for_completion(
6627 &self,
6628 buffer_handle: Entity<Buffer>,
6629 completions: Rc<RefCell<Box<[Completion]>>>,
6630 completion_index: usize,
6631 push_to_history: bool,
6632 cx: &mut Context<Self>,
6633 ) -> Task<Result<Option<Transaction>>> {
6634 if let Some((client, project_id)) = self.upstream_client() {
6635 let buffer = buffer_handle.read(cx);
6636 let buffer_id = buffer.remote_id();
6637 cx.spawn(async move |_, cx| {
6638 let request = {
6639 let completion = completions.borrow()[completion_index].clone();
6640 proto::ApplyCompletionAdditionalEdits {
6641 project_id,
6642 buffer_id: buffer_id.into(),
6643 completion: Some(Self::serialize_completion(&CoreCompletion {
6644 replace_range: completion.replace_range,
6645 new_text: completion.new_text,
6646 source: completion.source,
6647 })),
6648 }
6649 };
6650
6651 let Some(transaction) = client.request(request).await?.transaction else {
6652 return Ok(None);
6653 };
6654
6655 let transaction = language::proto::deserialize_transaction(transaction)?;
6656 buffer_handle
6657 .update(cx, |buffer, _| {
6658 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6659 })
6660 .await?;
6661 if push_to_history {
6662 buffer_handle.update(cx, |buffer, _| {
6663 buffer.push_transaction(transaction.clone(), Instant::now());
6664 buffer.finalize_last_transaction();
6665 });
6666 }
6667 Ok(Some(transaction))
6668 })
6669 } else {
6670 let request_timeout = ProjectSettings::get_global(cx)
6671 .global_lsp_settings
6672 .get_request_timeout();
6673
6674 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6675 let completion = &completions.borrow()[completion_index];
6676 let server_id = completion.source.server_id()?;
6677 Some(
6678 self.language_server_for_local_buffer(buffer, server_id, cx)?
6679 .1
6680 .clone(),
6681 )
6682 }) else {
6683 return Task::ready(Ok(None));
6684 };
6685
6686 cx.spawn(async move |this, cx| {
6687 Self::resolve_completion_local(
6688 server.clone(),
6689 completions.clone(),
6690 completion_index,
6691 request_timeout,
6692 )
6693 .await
6694 .context("resolving completion")?;
6695 let completion = completions.borrow()[completion_index].clone();
6696 let additional_text_edits = completion
6697 .source
6698 .lsp_completion(true)
6699 .as_ref()
6700 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6701 if let Some(edits) = additional_text_edits {
6702 let edits = this
6703 .update(cx, |this, cx| {
6704 this.as_local_mut().unwrap().edits_from_lsp(
6705 &buffer_handle,
6706 edits,
6707 server.server_id(),
6708 None,
6709 cx,
6710 )
6711 })?
6712 .await?;
6713
6714 buffer_handle.update(cx, |buffer, cx| {
6715 buffer.finalize_last_transaction();
6716 buffer.start_transaction();
6717
6718 for (range, text) in edits {
6719 let primary = &completion.replace_range;
6720
6721 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6722 // and the primary completion is just an insertion (empty range), then this is likely
6723 // an auto-import scenario and should not be considered overlapping
6724 // https://github.com/zed-industries/zed/issues/26136
6725 let is_file_start_auto_import = {
6726 let snapshot = buffer.snapshot();
6727 let primary_start_point = primary.start.to_point(&snapshot);
6728 let range_start_point = range.start.to_point(&snapshot);
6729
6730 let result = primary_start_point.row == 0
6731 && primary_start_point.column == 0
6732 && range_start_point.row == 0
6733 && range_start_point.column == 0;
6734
6735 result
6736 };
6737
6738 let has_overlap = if is_file_start_auto_import {
6739 false
6740 } else {
6741 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6742 && primary.end.cmp(&range.start, buffer).is_ge();
6743 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6744 && range.end.cmp(&primary.end, buffer).is_ge();
6745 let result = start_within || end_within;
6746 result
6747 };
6748
6749 //Skip additional edits which overlap with the primary completion edit
6750 //https://github.com/zed-industries/zed/pull/1871
6751 if !has_overlap {
6752 buffer.edit([(range, text)], None, cx);
6753 }
6754 }
6755
6756 let transaction = if buffer.end_transaction(cx).is_some() {
6757 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6758 if !push_to_history {
6759 buffer.forget_transaction(transaction.id);
6760 }
6761 Some(transaction)
6762 } else {
6763 None
6764 };
6765 Ok(transaction)
6766 })
6767 } else {
6768 Ok(None)
6769 }
6770 })
6771 }
6772 }
6773
6774 pub fn pull_diagnostics(
6775 &mut self,
6776 buffer: Entity<Buffer>,
6777 cx: &mut Context<Self>,
6778 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6779 let buffer_id = buffer.read(cx).remote_id();
6780
6781 if let Some((client, upstream_project_id)) = self.upstream_client() {
6782 let mut suitable_capabilities = None;
6783 // Are we capable for proto request?
6784 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6785 &buffer,
6786 |capabilities| {
6787 if let Some(caps) = &capabilities.diagnostic_provider {
6788 suitable_capabilities = Some(caps.clone());
6789 true
6790 } else {
6791 false
6792 }
6793 },
6794 cx,
6795 );
6796 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6797 let Some(dynamic_caps) = suitable_capabilities else {
6798 return Task::ready(Ok(None));
6799 };
6800 assert!(any_server_has_diagnostics_provider);
6801
6802 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6803 let request = GetDocumentDiagnostics {
6804 previous_result_id: None,
6805 identifier,
6806 registration_id: None,
6807 };
6808 let request_timeout = ProjectSettings::get_global(cx)
6809 .global_lsp_settings
6810 .get_request_timeout();
6811 let request_task = client.request_lsp(
6812 upstream_project_id,
6813 None,
6814 request_timeout,
6815 cx.background_executor().clone(),
6816 request.to_proto(upstream_project_id, buffer.read(cx)),
6817 );
6818 cx.background_spawn(async move {
6819 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6820 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6821 // Do not attempt to further process the dummy responses here.
6822 let _response = request_task.await?;
6823 Ok(None)
6824 })
6825 } else {
6826 let servers = buffer.update(cx, |buffer, cx| {
6827 self.running_language_servers_for_local_buffer(buffer, cx)
6828 .map(|(_, server)| server.clone())
6829 .collect::<Vec<_>>()
6830 });
6831
6832 let pull_diagnostics = servers
6833 .into_iter()
6834 .flat_map(|server| {
6835 let result = maybe!({
6836 let local = self.as_local()?;
6837 let server_id = server.server_id();
6838 let providers_with_identifiers = local
6839 .language_server_dynamic_registrations
6840 .get(&server_id)
6841 .into_iter()
6842 .flat_map(|registrations| registrations.diagnostics.clone())
6843 .collect::<Vec<_>>();
6844 Some(
6845 providers_with_identifiers
6846 .into_iter()
6847 .map(|(registration_id, dynamic_caps)| {
6848 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6849 let registration_id = registration_id.map(SharedString::from);
6850 let result_id = self.result_id_for_buffer_pull(
6851 server_id,
6852 buffer_id,
6853 ®istration_id,
6854 cx,
6855 );
6856 self.request_lsp(
6857 buffer.clone(),
6858 LanguageServerToQuery::Other(server_id),
6859 GetDocumentDiagnostics {
6860 previous_result_id: result_id,
6861 registration_id,
6862 identifier,
6863 },
6864 cx,
6865 )
6866 })
6867 .collect::<Vec<_>>(),
6868 )
6869 });
6870
6871 result.unwrap_or_default()
6872 })
6873 .collect::<Vec<_>>();
6874
6875 cx.background_spawn(async move {
6876 let mut responses = Vec::new();
6877 for diagnostics in join_all(pull_diagnostics).await {
6878 responses.extend(diagnostics?);
6879 }
6880 Ok(Some(responses))
6881 })
6882 }
6883 }
6884
6885 pub fn applicable_inlay_chunks(
6886 &mut self,
6887 buffer: &Entity<Buffer>,
6888 ranges: &[Range<text::Anchor>],
6889 cx: &mut Context<Self>,
6890 ) -> Vec<Range<BufferRow>> {
6891 let buffer_snapshot = buffer.read(cx).snapshot();
6892 let ranges = ranges
6893 .iter()
6894 .map(|range| range.to_point(&buffer_snapshot))
6895 .collect::<Vec<_>>();
6896
6897 self.latest_lsp_data(buffer, cx)
6898 .inlay_hints
6899 .applicable_chunks(ranges.as_slice())
6900 .map(|chunk| chunk.row_range())
6901 .collect()
6902 }
6903
6904 pub fn invalidate_inlay_hints<'a>(
6905 &'a mut self,
6906 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6907 ) {
6908 for buffer_id in for_buffers {
6909 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6910 lsp_data.inlay_hints.clear();
6911 }
6912 }
6913 }
6914
6915 pub fn inlay_hints(
6916 &mut self,
6917 invalidate: InvalidationStrategy,
6918 buffer: Entity<Buffer>,
6919 ranges: Vec<Range<text::Anchor>>,
6920 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6921 cx: &mut Context<Self>,
6922 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6923 let next_hint_id = self.next_hint_id.clone();
6924 let lsp_data = self.latest_lsp_data(&buffer, cx);
6925 let query_version = lsp_data.buffer_version.clone();
6926 let mut lsp_refresh_requested = false;
6927 let for_server = if let InvalidationStrategy::RefreshRequested {
6928 server_id,
6929 request_id,
6930 } = invalidate
6931 {
6932 let invalidated = lsp_data
6933 .inlay_hints
6934 .invalidate_for_server_refresh(server_id, request_id);
6935 lsp_refresh_requested = invalidated;
6936 Some(server_id)
6937 } else {
6938 None
6939 };
6940 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6941 let known_chunks = known_chunks
6942 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6943 .map(|(_, known_chunks)| known_chunks)
6944 .unwrap_or_default();
6945
6946 let buffer_snapshot = buffer.read(cx).snapshot();
6947 let ranges = ranges
6948 .iter()
6949 .map(|range| range.to_point(&buffer_snapshot))
6950 .collect::<Vec<_>>();
6951
6952 let mut hint_fetch_tasks = Vec::new();
6953 let mut cached_inlay_hints = None;
6954 let mut ranges_to_query = None;
6955 let applicable_chunks = existing_inlay_hints
6956 .applicable_chunks(ranges.as_slice())
6957 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6958 .collect::<Vec<_>>();
6959 if applicable_chunks.is_empty() {
6960 return HashMap::default();
6961 }
6962
6963 for row_chunk in applicable_chunks {
6964 match (
6965 existing_inlay_hints
6966 .cached_hints(&row_chunk)
6967 .filter(|_| !lsp_refresh_requested)
6968 .cloned(),
6969 existing_inlay_hints
6970 .fetched_hints(&row_chunk)
6971 .as_ref()
6972 .filter(|_| !lsp_refresh_requested)
6973 .cloned(),
6974 ) {
6975 (None, None) => {
6976 let chunk_range = row_chunk.anchor_range();
6977 ranges_to_query
6978 .get_or_insert_with(Vec::new)
6979 .push((row_chunk, chunk_range));
6980 }
6981 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6982 (Some(cached_hints), None) => {
6983 for (server_id, cached_hints) in cached_hints {
6984 if for_server.is_none_or(|for_server| for_server == server_id) {
6985 cached_inlay_hints
6986 .get_or_insert_with(HashMap::default)
6987 .entry(row_chunk.row_range())
6988 .or_insert_with(HashMap::default)
6989 .entry(server_id)
6990 .or_insert_with(Vec::new)
6991 .extend(cached_hints);
6992 }
6993 }
6994 }
6995 (Some(cached_hints), Some(fetched_hints)) => {
6996 hint_fetch_tasks.push((row_chunk, fetched_hints));
6997 for (server_id, cached_hints) in cached_hints {
6998 if for_server.is_none_or(|for_server| for_server == server_id) {
6999 cached_inlay_hints
7000 .get_or_insert_with(HashMap::default)
7001 .entry(row_chunk.row_range())
7002 .or_insert_with(HashMap::default)
7003 .entry(server_id)
7004 .or_insert_with(Vec::new)
7005 .extend(cached_hints);
7006 }
7007 }
7008 }
7009 }
7010 }
7011
7012 if hint_fetch_tasks.is_empty()
7013 && ranges_to_query
7014 .as_ref()
7015 .is_none_or(|ranges| ranges.is_empty())
7016 && let Some(cached_inlay_hints) = cached_inlay_hints
7017 {
7018 cached_inlay_hints
7019 .into_iter()
7020 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7021 .collect()
7022 } else {
7023 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7024 let next_hint_id = next_hint_id.clone();
7025 let buffer = buffer.clone();
7026 let query_version = query_version.clone();
7027 let new_inlay_hints = cx
7028 .spawn(async move |lsp_store, cx| {
7029 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7030 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7031 })?;
7032 new_fetch_task
7033 .await
7034 .and_then(|new_hints_by_server| {
7035 lsp_store.update(cx, |lsp_store, cx| {
7036 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7037 let update_cache = lsp_data.buffer_version == query_version;
7038 if new_hints_by_server.is_empty() {
7039 if update_cache {
7040 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7041 }
7042 HashMap::default()
7043 } else {
7044 new_hints_by_server
7045 .into_iter()
7046 .map(|(server_id, new_hints)| {
7047 let new_hints = new_hints
7048 .into_iter()
7049 .map(|new_hint| {
7050 (
7051 InlayId::Hint(next_hint_id.fetch_add(
7052 1,
7053 atomic::Ordering::AcqRel,
7054 )),
7055 new_hint,
7056 )
7057 })
7058 .collect::<Vec<_>>();
7059 if update_cache {
7060 lsp_data.inlay_hints.insert_new_hints(
7061 chunk,
7062 server_id,
7063 new_hints.clone(),
7064 );
7065 }
7066 (server_id, new_hints)
7067 })
7068 .collect()
7069 }
7070 })
7071 })
7072 .map_err(Arc::new)
7073 })
7074 .shared();
7075
7076 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7077 *fetch_task = Some(new_inlay_hints.clone());
7078 hint_fetch_tasks.push((chunk, new_inlay_hints));
7079 }
7080
7081 cached_inlay_hints
7082 .unwrap_or_default()
7083 .into_iter()
7084 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7085 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7086 (
7087 chunk.row_range(),
7088 cx.spawn(async move |_, _| {
7089 hints_fetch.await.map_err(|e| {
7090 if e.error_code() != ErrorCode::Internal {
7091 anyhow!(e.error_code())
7092 } else {
7093 anyhow!("{e:#}")
7094 }
7095 })
7096 }),
7097 )
7098 }))
7099 .collect()
7100 }
7101 }
7102
7103 fn fetch_inlay_hints(
7104 &mut self,
7105 for_server: Option<LanguageServerId>,
7106 buffer: &Entity<Buffer>,
7107 range: Range<Anchor>,
7108 cx: &mut Context<Self>,
7109 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7110 let request = InlayHints {
7111 range: range.clone(),
7112 };
7113 if let Some((upstream_client, project_id)) = self.upstream_client() {
7114 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7115 return Task::ready(Ok(HashMap::default()));
7116 }
7117 let request_timeout = ProjectSettings::get_global(cx)
7118 .global_lsp_settings
7119 .get_request_timeout();
7120 let request_task = upstream_client.request_lsp(
7121 project_id,
7122 for_server.map(|id| id.to_proto()),
7123 request_timeout,
7124 cx.background_executor().clone(),
7125 request.to_proto(project_id, buffer.read(cx)),
7126 );
7127 let buffer = buffer.clone();
7128 cx.spawn(async move |weak_lsp_store, cx| {
7129 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7130 return Ok(HashMap::default());
7131 };
7132 let Some(responses) = request_task.await? else {
7133 return Ok(HashMap::default());
7134 };
7135
7136 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7137 let lsp_store = lsp_store.clone();
7138 let buffer = buffer.clone();
7139 let cx = cx.clone();
7140 let request = request.clone();
7141 async move {
7142 (
7143 LanguageServerId::from_proto(response.server_id),
7144 request
7145 .response_from_proto(response.response, lsp_store, buffer, cx)
7146 .await,
7147 )
7148 }
7149 }))
7150 .await;
7151
7152 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7153 let mut has_errors = false;
7154 let inlay_hints = inlay_hints
7155 .into_iter()
7156 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7157 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7158 Err(e) => {
7159 has_errors = true;
7160 log::error!("{e:#}");
7161 None
7162 }
7163 })
7164 .map(|(server_id, mut new_hints)| {
7165 new_hints.retain(|hint| {
7166 hint.position.is_valid(&buffer_snapshot)
7167 && range.start.is_valid(&buffer_snapshot)
7168 && range.end.is_valid(&buffer_snapshot)
7169 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7170 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7171 });
7172 (server_id, new_hints)
7173 })
7174 .collect::<HashMap<_, _>>();
7175 anyhow::ensure!(
7176 !has_errors || !inlay_hints.is_empty(),
7177 "Failed to fetch inlay hints"
7178 );
7179 Ok(inlay_hints)
7180 })
7181 } else {
7182 let inlay_hints_task = match for_server {
7183 Some(server_id) => {
7184 let server_task = self.request_lsp(
7185 buffer.clone(),
7186 LanguageServerToQuery::Other(server_id),
7187 request,
7188 cx,
7189 );
7190 cx.background_spawn(async move {
7191 let mut responses = Vec::new();
7192 match server_task.await {
7193 Ok(response) => responses.push((server_id, response)),
7194 // rust-analyzer likes to error with this when its still loading up
7195 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7196 Err(e) => log::error!(
7197 "Error handling response for inlay hints request: {e:#}"
7198 ),
7199 }
7200 responses
7201 })
7202 }
7203 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7204 };
7205 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7206 cx.background_spawn(async move {
7207 Ok(inlay_hints_task
7208 .await
7209 .into_iter()
7210 .map(|(server_id, mut new_hints)| {
7211 new_hints.retain(|hint| {
7212 hint.position.is_valid(&buffer_snapshot)
7213 && range.start.is_valid(&buffer_snapshot)
7214 && range.end.is_valid(&buffer_snapshot)
7215 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7216 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7217 });
7218 (server_id, new_hints)
7219 })
7220 .collect())
7221 })
7222 }
7223 }
7224
7225 fn diagnostic_registration_exists(
7226 &self,
7227 server_id: LanguageServerId,
7228 registration_id: &Option<SharedString>,
7229 ) -> bool {
7230 let Some(local) = self.as_local() else {
7231 return false;
7232 };
7233 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7234 else {
7235 return false;
7236 };
7237 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7238 registrations.diagnostics.contains_key(®istration_key)
7239 }
7240
7241 pub fn pull_diagnostics_for_buffer(
7242 &mut self,
7243 buffer: Entity<Buffer>,
7244 cx: &mut Context<Self>,
7245 ) -> Task<anyhow::Result<()>> {
7246 let diagnostics = self.pull_diagnostics(buffer, cx);
7247 cx.spawn(async move |lsp_store, cx| {
7248 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7249 return Ok(());
7250 };
7251 lsp_store.update(cx, |lsp_store, cx| {
7252 if lsp_store.as_local().is_none() {
7253 return;
7254 }
7255
7256 let mut unchanged_buffers = HashMap::default();
7257 let server_diagnostics_updates = diagnostics
7258 .into_iter()
7259 .filter_map(|diagnostics_set| match diagnostics_set {
7260 LspPullDiagnostics::Response {
7261 server_id,
7262 uri,
7263 diagnostics,
7264 registration_id,
7265 } => Some((server_id, uri, diagnostics, registration_id)),
7266 LspPullDiagnostics::Default => None,
7267 })
7268 .filter(|(server_id, _, _, registration_id)| {
7269 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7270 })
7271 .fold(
7272 HashMap::default(),
7273 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7274 let (result_id, diagnostics) = match diagnostics {
7275 PulledDiagnostics::Unchanged { result_id } => {
7276 unchanged_buffers
7277 .entry(new_registration_id.clone())
7278 .or_insert_with(HashSet::default)
7279 .insert(uri.clone());
7280 (Some(result_id), Vec::new())
7281 }
7282 PulledDiagnostics::Changed {
7283 result_id,
7284 diagnostics,
7285 } => (result_id, diagnostics),
7286 };
7287 let disk_based_sources = Cow::Owned(
7288 lsp_store
7289 .language_server_adapter_for_id(server_id)
7290 .as_ref()
7291 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7292 .unwrap_or(&[])
7293 .to_vec(),
7294 );
7295 acc.entry(server_id)
7296 .or_insert_with(HashMap::default)
7297 .entry(new_registration_id.clone())
7298 .or_insert_with(Vec::new)
7299 .push(DocumentDiagnosticsUpdate {
7300 server_id,
7301 diagnostics: lsp::PublishDiagnosticsParams {
7302 uri,
7303 diagnostics,
7304 version: None,
7305 },
7306 result_id: result_id.map(SharedString::new),
7307 disk_based_sources,
7308 registration_id: new_registration_id,
7309 });
7310 acc
7311 },
7312 );
7313
7314 for diagnostic_updates in server_diagnostics_updates.into_values() {
7315 for (registration_id, diagnostic_updates) in diagnostic_updates {
7316 lsp_store
7317 .merge_lsp_diagnostics(
7318 DiagnosticSourceKind::Pulled,
7319 diagnostic_updates,
7320 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7321 DiagnosticSourceKind::Pulled => {
7322 old_diagnostic.registration_id != registration_id
7323 || unchanged_buffers
7324 .get(&old_diagnostic.registration_id)
7325 .is_some_and(|unchanged_buffers| {
7326 unchanged_buffers.contains(&document_uri)
7327 })
7328 }
7329 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7330 true
7331 }
7332 },
7333 cx,
7334 )
7335 .log_err();
7336 }
7337 }
7338 })
7339 })
7340 }
7341
7342 pub fn signature_help<T: ToPointUtf16>(
7343 &mut self,
7344 buffer: &Entity<Buffer>,
7345 position: T,
7346 cx: &mut Context<Self>,
7347 ) -> Task<Option<Vec<SignatureHelp>>> {
7348 let position = position.to_point_utf16(buffer.read(cx));
7349
7350 if let Some((client, upstream_project_id)) = self.upstream_client() {
7351 let request = GetSignatureHelp { position };
7352 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7353 return Task::ready(None);
7354 }
7355 let request_timeout = ProjectSettings::get_global(cx)
7356 .global_lsp_settings
7357 .get_request_timeout();
7358 let request_task = client.request_lsp(
7359 upstream_project_id,
7360 None,
7361 request_timeout,
7362 cx.background_executor().clone(),
7363 request.to_proto(upstream_project_id, buffer.read(cx)),
7364 );
7365 let buffer = buffer.clone();
7366 cx.spawn(async move |weak_lsp_store, cx| {
7367 let lsp_store = weak_lsp_store.upgrade()?;
7368 let signatures = join_all(
7369 request_task
7370 .await
7371 .log_err()
7372 .flatten()
7373 .map(|response| response.payload)
7374 .unwrap_or_default()
7375 .into_iter()
7376 .map(|response| {
7377 let response = GetSignatureHelp { position }.response_from_proto(
7378 response.response,
7379 lsp_store.clone(),
7380 buffer.clone(),
7381 cx.clone(),
7382 );
7383 async move { response.await.log_err().flatten() }
7384 }),
7385 )
7386 .await
7387 .into_iter()
7388 .flatten()
7389 .collect();
7390 Some(signatures)
7391 })
7392 } else {
7393 let all_actions_task = self.request_multiple_lsp_locally(
7394 buffer,
7395 Some(position),
7396 GetSignatureHelp { position },
7397 cx,
7398 );
7399 cx.background_spawn(async move {
7400 Some(
7401 all_actions_task
7402 .await
7403 .into_iter()
7404 .flat_map(|(_, actions)| actions)
7405 .collect::<Vec<_>>(),
7406 )
7407 })
7408 }
7409 }
7410
7411 pub fn hover(
7412 &mut self,
7413 buffer: &Entity<Buffer>,
7414 position: PointUtf16,
7415 cx: &mut Context<Self>,
7416 ) -> Task<Option<Vec<Hover>>> {
7417 if let Some((client, upstream_project_id)) = self.upstream_client() {
7418 let request = GetHover { position };
7419 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7420 return Task::ready(None);
7421 }
7422 let request_timeout = ProjectSettings::get_global(cx)
7423 .global_lsp_settings
7424 .get_request_timeout();
7425 let request_task = client.request_lsp(
7426 upstream_project_id,
7427 None,
7428 request_timeout,
7429 cx.background_executor().clone(),
7430 request.to_proto(upstream_project_id, buffer.read(cx)),
7431 );
7432 let buffer = buffer.clone();
7433 cx.spawn(async move |weak_lsp_store, cx| {
7434 let lsp_store = weak_lsp_store.upgrade()?;
7435 let hovers = join_all(
7436 request_task
7437 .await
7438 .log_err()
7439 .flatten()
7440 .map(|response| response.payload)
7441 .unwrap_or_default()
7442 .into_iter()
7443 .map(|response| {
7444 let response = GetHover { position }.response_from_proto(
7445 response.response,
7446 lsp_store.clone(),
7447 buffer.clone(),
7448 cx.clone(),
7449 );
7450 async move {
7451 response
7452 .await
7453 .log_err()
7454 .flatten()
7455 .and_then(remove_empty_hover_blocks)
7456 }
7457 }),
7458 )
7459 .await
7460 .into_iter()
7461 .flatten()
7462 .collect();
7463 Some(hovers)
7464 })
7465 } else {
7466 let all_actions_task = self.request_multiple_lsp_locally(
7467 buffer,
7468 Some(position),
7469 GetHover { position },
7470 cx,
7471 );
7472 cx.background_spawn(async move {
7473 Some(
7474 all_actions_task
7475 .await
7476 .into_iter()
7477 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7478 .collect::<Vec<Hover>>(),
7479 )
7480 })
7481 }
7482 }
7483
7484 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7485 let language_registry = self.languages.clone();
7486
7487 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7488 let request = upstream_client.request(proto::GetProjectSymbols {
7489 project_id: *project_id,
7490 query: query.to_string(),
7491 });
7492 cx.foreground_executor().spawn(async move {
7493 let response = request.await?;
7494 let mut symbols = Vec::new();
7495 let core_symbols = response
7496 .symbols
7497 .into_iter()
7498 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7499 .collect::<Vec<_>>();
7500 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7501 .await;
7502 Ok(symbols)
7503 })
7504 } else if let Some(local) = self.as_local() {
7505 struct WorkspaceSymbolsResult {
7506 server_id: LanguageServerId,
7507 lsp_adapter: Arc<CachedLspAdapter>,
7508 worktree: WeakEntity<Worktree>,
7509 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7510 }
7511
7512 let mut requests = Vec::new();
7513 let mut requested_servers = BTreeSet::new();
7514 let request_timeout = ProjectSettings::get_global(cx)
7515 .global_lsp_settings
7516 .get_request_timeout();
7517
7518 for (seed, state) in local.language_server_ids.iter() {
7519 let Some(worktree_handle) = self
7520 .worktree_store
7521 .read(cx)
7522 .worktree_for_id(seed.worktree_id, cx)
7523 else {
7524 continue;
7525 };
7526
7527 let worktree = worktree_handle.read(cx);
7528 if !worktree.is_visible() {
7529 continue;
7530 }
7531
7532 if !requested_servers.insert(state.id) {
7533 continue;
7534 }
7535
7536 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7537 Some(LanguageServerState::Running {
7538 adapter, server, ..
7539 }) => (adapter.clone(), server),
7540
7541 _ => continue,
7542 };
7543
7544 let supports_workspace_symbol_request =
7545 match server.capabilities().workspace_symbol_provider {
7546 Some(OneOf::Left(supported)) => supported,
7547 Some(OneOf::Right(_)) => true,
7548 None => false,
7549 };
7550
7551 if !supports_workspace_symbol_request {
7552 continue;
7553 }
7554
7555 let worktree_handle = worktree_handle.clone();
7556 let server_id = server.server_id();
7557 requests.push(
7558 server
7559 .request::<lsp::request::WorkspaceSymbolRequest>(
7560 lsp::WorkspaceSymbolParams {
7561 query: query.to_string(),
7562 ..Default::default()
7563 },
7564 request_timeout,
7565 )
7566 .map(move |response| {
7567 let lsp_symbols = response
7568 .into_response()
7569 .context("workspace symbols request")
7570 .log_err()
7571 .flatten()
7572 .map(|symbol_response| match symbol_response {
7573 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7574 flat_responses
7575 .into_iter()
7576 .map(|lsp_symbol| {
7577 (
7578 lsp_symbol.name,
7579 lsp_symbol.kind,
7580 lsp_symbol.location,
7581 lsp_symbol.container_name,
7582 )
7583 })
7584 .collect::<Vec<_>>()
7585 }
7586 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7587 nested_responses
7588 .into_iter()
7589 .filter_map(|lsp_symbol| {
7590 let location = match lsp_symbol.location {
7591 OneOf::Left(location) => location,
7592 OneOf::Right(_) => {
7593 log::error!(
7594 "Unexpected: client capabilities \
7595 forbid symbol resolutions in \
7596 workspace.symbol.resolveSupport"
7597 );
7598 return None;
7599 }
7600 };
7601 Some((
7602 lsp_symbol.name,
7603 lsp_symbol.kind,
7604 location,
7605 lsp_symbol.container_name,
7606 ))
7607 })
7608 .collect::<Vec<_>>()
7609 }
7610 })
7611 .unwrap_or_default();
7612
7613 WorkspaceSymbolsResult {
7614 server_id,
7615 lsp_adapter,
7616 worktree: worktree_handle.downgrade(),
7617 lsp_symbols,
7618 }
7619 }),
7620 );
7621 }
7622
7623 cx.spawn(async move |this, cx| {
7624 let responses = futures::future::join_all(requests).await;
7625 let this = match this.upgrade() {
7626 Some(this) => this,
7627 None => return Ok(Vec::new()),
7628 };
7629
7630 let mut symbols = Vec::new();
7631 for result in responses {
7632 let core_symbols = this.update(cx, |this, cx| {
7633 result
7634 .lsp_symbols
7635 .into_iter()
7636 .filter_map(
7637 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7638 let abs_path = symbol_location.uri.to_file_path().ok()?;
7639 let source_worktree = result.worktree.upgrade()?;
7640 let source_worktree_id = source_worktree.read(cx).id();
7641
7642 let path = if let Some((tree, rel_path)) =
7643 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7644 {
7645 let worktree_id = tree.read(cx).id();
7646 SymbolLocation::InProject(ProjectPath {
7647 worktree_id,
7648 path: rel_path,
7649 })
7650 } else {
7651 SymbolLocation::OutsideProject {
7652 signature: this.symbol_signature(&abs_path),
7653 abs_path: abs_path.into(),
7654 }
7655 };
7656
7657 Some(CoreSymbol {
7658 source_language_server_id: result.server_id,
7659 language_server_name: result.lsp_adapter.name.clone(),
7660 source_worktree_id,
7661 path,
7662 kind: symbol_kind,
7663 name: symbol_name,
7664 range: range_from_lsp(symbol_location.range),
7665 container_name,
7666 })
7667 },
7668 )
7669 .collect::<Vec<_>>()
7670 });
7671
7672 populate_labels_for_symbols(
7673 core_symbols,
7674 &language_registry,
7675 Some(result.lsp_adapter),
7676 &mut symbols,
7677 )
7678 .await;
7679 }
7680
7681 Ok(symbols)
7682 })
7683 } else {
7684 Task::ready(Err(anyhow!("No upstream client or local language server")))
7685 }
7686 }
7687
7688 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7689 let mut summary = DiagnosticSummary::default();
7690 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7691 summary.error_count += path_summary.error_count;
7692 summary.warning_count += path_summary.warning_count;
7693 }
7694 summary
7695 }
7696
7697 /// Returns the diagnostic summary for a specific project path.
7698 pub fn diagnostic_summary_for_path(
7699 &self,
7700 project_path: &ProjectPath,
7701 _: &App,
7702 ) -> DiagnosticSummary {
7703 if let Some(summaries) = self
7704 .diagnostic_summaries
7705 .get(&project_path.worktree_id)
7706 .and_then(|map| map.get(&project_path.path))
7707 {
7708 let (error_count, warning_count) = summaries.iter().fold(
7709 (0, 0),
7710 |(error_count, warning_count), (_language_server_id, summary)| {
7711 (
7712 error_count + summary.error_count,
7713 warning_count + summary.warning_count,
7714 )
7715 },
7716 );
7717
7718 DiagnosticSummary {
7719 error_count,
7720 warning_count,
7721 }
7722 } else {
7723 DiagnosticSummary::default()
7724 }
7725 }
7726
7727 pub fn diagnostic_summaries<'a>(
7728 &'a self,
7729 include_ignored: bool,
7730 cx: &'a App,
7731 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7732 self.worktree_store
7733 .read(cx)
7734 .visible_worktrees(cx)
7735 .filter_map(|worktree| {
7736 let worktree = worktree.read(cx);
7737 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7738 })
7739 .flat_map(move |(worktree, summaries)| {
7740 let worktree_id = worktree.id();
7741 summaries
7742 .iter()
7743 .filter(move |(path, _)| {
7744 include_ignored
7745 || worktree
7746 .entry_for_path(path.as_ref())
7747 .is_some_and(|entry| !entry.is_ignored)
7748 })
7749 .flat_map(move |(path, summaries)| {
7750 summaries.iter().map(move |(server_id, summary)| {
7751 (
7752 ProjectPath {
7753 worktree_id,
7754 path: path.clone(),
7755 },
7756 *server_id,
7757 *summary,
7758 )
7759 })
7760 })
7761 })
7762 }
7763
7764 pub fn on_buffer_edited(
7765 &mut self,
7766 buffer: Entity<Buffer>,
7767 cx: &mut Context<Self>,
7768 ) -> Option<()> {
7769 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7770 Some(
7771 self.as_local()?
7772 .language_servers_for_buffer(buffer, cx)
7773 .map(|i| i.1.clone())
7774 .collect(),
7775 )
7776 })?;
7777
7778 let buffer = buffer.read(cx);
7779 let file = File::from_dyn(buffer.file())?;
7780 let abs_path = file.as_local()?.abs_path(cx);
7781 let uri = lsp::Uri::from_file_path(&abs_path)
7782 .ok()
7783 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7784 .log_err()?;
7785 let next_snapshot = buffer.text_snapshot();
7786 for language_server in language_servers {
7787 let language_server = language_server.clone();
7788
7789 let buffer_snapshots = self
7790 .as_local_mut()?
7791 .buffer_snapshots
7792 .get_mut(&buffer.remote_id())
7793 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7794 let previous_snapshot = buffer_snapshots.last()?;
7795
7796 let build_incremental_change = || {
7797 buffer
7798 .edits_since::<Dimensions<PointUtf16, usize>>(
7799 previous_snapshot.snapshot.version(),
7800 )
7801 .map(|edit| {
7802 let edit_start = edit.new.start.0;
7803 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7804 let new_text = next_snapshot
7805 .text_for_range(edit.new.start.1..edit.new.end.1)
7806 .collect();
7807 lsp::TextDocumentContentChangeEvent {
7808 range: Some(lsp::Range::new(
7809 point_to_lsp(edit_start),
7810 point_to_lsp(edit_end),
7811 )),
7812 range_length: None,
7813 text: new_text,
7814 }
7815 })
7816 .collect()
7817 };
7818
7819 let document_sync_kind = language_server
7820 .capabilities()
7821 .text_document_sync
7822 .as_ref()
7823 .and_then(|sync| match sync {
7824 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7825 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7826 });
7827
7828 let content_changes: Vec<_> = match document_sync_kind {
7829 Some(lsp::TextDocumentSyncKind::FULL) => {
7830 vec![lsp::TextDocumentContentChangeEvent {
7831 range: None,
7832 range_length: None,
7833 text: next_snapshot.text(),
7834 }]
7835 }
7836 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7837 _ => {
7838 #[cfg(any(test, feature = "test-support"))]
7839 {
7840 build_incremental_change()
7841 }
7842
7843 #[cfg(not(any(test, feature = "test-support")))]
7844 {
7845 continue;
7846 }
7847 }
7848 };
7849
7850 let next_version = previous_snapshot.version + 1;
7851 buffer_snapshots.push(LspBufferSnapshot {
7852 version: next_version,
7853 snapshot: next_snapshot.clone(),
7854 });
7855
7856 language_server
7857 .notify::<lsp::notification::DidChangeTextDocument>(
7858 lsp::DidChangeTextDocumentParams {
7859 text_document: lsp::VersionedTextDocumentIdentifier::new(
7860 uri.clone(),
7861 next_version,
7862 ),
7863 content_changes,
7864 },
7865 )
7866 .ok();
7867 self.pull_workspace_diagnostics(language_server.server_id());
7868 }
7869
7870 None
7871 }
7872
7873 pub fn on_buffer_saved(
7874 &mut self,
7875 buffer: Entity<Buffer>,
7876 cx: &mut Context<Self>,
7877 ) -> Option<()> {
7878 let file = File::from_dyn(buffer.read(cx).file())?;
7879 let worktree_id = file.worktree_id(cx);
7880 let abs_path = file.as_local()?.abs_path(cx);
7881 let text_document = lsp::TextDocumentIdentifier {
7882 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7883 };
7884 let local = self.as_local()?;
7885
7886 for server in local.language_servers_for_worktree(worktree_id) {
7887 if let Some(include_text) = include_text(server.as_ref()) {
7888 let text = if include_text {
7889 Some(buffer.read(cx).text())
7890 } else {
7891 None
7892 };
7893 server
7894 .notify::<lsp::notification::DidSaveTextDocument>(
7895 lsp::DidSaveTextDocumentParams {
7896 text_document: text_document.clone(),
7897 text,
7898 },
7899 )
7900 .ok();
7901 }
7902 }
7903
7904 let language_servers = buffer.update(cx, |buffer, cx| {
7905 local.language_server_ids_for_buffer(buffer, cx)
7906 });
7907 for language_server_id in language_servers {
7908 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7909 }
7910
7911 None
7912 }
7913
7914 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7915 maybe!(async move {
7916 let mut refreshed_servers = HashSet::default();
7917 let servers = lsp_store
7918 .update(cx, |lsp_store, cx| {
7919 let local = lsp_store.as_local()?;
7920
7921 let servers = local
7922 .language_server_ids
7923 .iter()
7924 .filter_map(|(seed, state)| {
7925 let worktree = lsp_store
7926 .worktree_store
7927 .read(cx)
7928 .worktree_for_id(seed.worktree_id, cx);
7929 let delegate: Arc<dyn LspAdapterDelegate> =
7930 worktree.map(|worktree| {
7931 LocalLspAdapterDelegate::new(
7932 local.languages.clone(),
7933 &local.environment,
7934 cx.weak_entity(),
7935 &worktree,
7936 local.http_client.clone(),
7937 local.fs.clone(),
7938 cx,
7939 )
7940 })?;
7941 let server_id = state.id;
7942
7943 let states = local.language_servers.get(&server_id)?;
7944
7945 match states {
7946 LanguageServerState::Starting { .. } => None,
7947 LanguageServerState::Running {
7948 adapter, server, ..
7949 } => {
7950 let adapter = adapter.clone();
7951 let server = server.clone();
7952 refreshed_servers.insert(server.name());
7953 let toolchain = seed.toolchain.clone();
7954 Some(cx.spawn(async move |_, cx| {
7955 let settings =
7956 LocalLspStore::workspace_configuration_for_adapter(
7957 adapter.adapter.clone(),
7958 &delegate,
7959 toolchain,
7960 None,
7961 cx,
7962 )
7963 .await
7964 .ok()?;
7965 server
7966 .notify::<lsp::notification::DidChangeConfiguration>(
7967 lsp::DidChangeConfigurationParams { settings },
7968 )
7969 .ok()?;
7970 Some(())
7971 }))
7972 }
7973 }
7974 })
7975 .collect::<Vec<_>>();
7976
7977 Some(servers)
7978 })
7979 .ok()
7980 .flatten()?;
7981
7982 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7983 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7984 // to stop and unregister its language server wrapper.
7985 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7986 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7987 let _: Vec<Option<()>> = join_all(servers).await;
7988
7989 Some(())
7990 })
7991 .await;
7992 }
7993
7994 fn maintain_workspace_config(
7995 external_refresh_requests: watch::Receiver<()>,
7996 cx: &mut Context<Self>,
7997 ) -> Task<Result<()>> {
7998 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7999 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8000
8001 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8002 *settings_changed_tx.borrow_mut() = ();
8003 });
8004
8005 let mut joint_future =
8006 futures::stream::select(settings_changed_rx, external_refresh_requests);
8007 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8008 // - 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).
8009 // - 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.
8010 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8011 // - 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,
8012 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8013 cx.spawn(async move |this, cx| {
8014 while let Some(()) = joint_future.next().await {
8015 this.update(cx, |this, cx| {
8016 this.refresh_server_tree(cx);
8017 })
8018 .ok();
8019
8020 Self::refresh_workspace_configurations(&this, cx).await;
8021 }
8022
8023 drop(settings_observation);
8024 anyhow::Ok(())
8025 })
8026 }
8027
8028 pub fn running_language_servers_for_local_buffer<'a>(
8029 &'a self,
8030 buffer: &Buffer,
8031 cx: &mut App,
8032 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8033 let local = self.as_local();
8034 let language_server_ids = local
8035 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8036 .unwrap_or_default();
8037
8038 language_server_ids
8039 .into_iter()
8040 .filter_map(
8041 move |server_id| match local?.language_servers.get(&server_id)? {
8042 LanguageServerState::Running {
8043 adapter, server, ..
8044 } => Some((adapter, server)),
8045 _ => None,
8046 },
8047 )
8048 }
8049
8050 pub fn language_servers_for_local_buffer(
8051 &self,
8052 buffer: &Buffer,
8053 cx: &mut App,
8054 ) -> Vec<LanguageServerId> {
8055 let local = self.as_local();
8056 local
8057 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8058 .unwrap_or_default()
8059 }
8060
8061 pub fn language_server_for_local_buffer<'a>(
8062 &'a self,
8063 buffer: &'a Buffer,
8064 server_id: LanguageServerId,
8065 cx: &'a mut App,
8066 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8067 self.as_local()?
8068 .language_servers_for_buffer(buffer, cx)
8069 .find(|(_, s)| s.server_id() == server_id)
8070 }
8071
8072 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8073 self.diagnostic_summaries.remove(&id_to_remove);
8074 if let Some(local) = self.as_local_mut() {
8075 let to_remove = local.remove_worktree(id_to_remove, cx);
8076 for server in to_remove {
8077 self.language_server_statuses.remove(&server);
8078 }
8079 }
8080 }
8081
8082 pub fn shared(
8083 &mut self,
8084 project_id: u64,
8085 downstream_client: AnyProtoClient,
8086 _: &mut Context<Self>,
8087 ) {
8088 self.downstream_client = Some((downstream_client.clone(), project_id));
8089
8090 for (server_id, status) in &self.language_server_statuses {
8091 if let Some(server) = self.language_server_for_id(*server_id) {
8092 downstream_client
8093 .send(proto::StartLanguageServer {
8094 project_id,
8095 server: Some(proto::LanguageServer {
8096 id: server_id.to_proto(),
8097 name: status.name.to_string(),
8098 worktree_id: status.worktree.map(|id| id.to_proto()),
8099 }),
8100 capabilities: serde_json::to_string(&server.capabilities())
8101 .expect("serializing server LSP capabilities"),
8102 })
8103 .log_err();
8104 }
8105 }
8106 }
8107
8108 pub fn disconnected_from_host(&mut self) {
8109 self.downstream_client.take();
8110 }
8111
8112 pub fn disconnected_from_ssh_remote(&mut self) {
8113 if let LspStoreMode::Remote(RemoteLspStore {
8114 upstream_client, ..
8115 }) = &mut self.mode
8116 {
8117 upstream_client.take();
8118 }
8119 }
8120
8121 pub(crate) fn set_language_server_statuses_from_proto(
8122 &mut self,
8123 project: WeakEntity<Project>,
8124 language_servers: Vec<proto::LanguageServer>,
8125 server_capabilities: Vec<String>,
8126 cx: &mut Context<Self>,
8127 ) {
8128 let lsp_logs = cx
8129 .try_global::<GlobalLogStore>()
8130 .map(|lsp_store| lsp_store.0.clone());
8131
8132 self.language_server_statuses = language_servers
8133 .into_iter()
8134 .zip(server_capabilities)
8135 .map(|(server, server_capabilities)| {
8136 let server_id = LanguageServerId(server.id as usize);
8137 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8138 self.lsp_server_capabilities
8139 .insert(server_id, server_capabilities);
8140 }
8141
8142 let name = LanguageServerName::from_proto(server.name);
8143 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8144
8145 if let Some(lsp_logs) = &lsp_logs {
8146 lsp_logs.update(cx, |lsp_logs, cx| {
8147 lsp_logs.add_language_server(
8148 // Only remote clients get their language servers set from proto
8149 LanguageServerKind::Remote {
8150 project: project.clone(),
8151 },
8152 server_id,
8153 Some(name.clone()),
8154 worktree,
8155 None,
8156 cx,
8157 );
8158 });
8159 }
8160
8161 (
8162 server_id,
8163 LanguageServerStatus {
8164 name,
8165 server_version: None,
8166 pending_work: Default::default(),
8167 has_pending_diagnostic_updates: false,
8168 progress_tokens: Default::default(),
8169 worktree,
8170 binary: None,
8171 configuration: None,
8172 workspace_folders: BTreeSet::new(),
8173 process_id: None,
8174 },
8175 )
8176 })
8177 .collect();
8178 }
8179
8180 #[cfg(feature = "test-support")]
8181 pub fn update_diagnostic_entries(
8182 &mut self,
8183 server_id: LanguageServerId,
8184 abs_path: PathBuf,
8185 result_id: Option<SharedString>,
8186 version: Option<i32>,
8187 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8188 cx: &mut Context<Self>,
8189 ) -> anyhow::Result<()> {
8190 self.merge_diagnostic_entries(
8191 vec![DocumentDiagnosticsUpdate {
8192 diagnostics: DocumentDiagnostics {
8193 diagnostics,
8194 document_abs_path: abs_path,
8195 version,
8196 },
8197 result_id,
8198 server_id,
8199 disk_based_sources: Cow::Borrowed(&[]),
8200 registration_id: None,
8201 }],
8202 |_, _, _| false,
8203 cx,
8204 )?;
8205 Ok(())
8206 }
8207
8208 pub fn merge_diagnostic_entries<'a>(
8209 &mut self,
8210 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8211 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8212 cx: &mut Context<Self>,
8213 ) -> anyhow::Result<()> {
8214 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8215 let mut updated_diagnostics_paths = HashMap::default();
8216 for mut update in diagnostic_updates {
8217 let abs_path = &update.diagnostics.document_abs_path;
8218 let server_id = update.server_id;
8219 let Some((worktree, relative_path)) =
8220 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8221 else {
8222 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8223 return Ok(());
8224 };
8225
8226 let worktree_id = worktree.read(cx).id();
8227 let project_path = ProjectPath {
8228 worktree_id,
8229 path: relative_path,
8230 };
8231
8232 let document_uri = lsp::Uri::from_file_path(abs_path)
8233 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8234 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8235 let snapshot = buffer_handle.read(cx).snapshot();
8236 let buffer = buffer_handle.read(cx);
8237 let reused_diagnostics = buffer
8238 .buffer_diagnostics(Some(server_id))
8239 .iter()
8240 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8241 .map(|v| {
8242 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8243 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8244 DiagnosticEntry {
8245 range: start..end,
8246 diagnostic: v.diagnostic.clone(),
8247 }
8248 })
8249 .collect::<Vec<_>>();
8250
8251 self.as_local_mut()
8252 .context("cannot merge diagnostics on a remote LspStore")?
8253 .update_buffer_diagnostics(
8254 &buffer_handle,
8255 server_id,
8256 Some(update.registration_id),
8257 update.result_id,
8258 update.diagnostics.version,
8259 update.diagnostics.diagnostics.clone(),
8260 reused_diagnostics.clone(),
8261 cx,
8262 )?;
8263
8264 update.diagnostics.diagnostics.extend(reused_diagnostics);
8265 } else if let Some(local) = self.as_local() {
8266 let reused_diagnostics = local
8267 .diagnostics
8268 .get(&worktree_id)
8269 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8270 .and_then(|diagnostics_by_server_id| {
8271 diagnostics_by_server_id
8272 .binary_search_by_key(&server_id, |e| e.0)
8273 .ok()
8274 .map(|ix| &diagnostics_by_server_id[ix].1)
8275 })
8276 .into_iter()
8277 .flatten()
8278 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8279
8280 update
8281 .diagnostics
8282 .diagnostics
8283 .extend(reused_diagnostics.cloned());
8284 }
8285
8286 let updated = worktree.update(cx, |worktree, cx| {
8287 self.update_worktree_diagnostics(
8288 worktree.id(),
8289 server_id,
8290 project_path.path.clone(),
8291 update.diagnostics.diagnostics,
8292 cx,
8293 )
8294 })?;
8295 match updated {
8296 ControlFlow::Continue(new_summary) => {
8297 if let Some((project_id, new_summary)) = new_summary {
8298 match &mut diagnostics_summary {
8299 Some(diagnostics_summary) => {
8300 diagnostics_summary
8301 .more_summaries
8302 .push(proto::DiagnosticSummary {
8303 path: project_path.path.as_ref().to_proto(),
8304 language_server_id: server_id.0 as u64,
8305 error_count: new_summary.error_count,
8306 warning_count: new_summary.warning_count,
8307 })
8308 }
8309 None => {
8310 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8311 project_id,
8312 worktree_id: worktree_id.to_proto(),
8313 summary: Some(proto::DiagnosticSummary {
8314 path: project_path.path.as_ref().to_proto(),
8315 language_server_id: server_id.0 as u64,
8316 error_count: new_summary.error_count,
8317 warning_count: new_summary.warning_count,
8318 }),
8319 more_summaries: Vec::new(),
8320 })
8321 }
8322 }
8323 }
8324 updated_diagnostics_paths
8325 .entry(server_id)
8326 .or_insert_with(Vec::new)
8327 .push(project_path);
8328 }
8329 ControlFlow::Break(()) => {}
8330 }
8331 }
8332
8333 if let Some((diagnostics_summary, (downstream_client, _))) =
8334 diagnostics_summary.zip(self.downstream_client.as_ref())
8335 {
8336 downstream_client.send(diagnostics_summary).log_err();
8337 }
8338 for (server_id, paths) in updated_diagnostics_paths {
8339 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8340 }
8341 Ok(())
8342 }
8343
8344 fn update_worktree_diagnostics(
8345 &mut self,
8346 worktree_id: WorktreeId,
8347 server_id: LanguageServerId,
8348 path_in_worktree: Arc<RelPath>,
8349 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8350 _: &mut Context<Worktree>,
8351 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8352 let local = match &mut self.mode {
8353 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8354 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8355 };
8356
8357 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8358 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8359 let summaries_by_server_id = summaries_for_tree
8360 .entry(path_in_worktree.clone())
8361 .or_default();
8362
8363 let old_summary = summaries_by_server_id
8364 .remove(&server_id)
8365 .unwrap_or_default();
8366
8367 let new_summary = DiagnosticSummary::new(&diagnostics);
8368 if diagnostics.is_empty() {
8369 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8370 {
8371 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8372 diagnostics_by_server_id.remove(ix);
8373 }
8374 if diagnostics_by_server_id.is_empty() {
8375 diagnostics_for_tree.remove(&path_in_worktree);
8376 }
8377 }
8378 } else {
8379 summaries_by_server_id.insert(server_id, new_summary);
8380 let diagnostics_by_server_id = diagnostics_for_tree
8381 .entry(path_in_worktree.clone())
8382 .or_default();
8383 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8384 Ok(ix) => {
8385 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8386 }
8387 Err(ix) => {
8388 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8389 }
8390 }
8391 }
8392
8393 if !old_summary.is_empty() || !new_summary.is_empty() {
8394 if let Some((_, project_id)) = &self.downstream_client {
8395 Ok(ControlFlow::Continue(Some((
8396 *project_id,
8397 proto::DiagnosticSummary {
8398 path: path_in_worktree.to_proto(),
8399 language_server_id: server_id.0 as u64,
8400 error_count: new_summary.error_count as u32,
8401 warning_count: new_summary.warning_count as u32,
8402 },
8403 ))))
8404 } else {
8405 Ok(ControlFlow::Continue(None))
8406 }
8407 } else {
8408 Ok(ControlFlow::Break(()))
8409 }
8410 }
8411
8412 pub fn open_buffer_for_symbol(
8413 &mut self,
8414 symbol: &Symbol,
8415 cx: &mut Context<Self>,
8416 ) -> Task<Result<Entity<Buffer>>> {
8417 if let Some((client, project_id)) = self.upstream_client() {
8418 let request = client.request(proto::OpenBufferForSymbol {
8419 project_id,
8420 symbol: Some(Self::serialize_symbol(symbol)),
8421 });
8422 cx.spawn(async move |this, cx| {
8423 let response = request.await?;
8424 let buffer_id = BufferId::new(response.buffer_id)?;
8425 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8426 .await
8427 })
8428 } else if let Some(local) = self.as_local() {
8429 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8430 seed.worktree_id == symbol.source_worktree_id
8431 && state.id == symbol.source_language_server_id
8432 && symbol.language_server_name == seed.name
8433 });
8434 if !is_valid {
8435 return Task::ready(Err(anyhow!(
8436 "language server for worktree and language not found"
8437 )));
8438 };
8439
8440 let symbol_abs_path = match &symbol.path {
8441 SymbolLocation::InProject(project_path) => self
8442 .worktree_store
8443 .read(cx)
8444 .absolutize(&project_path, cx)
8445 .context("no such worktree"),
8446 SymbolLocation::OutsideProject {
8447 abs_path,
8448 signature: _,
8449 } => Ok(abs_path.to_path_buf()),
8450 };
8451 let symbol_abs_path = match symbol_abs_path {
8452 Ok(abs_path) => abs_path,
8453 Err(err) => return Task::ready(Err(err)),
8454 };
8455 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8456 uri
8457 } else {
8458 return Task::ready(Err(anyhow!("invalid symbol path")));
8459 };
8460
8461 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8462 } else {
8463 Task::ready(Err(anyhow!("no upstream client or local store")))
8464 }
8465 }
8466
8467 pub(crate) fn open_local_buffer_via_lsp(
8468 &mut self,
8469 abs_path: lsp::Uri,
8470 language_server_id: LanguageServerId,
8471 cx: &mut Context<Self>,
8472 ) -> Task<Result<Entity<Buffer>>> {
8473 let path_style = self.worktree_store.read(cx).path_style();
8474 cx.spawn(async move |lsp_store, cx| {
8475 // Escape percent-encoded string.
8476 let current_scheme = abs_path.scheme().to_owned();
8477 // Uri is immutable, so we can't modify the scheme
8478
8479 let abs_path = abs_path
8480 .to_file_path_ext(path_style)
8481 .map_err(|()| anyhow!("can't convert URI to path"))?;
8482 let p = abs_path.clone();
8483 let yarn_worktree = lsp_store
8484 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8485 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8486 cx.spawn(async move |this, cx| {
8487 let t = this
8488 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8489 .ok()?;
8490 t.await
8491 })
8492 }),
8493 None => Task::ready(None),
8494 })?
8495 .await;
8496 let (worktree_root_target, known_relative_path) =
8497 if let Some((zip_root, relative_path)) = yarn_worktree {
8498 (zip_root, Some(relative_path))
8499 } else {
8500 (Arc::<Path>::from(abs_path.as_path()), None)
8501 };
8502 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8503 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8504 worktree_store.find_worktree(&worktree_root_target, cx)
8505 })
8506 })?;
8507 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8508 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8509 (result.0, relative_path, None)
8510 } else {
8511 let worktree = lsp_store
8512 .update(cx, |lsp_store, cx| {
8513 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8514 worktree_store.create_worktree(&worktree_root_target, false, cx)
8515 })
8516 })?
8517 .await?;
8518 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8519 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8520 lsp_store
8521 .update(cx, |lsp_store, cx| {
8522 if let Some(local) = lsp_store.as_local_mut() {
8523 local.register_language_server_for_invisible_worktree(
8524 &worktree,
8525 language_server_id,
8526 cx,
8527 )
8528 }
8529 match lsp_store.language_server_statuses.get(&language_server_id) {
8530 Some(status) => status.worktree,
8531 None => None,
8532 }
8533 })
8534 .ok()
8535 .flatten()
8536 .zip(Some(worktree_root.clone()))
8537 } else {
8538 None
8539 };
8540 let relative_path = if let Some(known_path) = known_relative_path {
8541 known_path
8542 } else {
8543 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8544 .into_arc()
8545 };
8546 (worktree, relative_path, source_ws)
8547 };
8548 let project_path = ProjectPath {
8549 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8550 path: relative_path,
8551 };
8552 let buffer = lsp_store
8553 .update(cx, |lsp_store, cx| {
8554 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8555 buffer_store.open_buffer(project_path, cx)
8556 })
8557 })?
8558 .await?;
8559 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8560 if let Some((source_ws, worktree_root)) = source_ws {
8561 buffer.update(cx, |buffer, cx| {
8562 let settings = WorktreeSettings::get(
8563 Some(
8564 (&ProjectPath {
8565 worktree_id: source_ws,
8566 path: Arc::from(RelPath::empty()),
8567 })
8568 .into(),
8569 ),
8570 cx,
8571 );
8572 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8573 if is_read_only {
8574 buffer.set_capability(Capability::ReadOnly, cx);
8575 }
8576 });
8577 }
8578 Ok(buffer)
8579 })
8580 }
8581
8582 fn local_lsp_servers_for_buffer(
8583 &self,
8584 buffer: &Entity<Buffer>,
8585 cx: &mut Context<Self>,
8586 ) -> Vec<LanguageServerId> {
8587 let Some(local) = self.as_local() else {
8588 return Vec::new();
8589 };
8590
8591 let snapshot = buffer.read(cx).snapshot();
8592
8593 buffer.update(cx, |buffer, cx| {
8594 local
8595 .language_servers_for_buffer(buffer, cx)
8596 .map(|(_, server)| server.server_id())
8597 .filter(|server_id| {
8598 self.as_local().is_none_or(|local| {
8599 local
8600 .buffers_opened_in_servers
8601 .get(&snapshot.remote_id())
8602 .is_some_and(|servers| servers.contains(server_id))
8603 })
8604 })
8605 .collect()
8606 })
8607 }
8608
8609 fn request_multiple_lsp_locally<P, R>(
8610 &mut self,
8611 buffer: &Entity<Buffer>,
8612 position: Option<P>,
8613 request: R,
8614 cx: &mut Context<Self>,
8615 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8616 where
8617 P: ToOffset,
8618 R: LspCommand + Clone,
8619 <R::LspRequest as lsp::request::Request>::Result: Send,
8620 <R::LspRequest as lsp::request::Request>::Params: Send,
8621 {
8622 let Some(local) = self.as_local() else {
8623 return Task::ready(Vec::new());
8624 };
8625
8626 let snapshot = buffer.read(cx).snapshot();
8627 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8628
8629 let server_ids = buffer.update(cx, |buffer, cx| {
8630 local
8631 .language_servers_for_buffer(buffer, cx)
8632 .filter(|(adapter, _)| {
8633 scope
8634 .as_ref()
8635 .map(|scope| scope.language_allowed(&adapter.name))
8636 .unwrap_or(true)
8637 })
8638 .map(|(_, server)| server.server_id())
8639 .filter(|server_id| {
8640 self.as_local().is_none_or(|local| {
8641 local
8642 .buffers_opened_in_servers
8643 .get(&snapshot.remote_id())
8644 .is_some_and(|servers| servers.contains(server_id))
8645 })
8646 })
8647 .collect::<Vec<_>>()
8648 });
8649
8650 let mut response_results = server_ids
8651 .into_iter()
8652 .map(|server_id| {
8653 let task = self.request_lsp(
8654 buffer.clone(),
8655 LanguageServerToQuery::Other(server_id),
8656 request.clone(),
8657 cx,
8658 );
8659 async move { (server_id, task.await) }
8660 })
8661 .collect::<FuturesUnordered<_>>();
8662
8663 cx.background_spawn(async move {
8664 let mut responses = Vec::with_capacity(response_results.len());
8665 while let Some((server_id, response_result)) = response_results.next().await {
8666 match response_result {
8667 Ok(response) => responses.push((server_id, response)),
8668 // rust-analyzer likes to error with this when its still loading up
8669 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8670 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8671 }
8672 }
8673 responses
8674 })
8675 }
8676
8677 async fn handle_lsp_get_completions(
8678 this: Entity<Self>,
8679 envelope: TypedEnvelope<proto::GetCompletions>,
8680 mut cx: AsyncApp,
8681 ) -> Result<proto::GetCompletionsResponse> {
8682 let sender_id = envelope.original_sender_id().unwrap_or_default();
8683
8684 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8685 let buffer_handle = this.update(&mut cx, |this, cx| {
8686 this.buffer_store.read(cx).get_existing(buffer_id)
8687 })?;
8688 let request = GetCompletions::from_proto(
8689 envelope.payload,
8690 this.clone(),
8691 buffer_handle.clone(),
8692 cx.clone(),
8693 )
8694 .await?;
8695
8696 let server_to_query = match request.server_id {
8697 Some(server_id) => LanguageServerToQuery::Other(server_id),
8698 None => LanguageServerToQuery::FirstCapable,
8699 };
8700
8701 let response = this
8702 .update(&mut cx, |this, cx| {
8703 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8704 })
8705 .await?;
8706 this.update(&mut cx, |this, cx| {
8707 Ok(GetCompletions::response_to_proto(
8708 response,
8709 this,
8710 sender_id,
8711 &buffer_handle.read(cx).version(),
8712 cx,
8713 ))
8714 })
8715 }
8716
8717 async fn handle_lsp_command<T: LspCommand>(
8718 this: Entity<Self>,
8719 envelope: TypedEnvelope<T::ProtoRequest>,
8720 mut cx: AsyncApp,
8721 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8722 where
8723 <T::LspRequest as lsp::request::Request>::Params: Send,
8724 <T::LspRequest as lsp::request::Request>::Result: Send,
8725 {
8726 let sender_id = envelope.original_sender_id().unwrap_or_default();
8727 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8728 let buffer_handle = this.update(&mut cx, |this, cx| {
8729 this.buffer_store.read(cx).get_existing(buffer_id)
8730 })?;
8731 let request = T::from_proto(
8732 envelope.payload,
8733 this.clone(),
8734 buffer_handle.clone(),
8735 cx.clone(),
8736 )
8737 .await?;
8738 let response = this
8739 .update(&mut cx, |this, cx| {
8740 this.request_lsp(
8741 buffer_handle.clone(),
8742 LanguageServerToQuery::FirstCapable,
8743 request,
8744 cx,
8745 )
8746 })
8747 .await?;
8748 this.update(&mut cx, |this, cx| {
8749 Ok(T::response_to_proto(
8750 response,
8751 this,
8752 sender_id,
8753 &buffer_handle.read(cx).version(),
8754 cx,
8755 ))
8756 })
8757 }
8758
8759 async fn handle_lsp_query(
8760 lsp_store: Entity<Self>,
8761 envelope: TypedEnvelope<proto::LspQuery>,
8762 mut cx: AsyncApp,
8763 ) -> Result<proto::Ack> {
8764 use proto::lsp_query::Request;
8765 let sender_id = envelope.original_sender_id().unwrap_or_default();
8766 let lsp_query = envelope.payload;
8767 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8768 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8769 match lsp_query.request.context("invalid LSP query request")? {
8770 Request::GetReferences(get_references) => {
8771 let position = get_references.position.clone().and_then(deserialize_anchor);
8772 Self::query_lsp_locally::<GetReferences>(
8773 lsp_store,
8774 server_id,
8775 sender_id,
8776 lsp_request_id,
8777 get_references,
8778 position,
8779 &mut cx,
8780 )
8781 .await?;
8782 }
8783 Request::GetDocumentColor(get_document_color) => {
8784 Self::query_lsp_locally::<GetDocumentColor>(
8785 lsp_store,
8786 server_id,
8787 sender_id,
8788 lsp_request_id,
8789 get_document_color,
8790 None,
8791 &mut cx,
8792 )
8793 .await?;
8794 }
8795 Request::GetFoldingRanges(get_folding_ranges) => {
8796 Self::query_lsp_locally::<GetFoldingRanges>(
8797 lsp_store,
8798 server_id,
8799 sender_id,
8800 lsp_request_id,
8801 get_folding_ranges,
8802 None,
8803 &mut cx,
8804 )
8805 .await?;
8806 }
8807 Request::GetHover(get_hover) => {
8808 let position = get_hover.position.clone().and_then(deserialize_anchor);
8809 Self::query_lsp_locally::<GetHover>(
8810 lsp_store,
8811 server_id,
8812 sender_id,
8813 lsp_request_id,
8814 get_hover,
8815 position,
8816 &mut cx,
8817 )
8818 .await?;
8819 }
8820 Request::GetCodeActions(get_code_actions) => {
8821 Self::query_lsp_locally::<GetCodeActions>(
8822 lsp_store,
8823 server_id,
8824 sender_id,
8825 lsp_request_id,
8826 get_code_actions,
8827 None,
8828 &mut cx,
8829 )
8830 .await?;
8831 }
8832 Request::GetSignatureHelp(get_signature_help) => {
8833 let position = get_signature_help
8834 .position
8835 .clone()
8836 .and_then(deserialize_anchor);
8837 Self::query_lsp_locally::<GetSignatureHelp>(
8838 lsp_store,
8839 server_id,
8840 sender_id,
8841 lsp_request_id,
8842 get_signature_help,
8843 position,
8844 &mut cx,
8845 )
8846 .await?;
8847 }
8848 Request::GetCodeLens(get_code_lens) => {
8849 Self::query_lsp_locally::<GetCodeLens>(
8850 lsp_store,
8851 server_id,
8852 sender_id,
8853 lsp_request_id,
8854 get_code_lens,
8855 None,
8856 &mut cx,
8857 )
8858 .await?;
8859 }
8860 Request::GetDefinition(get_definition) => {
8861 let position = get_definition.position.clone().and_then(deserialize_anchor);
8862 Self::query_lsp_locally::<GetDefinitions>(
8863 lsp_store,
8864 server_id,
8865 sender_id,
8866 lsp_request_id,
8867 get_definition,
8868 position,
8869 &mut cx,
8870 )
8871 .await?;
8872 }
8873 Request::GetDeclaration(get_declaration) => {
8874 let position = get_declaration
8875 .position
8876 .clone()
8877 .and_then(deserialize_anchor);
8878 Self::query_lsp_locally::<GetDeclarations>(
8879 lsp_store,
8880 server_id,
8881 sender_id,
8882 lsp_request_id,
8883 get_declaration,
8884 position,
8885 &mut cx,
8886 )
8887 .await?;
8888 }
8889 Request::GetTypeDefinition(get_type_definition) => {
8890 let position = get_type_definition
8891 .position
8892 .clone()
8893 .and_then(deserialize_anchor);
8894 Self::query_lsp_locally::<GetTypeDefinitions>(
8895 lsp_store,
8896 server_id,
8897 sender_id,
8898 lsp_request_id,
8899 get_type_definition,
8900 position,
8901 &mut cx,
8902 )
8903 .await?;
8904 }
8905 Request::GetImplementation(get_implementation) => {
8906 let position = get_implementation
8907 .position
8908 .clone()
8909 .and_then(deserialize_anchor);
8910 Self::query_lsp_locally::<GetImplementations>(
8911 lsp_store,
8912 server_id,
8913 sender_id,
8914 lsp_request_id,
8915 get_implementation,
8916 position,
8917 &mut cx,
8918 )
8919 .await?;
8920 }
8921 Request::InlayHints(inlay_hints) => {
8922 let query_start = inlay_hints
8923 .start
8924 .clone()
8925 .and_then(deserialize_anchor)
8926 .context("invalid inlay hints range start")?;
8927 let query_end = inlay_hints
8928 .end
8929 .clone()
8930 .and_then(deserialize_anchor)
8931 .context("invalid inlay hints range end")?;
8932 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8933 &lsp_store,
8934 server_id,
8935 lsp_request_id,
8936 &inlay_hints,
8937 query_start..query_end,
8938 &mut cx,
8939 )
8940 .await
8941 .context("preparing inlay hints request")?;
8942 Self::query_lsp_locally::<InlayHints>(
8943 lsp_store,
8944 server_id,
8945 sender_id,
8946 lsp_request_id,
8947 inlay_hints,
8948 None,
8949 &mut cx,
8950 )
8951 .await
8952 .context("querying for inlay hints")?
8953 }
8954 //////////////////////////////
8955 // Below are LSP queries that need to fetch more data,
8956 // hence cannot just proxy the request to language server with `query_lsp_locally`.
8957 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8958 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
8959 &lsp_store,
8960 &get_document_diagnostics,
8961 &mut cx,
8962 )
8963 .await?;
8964 lsp_store.update(&mut cx, |lsp_store, cx| {
8965 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8966 let key = LspKey {
8967 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8968 server_queried: server_id,
8969 };
8970 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8971 ) {
8972 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8973 lsp_requests.clear();
8974 };
8975 }
8976
8977 lsp_data.lsp_requests.entry(key).or_default().insert(
8978 lsp_request_id,
8979 cx.spawn(async move |lsp_store, cx| {
8980 let diagnostics_pull = lsp_store
8981 .update(cx, |lsp_store, cx| {
8982 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8983 })
8984 .ok();
8985 if let Some(diagnostics_pull) = diagnostics_pull {
8986 match diagnostics_pull.await {
8987 Ok(()) => {}
8988 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8989 };
8990 }
8991 }),
8992 );
8993 });
8994 }
8995 Request::SemanticTokens(semantic_tokens) => {
8996 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
8997 &lsp_store,
8998 &semantic_tokens,
8999 &mut cx,
9000 )
9001 .await?;
9002 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9003 lsp_store.update(&mut cx, |lsp_store, cx| {
9004 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9005 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9006 let key = LspKey {
9007 request_type: TypeId::of::<SemanticTokensFull>(),
9008 server_queried: server_id,
9009 };
9010 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9011 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9012 lsp_requests.clear();
9013 };
9014 }
9015
9016 lsp_data.lsp_requests.entry(key).or_default().insert(
9017 lsp_request_id,
9018 cx.spawn(async move |lsp_store, cx| {
9019 let tokens_fetch = lsp_store
9020 .update(cx, |lsp_store, cx| {
9021 lsp_store
9022 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9023 })
9024 .ok();
9025 if let Some(tokens_fetch) = tokens_fetch {
9026 let new_tokens = tokens_fetch.await;
9027 if let Some(new_tokens) = new_tokens {
9028 lsp_store
9029 .update(cx, |lsp_store, cx| {
9030 let response = new_tokens
9031 .into_iter()
9032 .map(|(server_id, response)| {
9033 (
9034 server_id.to_proto(),
9035 SemanticTokensFull::response_to_proto(
9036 response,
9037 lsp_store,
9038 sender_id,
9039 &buffer_version,
9040 cx,
9041 ),
9042 )
9043 })
9044 .collect::<HashMap<_, _>>();
9045 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9046 project_id,
9047 lsp_request_id,
9048 response,
9049 ) {
9050 Ok(()) => {}
9051 Err(e) => {
9052 log::error!(
9053 "Failed to send semantic tokens LSP response: {e:#}",
9054 )
9055 }
9056 }
9057 })
9058 .ok();
9059 }
9060 }
9061 }),
9062 );
9063 }
9064 });
9065 }
9066 }
9067 Ok(proto::Ack {})
9068 }
9069
9070 async fn handle_lsp_query_response(
9071 lsp_store: Entity<Self>,
9072 envelope: TypedEnvelope<proto::LspQueryResponse>,
9073 cx: AsyncApp,
9074 ) -> Result<()> {
9075 lsp_store.read_with(&cx, |lsp_store, _| {
9076 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9077 upstream_client.handle_lsp_response(envelope.clone());
9078 }
9079 });
9080 Ok(())
9081 }
9082
9083 async fn handle_apply_code_action(
9084 this: Entity<Self>,
9085 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9086 mut cx: AsyncApp,
9087 ) -> Result<proto::ApplyCodeActionResponse> {
9088 let sender_id = envelope.original_sender_id().unwrap_or_default();
9089 let action =
9090 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9091 let apply_code_action = this.update(&mut cx, |this, cx| {
9092 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9093 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9094 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9095 })?;
9096
9097 let project_transaction = apply_code_action.await?;
9098 let project_transaction = this.update(&mut cx, |this, cx| {
9099 this.buffer_store.update(cx, |buffer_store, cx| {
9100 buffer_store.serialize_project_transaction_for_peer(
9101 project_transaction,
9102 sender_id,
9103 cx,
9104 )
9105 })
9106 });
9107 Ok(proto::ApplyCodeActionResponse {
9108 transaction: Some(project_transaction),
9109 })
9110 }
9111
9112 async fn handle_register_buffer_with_language_servers(
9113 this: Entity<Self>,
9114 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9115 mut cx: AsyncApp,
9116 ) -> Result<proto::Ack> {
9117 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9118 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9119 this.update(&mut cx, |this, cx| {
9120 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9121 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9122 project_id: upstream_project_id,
9123 buffer_id: buffer_id.to_proto(),
9124 only_servers: envelope.payload.only_servers,
9125 });
9126 }
9127
9128 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9129 anyhow::bail!("buffer is not open");
9130 };
9131
9132 let handle = this.register_buffer_with_language_servers(
9133 &buffer,
9134 envelope
9135 .payload
9136 .only_servers
9137 .into_iter()
9138 .filter_map(|selector| {
9139 Some(match selector.selector? {
9140 proto::language_server_selector::Selector::ServerId(server_id) => {
9141 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9142 }
9143 proto::language_server_selector::Selector::Name(name) => {
9144 LanguageServerSelector::Name(LanguageServerName(
9145 SharedString::from(name),
9146 ))
9147 }
9148 })
9149 })
9150 .collect(),
9151 false,
9152 cx,
9153 );
9154 // Pull diagnostics for the buffer even if it was already registered.
9155 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9156 // but it's unclear if we need it.
9157 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9158 .detach();
9159 this.buffer_store().update(cx, |buffer_store, _| {
9160 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9161 });
9162
9163 Ok(())
9164 })?;
9165 Ok(proto::Ack {})
9166 }
9167
9168 async fn handle_rename_project_entry(
9169 this: Entity<Self>,
9170 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9171 mut cx: AsyncApp,
9172 ) -> Result<proto::ProjectEntryResponse> {
9173 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9174 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9175 let new_path =
9176 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9177
9178 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9179 .update(&mut cx, |this, cx| {
9180 let (worktree, entry) = this
9181 .worktree_store
9182 .read(cx)
9183 .worktree_and_entry_for_id(entry_id, cx)?;
9184 let new_worktree = this
9185 .worktree_store
9186 .read(cx)
9187 .worktree_for_id(new_worktree_id, cx)?;
9188 Some((
9189 this.worktree_store.clone(),
9190 worktree,
9191 new_worktree,
9192 entry.clone(),
9193 ))
9194 })
9195 .context("worktree not found")?;
9196 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9197 (worktree.absolutize(&old_entry.path), worktree.id())
9198 });
9199 let new_abs_path =
9200 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9201
9202 let _transaction = Self::will_rename_entry(
9203 this.downgrade(),
9204 old_worktree_id,
9205 &old_abs_path,
9206 &new_abs_path,
9207 old_entry.is_dir(),
9208 cx.clone(),
9209 )
9210 .await;
9211 let response = WorktreeStore::handle_rename_project_entry(
9212 worktree_store,
9213 envelope.payload,
9214 cx.clone(),
9215 )
9216 .await;
9217 this.read_with(&cx, |this, _| {
9218 this.did_rename_entry(
9219 old_worktree_id,
9220 &old_abs_path,
9221 &new_abs_path,
9222 old_entry.is_dir(),
9223 );
9224 });
9225 response
9226 }
9227
9228 async fn handle_update_diagnostic_summary(
9229 this: Entity<Self>,
9230 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9231 mut cx: AsyncApp,
9232 ) -> Result<()> {
9233 this.update(&mut cx, |lsp_store, cx| {
9234 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9235 let mut updated_diagnostics_paths = HashMap::default();
9236 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9237 for message_summary in envelope
9238 .payload
9239 .summary
9240 .into_iter()
9241 .chain(envelope.payload.more_summaries)
9242 {
9243 let project_path = ProjectPath {
9244 worktree_id,
9245 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9246 };
9247 let path = project_path.path.clone();
9248 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9249 let summary = DiagnosticSummary {
9250 error_count: message_summary.error_count as usize,
9251 warning_count: message_summary.warning_count as usize,
9252 };
9253
9254 if summary.is_empty() {
9255 if let Some(worktree_summaries) =
9256 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9257 && let Some(summaries) = worktree_summaries.get_mut(&path)
9258 {
9259 summaries.remove(&server_id);
9260 if summaries.is_empty() {
9261 worktree_summaries.remove(&path);
9262 }
9263 }
9264 } else {
9265 lsp_store
9266 .diagnostic_summaries
9267 .entry(worktree_id)
9268 .or_default()
9269 .entry(path)
9270 .or_default()
9271 .insert(server_id, summary);
9272 }
9273
9274 if let Some((_, project_id)) = &lsp_store.downstream_client {
9275 match &mut diagnostics_summary {
9276 Some(diagnostics_summary) => {
9277 diagnostics_summary
9278 .more_summaries
9279 .push(proto::DiagnosticSummary {
9280 path: project_path.path.as_ref().to_proto(),
9281 language_server_id: server_id.0 as u64,
9282 error_count: summary.error_count as u32,
9283 warning_count: summary.warning_count as u32,
9284 })
9285 }
9286 None => {
9287 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9288 project_id: *project_id,
9289 worktree_id: worktree_id.to_proto(),
9290 summary: Some(proto::DiagnosticSummary {
9291 path: project_path.path.as_ref().to_proto(),
9292 language_server_id: server_id.0 as u64,
9293 error_count: summary.error_count as u32,
9294 warning_count: summary.warning_count as u32,
9295 }),
9296 more_summaries: Vec::new(),
9297 })
9298 }
9299 }
9300 }
9301 updated_diagnostics_paths
9302 .entry(server_id)
9303 .or_insert_with(Vec::new)
9304 .push(project_path);
9305 }
9306
9307 if let Some((diagnostics_summary, (downstream_client, _))) =
9308 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9309 {
9310 downstream_client.send(diagnostics_summary).log_err();
9311 }
9312 for (server_id, paths) in updated_diagnostics_paths {
9313 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9314 }
9315 Ok(())
9316 })
9317 }
9318
9319 async fn handle_start_language_server(
9320 lsp_store: Entity<Self>,
9321 envelope: TypedEnvelope<proto::StartLanguageServer>,
9322 mut cx: AsyncApp,
9323 ) -> Result<()> {
9324 let server = envelope.payload.server.context("invalid server")?;
9325 let server_capabilities =
9326 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9327 .with_context(|| {
9328 format!(
9329 "incorrect server capabilities {}",
9330 envelope.payload.capabilities
9331 )
9332 })?;
9333 lsp_store.update(&mut cx, |lsp_store, cx| {
9334 let server_id = LanguageServerId(server.id as usize);
9335 let server_name = LanguageServerName::from_proto(server.name.clone());
9336 lsp_store
9337 .lsp_server_capabilities
9338 .insert(server_id, server_capabilities);
9339 lsp_store.language_server_statuses.insert(
9340 server_id,
9341 LanguageServerStatus {
9342 name: server_name.clone(),
9343 server_version: None,
9344 pending_work: Default::default(),
9345 has_pending_diagnostic_updates: false,
9346 progress_tokens: Default::default(),
9347 worktree: server.worktree_id.map(WorktreeId::from_proto),
9348 binary: None,
9349 configuration: None,
9350 workspace_folders: BTreeSet::new(),
9351 process_id: None,
9352 },
9353 );
9354 cx.emit(LspStoreEvent::LanguageServerAdded(
9355 server_id,
9356 server_name,
9357 server.worktree_id.map(WorktreeId::from_proto),
9358 ));
9359 cx.notify();
9360 });
9361 Ok(())
9362 }
9363
9364 async fn handle_update_language_server(
9365 lsp_store: Entity<Self>,
9366 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9367 mut cx: AsyncApp,
9368 ) -> Result<()> {
9369 lsp_store.update(&mut cx, |lsp_store, cx| {
9370 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9371
9372 match envelope.payload.variant.context("invalid variant")? {
9373 proto::update_language_server::Variant::WorkStart(payload) => {
9374 lsp_store.on_lsp_work_start(
9375 language_server_id,
9376 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9377 .context("invalid progress token value")?,
9378 LanguageServerProgress {
9379 title: payload.title,
9380 is_disk_based_diagnostics_progress: false,
9381 is_cancellable: payload.is_cancellable.unwrap_or(false),
9382 message: payload.message,
9383 percentage: payload.percentage.map(|p| p as usize),
9384 last_update_at: cx.background_executor().now(),
9385 },
9386 cx,
9387 );
9388 }
9389 proto::update_language_server::Variant::WorkProgress(payload) => {
9390 lsp_store.on_lsp_work_progress(
9391 language_server_id,
9392 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9393 .context("invalid progress token value")?,
9394 LanguageServerProgress {
9395 title: None,
9396 is_disk_based_diagnostics_progress: false,
9397 is_cancellable: payload.is_cancellable.unwrap_or(false),
9398 message: payload.message,
9399 percentage: payload.percentage.map(|p| p as usize),
9400 last_update_at: cx.background_executor().now(),
9401 },
9402 cx,
9403 );
9404 }
9405
9406 proto::update_language_server::Variant::WorkEnd(payload) => {
9407 lsp_store.on_lsp_work_end(
9408 language_server_id,
9409 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9410 .context("invalid progress token value")?,
9411 cx,
9412 );
9413 }
9414
9415 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9416 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9417 }
9418
9419 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9420 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9421 }
9422
9423 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9424 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9425 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9426 cx.emit(LspStoreEvent::LanguageServerUpdate {
9427 language_server_id,
9428 name: envelope
9429 .payload
9430 .server_name
9431 .map(SharedString::new)
9432 .map(LanguageServerName),
9433 message: non_lsp,
9434 });
9435 }
9436 }
9437
9438 Ok(())
9439 })
9440 }
9441
9442 async fn handle_language_server_log(
9443 this: Entity<Self>,
9444 envelope: TypedEnvelope<proto::LanguageServerLog>,
9445 mut cx: AsyncApp,
9446 ) -> Result<()> {
9447 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9448 let log_type = envelope
9449 .payload
9450 .log_type
9451 .map(LanguageServerLogType::from_proto)
9452 .context("invalid language server log type")?;
9453
9454 let message = envelope.payload.message;
9455
9456 this.update(&mut cx, |_, cx| {
9457 cx.emit(LspStoreEvent::LanguageServerLog(
9458 language_server_id,
9459 log_type,
9460 message,
9461 ));
9462 });
9463 Ok(())
9464 }
9465
9466 async fn handle_lsp_ext_cancel_flycheck(
9467 lsp_store: Entity<Self>,
9468 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9469 cx: AsyncApp,
9470 ) -> Result<proto::Ack> {
9471 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9472 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9473 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9474 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9475 } else {
9476 None
9477 }
9478 });
9479 if let Some(task) = task {
9480 task.context("handling lsp ext cancel flycheck")?;
9481 }
9482
9483 Ok(proto::Ack {})
9484 }
9485
9486 async fn handle_lsp_ext_run_flycheck(
9487 lsp_store: Entity<Self>,
9488 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9489 mut cx: AsyncApp,
9490 ) -> Result<proto::Ack> {
9491 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9492 lsp_store.update(&mut cx, |lsp_store, cx| {
9493 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9494 let text_document = if envelope.payload.current_file_only {
9495 let buffer_id = envelope
9496 .payload
9497 .buffer_id
9498 .map(|id| BufferId::new(id))
9499 .transpose()?;
9500 buffer_id
9501 .and_then(|buffer_id| {
9502 lsp_store
9503 .buffer_store()
9504 .read(cx)
9505 .get(buffer_id)
9506 .and_then(|buffer| {
9507 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9508 })
9509 .map(|path| make_text_document_identifier(&path))
9510 })
9511 .transpose()?
9512 } else {
9513 None
9514 };
9515 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9516 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9517 )?;
9518 }
9519 anyhow::Ok(())
9520 })?;
9521
9522 Ok(proto::Ack {})
9523 }
9524
9525 async fn handle_lsp_ext_clear_flycheck(
9526 lsp_store: Entity<Self>,
9527 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9528 cx: AsyncApp,
9529 ) -> Result<proto::Ack> {
9530 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9531 lsp_store.read_with(&cx, |lsp_store, _| {
9532 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9533 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9534 } else {
9535 None
9536 }
9537 });
9538
9539 Ok(proto::Ack {})
9540 }
9541
9542 pub fn disk_based_diagnostics_started(
9543 &mut self,
9544 language_server_id: LanguageServerId,
9545 cx: &mut Context<Self>,
9546 ) {
9547 if let Some(language_server_status) =
9548 self.language_server_statuses.get_mut(&language_server_id)
9549 {
9550 language_server_status.has_pending_diagnostic_updates = true;
9551 }
9552
9553 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9554 cx.emit(LspStoreEvent::LanguageServerUpdate {
9555 language_server_id,
9556 name: self
9557 .language_server_adapter_for_id(language_server_id)
9558 .map(|adapter| adapter.name()),
9559 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9560 Default::default(),
9561 ),
9562 })
9563 }
9564
9565 pub fn disk_based_diagnostics_finished(
9566 &mut self,
9567 language_server_id: LanguageServerId,
9568 cx: &mut Context<Self>,
9569 ) {
9570 if let Some(language_server_status) =
9571 self.language_server_statuses.get_mut(&language_server_id)
9572 {
9573 language_server_status.has_pending_diagnostic_updates = false;
9574 }
9575
9576 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9577 cx.emit(LspStoreEvent::LanguageServerUpdate {
9578 language_server_id,
9579 name: self
9580 .language_server_adapter_for_id(language_server_id)
9581 .map(|adapter| adapter.name()),
9582 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9583 Default::default(),
9584 ),
9585 })
9586 }
9587
9588 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9589 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9590 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9591 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9592 // the language server might take some time to publish diagnostics.
9593 fn simulate_disk_based_diagnostics_events_if_needed(
9594 &mut self,
9595 language_server_id: LanguageServerId,
9596 cx: &mut Context<Self>,
9597 ) {
9598 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9599
9600 let Some(LanguageServerState::Running {
9601 simulate_disk_based_diagnostics_completion,
9602 adapter,
9603 ..
9604 }) = self
9605 .as_local_mut()
9606 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9607 else {
9608 return;
9609 };
9610
9611 if adapter.disk_based_diagnostics_progress_token.is_some() {
9612 return;
9613 }
9614
9615 let prev_task =
9616 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9617 cx.background_executor()
9618 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9619 .await;
9620
9621 this.update(cx, |this, cx| {
9622 this.disk_based_diagnostics_finished(language_server_id, cx);
9623
9624 if let Some(LanguageServerState::Running {
9625 simulate_disk_based_diagnostics_completion,
9626 ..
9627 }) = this.as_local_mut().and_then(|local_store| {
9628 local_store.language_servers.get_mut(&language_server_id)
9629 }) {
9630 *simulate_disk_based_diagnostics_completion = None;
9631 }
9632 })
9633 .ok();
9634 }));
9635
9636 if prev_task.is_none() {
9637 self.disk_based_diagnostics_started(language_server_id, cx);
9638 }
9639 }
9640
9641 pub fn language_server_statuses(
9642 &self,
9643 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9644 self.language_server_statuses
9645 .iter()
9646 .map(|(key, value)| (*key, value))
9647 }
9648
9649 pub(super) fn did_rename_entry(
9650 &self,
9651 worktree_id: WorktreeId,
9652 old_path: &Path,
9653 new_path: &Path,
9654 is_dir: bool,
9655 ) {
9656 maybe!({
9657 let local_store = self.as_local()?;
9658
9659 let old_uri = lsp::Uri::from_file_path(old_path)
9660 .ok()
9661 .map(|uri| uri.to_string())?;
9662 let new_uri = lsp::Uri::from_file_path(new_path)
9663 .ok()
9664 .map(|uri| uri.to_string())?;
9665
9666 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9667 let Some(filter) = local_store
9668 .language_server_paths_watched_for_rename
9669 .get(&language_server.server_id())
9670 else {
9671 continue;
9672 };
9673
9674 if filter.should_send_did_rename(&old_uri, is_dir) {
9675 language_server
9676 .notify::<DidRenameFiles>(RenameFilesParams {
9677 files: vec![FileRename {
9678 old_uri: old_uri.clone(),
9679 new_uri: new_uri.clone(),
9680 }],
9681 })
9682 .ok();
9683 }
9684 }
9685 Some(())
9686 });
9687 }
9688
9689 pub(super) fn will_rename_entry(
9690 this: WeakEntity<Self>,
9691 worktree_id: WorktreeId,
9692 old_path: &Path,
9693 new_path: &Path,
9694 is_dir: bool,
9695 cx: AsyncApp,
9696 ) -> Task<ProjectTransaction> {
9697 let old_uri = lsp::Uri::from_file_path(old_path)
9698 .ok()
9699 .map(|uri| uri.to_string());
9700 let new_uri = lsp::Uri::from_file_path(new_path)
9701 .ok()
9702 .map(|uri| uri.to_string());
9703 cx.spawn(async move |cx| {
9704 let mut tasks = vec![];
9705 this.update(cx, |this, cx| {
9706 let local_store = this.as_local()?;
9707 let old_uri = old_uri?;
9708 let new_uri = new_uri?;
9709 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9710 let Some(filter) = local_store
9711 .language_server_paths_watched_for_rename
9712 .get(&language_server.server_id())
9713 else {
9714 continue;
9715 };
9716
9717 if !filter.should_send_will_rename(&old_uri, is_dir) {
9718 continue;
9719 }
9720 let request_timeout = ProjectSettings::get_global(cx)
9721 .global_lsp_settings
9722 .get_request_timeout();
9723
9724 let apply_edit = cx.spawn({
9725 let old_uri = old_uri.clone();
9726 let new_uri = new_uri.clone();
9727 let language_server = language_server.clone();
9728 async move |this, cx| {
9729 let edit = language_server
9730 .request::<WillRenameFiles>(
9731 RenameFilesParams {
9732 files: vec![FileRename { old_uri, new_uri }],
9733 },
9734 request_timeout,
9735 )
9736 .await
9737 .into_response()
9738 .context("will rename files")
9739 .log_err()
9740 .flatten()?;
9741
9742 LocalLspStore::deserialize_workspace_edit(
9743 this.upgrade()?,
9744 edit,
9745 false,
9746 language_server.clone(),
9747 cx,
9748 )
9749 .await
9750 .ok()
9751 }
9752 });
9753 tasks.push(apply_edit);
9754 }
9755 Some(())
9756 })
9757 .ok()
9758 .flatten();
9759 let mut merged_transaction = ProjectTransaction::default();
9760 for task in tasks {
9761 // Await on tasks sequentially so that the order of application of edits is deterministic
9762 // (at least with regards to the order of registration of language servers)
9763 if let Some(transaction) = task.await {
9764 for (buffer, buffer_transaction) in transaction.0 {
9765 merged_transaction.0.insert(buffer, buffer_transaction);
9766 }
9767 }
9768 }
9769 merged_transaction
9770 })
9771 }
9772
9773 fn lsp_notify_abs_paths_changed(
9774 &mut self,
9775 server_id: LanguageServerId,
9776 changes: Vec<PathEvent>,
9777 ) {
9778 maybe!({
9779 let server = self.language_server_for_id(server_id)?;
9780 let changes = changes
9781 .into_iter()
9782 .filter_map(|event| {
9783 let typ = match event.kind? {
9784 PathEventKind::Created => lsp::FileChangeType::CREATED,
9785 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9786 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9787 };
9788 Some(lsp::FileEvent {
9789 uri: file_path_to_lsp_url(&event.path).log_err()?,
9790 typ,
9791 })
9792 })
9793 .collect::<Vec<_>>();
9794 if !changes.is_empty() {
9795 server
9796 .notify::<lsp::notification::DidChangeWatchedFiles>(
9797 lsp::DidChangeWatchedFilesParams { changes },
9798 )
9799 .ok();
9800 }
9801 Some(())
9802 });
9803 }
9804
9805 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9806 self.as_local()?.language_server_for_id(id)
9807 }
9808
9809 fn on_lsp_progress(
9810 &mut self,
9811 progress_params: lsp::ProgressParams,
9812 language_server_id: LanguageServerId,
9813 disk_based_diagnostics_progress_token: Option<String>,
9814 cx: &mut Context<Self>,
9815 ) {
9816 match progress_params.value {
9817 lsp::ProgressParamsValue::WorkDone(progress) => {
9818 self.handle_work_done_progress(
9819 progress,
9820 language_server_id,
9821 disk_based_diagnostics_progress_token,
9822 ProgressToken::from_lsp(progress_params.token),
9823 cx,
9824 );
9825 }
9826 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9827 let registration_id = match progress_params.token {
9828 lsp::NumberOrString::Number(_) => None,
9829 lsp::NumberOrString::String(token) => token
9830 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9831 .map(|(_, id)| id.to_owned()),
9832 };
9833 if let Some(LanguageServerState::Running {
9834 workspace_diagnostics_refresh_tasks,
9835 ..
9836 }) = self
9837 .as_local_mut()
9838 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9839 && let Some(workspace_diagnostics) =
9840 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9841 {
9842 workspace_diagnostics.progress_tx.try_send(()).ok();
9843 self.apply_workspace_diagnostic_report(
9844 language_server_id,
9845 report,
9846 registration_id.map(SharedString::from),
9847 cx,
9848 )
9849 }
9850 }
9851 }
9852 }
9853
9854 fn handle_work_done_progress(
9855 &mut self,
9856 progress: lsp::WorkDoneProgress,
9857 language_server_id: LanguageServerId,
9858 disk_based_diagnostics_progress_token: Option<String>,
9859 token: ProgressToken,
9860 cx: &mut Context<Self>,
9861 ) {
9862 let language_server_status =
9863 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9864 status
9865 } else {
9866 return;
9867 };
9868
9869 if !language_server_status.progress_tokens.contains(&token) {
9870 return;
9871 }
9872
9873 let is_disk_based_diagnostics_progress =
9874 if let (Some(disk_based_token), ProgressToken::String(token)) =
9875 (&disk_based_diagnostics_progress_token, &token)
9876 {
9877 token.starts_with(disk_based_token)
9878 } else {
9879 false
9880 };
9881
9882 match progress {
9883 lsp::WorkDoneProgress::Begin(report) => {
9884 if is_disk_based_diagnostics_progress {
9885 self.disk_based_diagnostics_started(language_server_id, cx);
9886 }
9887 self.on_lsp_work_start(
9888 language_server_id,
9889 token.clone(),
9890 LanguageServerProgress {
9891 title: Some(report.title),
9892 is_disk_based_diagnostics_progress,
9893 is_cancellable: report.cancellable.unwrap_or(false),
9894 message: report.message.clone(),
9895 percentage: report.percentage.map(|p| p as usize),
9896 last_update_at: cx.background_executor().now(),
9897 },
9898 cx,
9899 );
9900 }
9901 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9902 language_server_id,
9903 token,
9904 LanguageServerProgress {
9905 title: None,
9906 is_disk_based_diagnostics_progress,
9907 is_cancellable: report.cancellable.unwrap_or(false),
9908 message: report.message,
9909 percentage: report.percentage.map(|p| p as usize),
9910 last_update_at: cx.background_executor().now(),
9911 },
9912 cx,
9913 ),
9914 lsp::WorkDoneProgress::End(_) => {
9915 language_server_status.progress_tokens.remove(&token);
9916 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9917 if is_disk_based_diagnostics_progress {
9918 self.disk_based_diagnostics_finished(language_server_id, cx);
9919 }
9920 }
9921 }
9922 }
9923
9924 fn on_lsp_work_start(
9925 &mut self,
9926 language_server_id: LanguageServerId,
9927 token: ProgressToken,
9928 progress: LanguageServerProgress,
9929 cx: &mut Context<Self>,
9930 ) {
9931 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9932 status.pending_work.insert(token.clone(), progress.clone());
9933 cx.notify();
9934 }
9935 cx.emit(LspStoreEvent::LanguageServerUpdate {
9936 language_server_id,
9937 name: self
9938 .language_server_adapter_for_id(language_server_id)
9939 .map(|adapter| adapter.name()),
9940 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9941 token: Some(token.to_proto()),
9942 title: progress.title,
9943 message: progress.message,
9944 percentage: progress.percentage.map(|p| p as u32),
9945 is_cancellable: Some(progress.is_cancellable),
9946 }),
9947 })
9948 }
9949
9950 fn on_lsp_work_progress(
9951 &mut self,
9952 language_server_id: LanguageServerId,
9953 token: ProgressToken,
9954 progress: LanguageServerProgress,
9955 cx: &mut Context<Self>,
9956 ) {
9957 let mut did_update = false;
9958 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9959 match status.pending_work.entry(token.clone()) {
9960 btree_map::Entry::Vacant(entry) => {
9961 entry.insert(progress.clone());
9962 did_update = true;
9963 }
9964 btree_map::Entry::Occupied(mut entry) => {
9965 let entry = entry.get_mut();
9966 if (progress.last_update_at - entry.last_update_at)
9967 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9968 {
9969 entry.last_update_at = progress.last_update_at;
9970 if progress.message.is_some() {
9971 entry.message = progress.message.clone();
9972 }
9973 if progress.percentage.is_some() {
9974 entry.percentage = progress.percentage;
9975 }
9976 if progress.is_cancellable != entry.is_cancellable {
9977 entry.is_cancellable = progress.is_cancellable;
9978 }
9979 did_update = true;
9980 }
9981 }
9982 }
9983 }
9984
9985 if did_update {
9986 cx.emit(LspStoreEvent::LanguageServerUpdate {
9987 language_server_id,
9988 name: self
9989 .language_server_adapter_for_id(language_server_id)
9990 .map(|adapter| adapter.name()),
9991 message: proto::update_language_server::Variant::WorkProgress(
9992 proto::LspWorkProgress {
9993 token: Some(token.to_proto()),
9994 message: progress.message,
9995 percentage: progress.percentage.map(|p| p as u32),
9996 is_cancellable: Some(progress.is_cancellable),
9997 },
9998 ),
9999 })
10000 }
10001 }
10002
10003 fn on_lsp_work_end(
10004 &mut self,
10005 language_server_id: LanguageServerId,
10006 token: ProgressToken,
10007 cx: &mut Context<Self>,
10008 ) {
10009 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10010 if let Some(work) = status.pending_work.remove(&token)
10011 && !work.is_disk_based_diagnostics_progress
10012 {
10013 cx.emit(LspStoreEvent::RefreshInlayHints {
10014 server_id: language_server_id,
10015 request_id: None,
10016 });
10017 }
10018 cx.notify();
10019 }
10020
10021 cx.emit(LspStoreEvent::LanguageServerUpdate {
10022 language_server_id,
10023 name: self
10024 .language_server_adapter_for_id(language_server_id)
10025 .map(|adapter| adapter.name()),
10026 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10027 token: Some(token.to_proto()),
10028 }),
10029 })
10030 }
10031
10032 pub async fn handle_resolve_completion_documentation(
10033 this: Entity<Self>,
10034 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10035 mut cx: AsyncApp,
10036 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10037 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10038
10039 let completion = this
10040 .read_with(&cx, |this, cx| {
10041 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10042 let server = this
10043 .language_server_for_id(id)
10044 .with_context(|| format!("No language server {id}"))?;
10045
10046 let request_timeout = ProjectSettings::get_global(cx)
10047 .global_lsp_settings
10048 .get_request_timeout();
10049
10050 anyhow::Ok(cx.background_spawn(async move {
10051 let can_resolve = server
10052 .capabilities()
10053 .completion_provider
10054 .as_ref()
10055 .and_then(|options| options.resolve_provider)
10056 .unwrap_or(false);
10057 if can_resolve {
10058 server
10059 .request::<lsp::request::ResolveCompletionItem>(
10060 lsp_completion,
10061 request_timeout,
10062 )
10063 .await
10064 .into_response()
10065 .context("resolve completion item")
10066 } else {
10067 anyhow::Ok(lsp_completion)
10068 }
10069 }))
10070 })?
10071 .await?;
10072
10073 let mut documentation_is_markdown = false;
10074 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10075 let documentation = match completion.documentation {
10076 Some(lsp::Documentation::String(text)) => text,
10077
10078 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10079 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10080 value
10081 }
10082
10083 _ => String::new(),
10084 };
10085
10086 // If we have a new buffer_id, that means we're talking to a new client
10087 // and want to check for new text_edits in the completion too.
10088 let mut old_replace_start = None;
10089 let mut old_replace_end = None;
10090 let mut old_insert_start = None;
10091 let mut old_insert_end = None;
10092 let mut new_text = String::default();
10093 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10094 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10095 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10096 anyhow::Ok(buffer.read(cx).snapshot())
10097 })?;
10098
10099 if let Some(text_edit) = completion.text_edit.as_ref() {
10100 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10101
10102 if let Some(mut edit) = edit {
10103 LineEnding::normalize(&mut edit.new_text);
10104
10105 new_text = edit.new_text;
10106 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10107 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10108 if let Some(insert_range) = edit.insert_range {
10109 old_insert_start = Some(serialize_anchor(&insert_range.start));
10110 old_insert_end = Some(serialize_anchor(&insert_range.end));
10111 }
10112 }
10113 }
10114 }
10115
10116 Ok(proto::ResolveCompletionDocumentationResponse {
10117 documentation,
10118 documentation_is_markdown,
10119 old_replace_start,
10120 old_replace_end,
10121 new_text,
10122 lsp_completion,
10123 old_insert_start,
10124 old_insert_end,
10125 })
10126 }
10127
10128 async fn handle_on_type_formatting(
10129 this: Entity<Self>,
10130 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10131 mut cx: AsyncApp,
10132 ) -> Result<proto::OnTypeFormattingResponse> {
10133 let on_type_formatting = this.update(&mut cx, |this, cx| {
10134 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10135 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10136 let position = envelope
10137 .payload
10138 .position
10139 .and_then(deserialize_anchor)
10140 .context("invalid position")?;
10141 anyhow::Ok(this.apply_on_type_formatting(
10142 buffer,
10143 position,
10144 envelope.payload.trigger.clone(),
10145 cx,
10146 ))
10147 })?;
10148
10149 let transaction = on_type_formatting
10150 .await?
10151 .as_ref()
10152 .map(language::proto::serialize_transaction);
10153 Ok(proto::OnTypeFormattingResponse { transaction })
10154 }
10155
10156 async fn handle_pull_workspace_diagnostics(
10157 lsp_store: Entity<Self>,
10158 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10159 mut cx: AsyncApp,
10160 ) -> Result<proto::Ack> {
10161 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10162 lsp_store.update(&mut cx, |lsp_store, _| {
10163 lsp_store.pull_workspace_diagnostics(server_id);
10164 });
10165 Ok(proto::Ack {})
10166 }
10167
10168 async fn handle_open_buffer_for_symbol(
10169 this: Entity<Self>,
10170 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10171 mut cx: AsyncApp,
10172 ) -> Result<proto::OpenBufferForSymbolResponse> {
10173 let peer_id = envelope.original_sender_id().unwrap_or_default();
10174 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10175 let symbol = Self::deserialize_symbol(symbol)?;
10176 this.read_with(&cx, |this, _| {
10177 if let SymbolLocation::OutsideProject {
10178 abs_path,
10179 signature,
10180 } = &symbol.path
10181 {
10182 let new_signature = this.symbol_signature(&abs_path);
10183 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10184 }
10185 Ok(())
10186 })?;
10187 let buffer = this
10188 .update(&mut cx, |this, cx| {
10189 this.open_buffer_for_symbol(
10190 &Symbol {
10191 language_server_name: symbol.language_server_name,
10192 source_worktree_id: symbol.source_worktree_id,
10193 source_language_server_id: symbol.source_language_server_id,
10194 path: symbol.path,
10195 name: symbol.name,
10196 kind: symbol.kind,
10197 range: symbol.range,
10198 label: CodeLabel::default(),
10199 container_name: symbol.container_name,
10200 },
10201 cx,
10202 )
10203 })
10204 .await?;
10205
10206 this.update(&mut cx, |this, cx| {
10207 let is_private = buffer
10208 .read(cx)
10209 .file()
10210 .map(|f| f.is_private())
10211 .unwrap_or_default();
10212 if is_private {
10213 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10214 } else {
10215 this.buffer_store
10216 .update(cx, |buffer_store, cx| {
10217 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10218 })
10219 .detach_and_log_err(cx);
10220 let buffer_id = buffer.read(cx).remote_id().to_proto();
10221 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10222 }
10223 })
10224 }
10225
10226 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10227 let mut hasher = Sha256::new();
10228 hasher.update(abs_path.to_string_lossy().as_bytes());
10229 hasher.update(self.nonce.to_be_bytes());
10230 hasher.finalize().as_slice().try_into().unwrap()
10231 }
10232
10233 pub async fn handle_get_project_symbols(
10234 this: Entity<Self>,
10235 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10236 mut cx: AsyncApp,
10237 ) -> Result<proto::GetProjectSymbolsResponse> {
10238 let symbols = this
10239 .update(&mut cx, |this, cx| {
10240 this.symbols(&envelope.payload.query, cx)
10241 })
10242 .await?;
10243
10244 Ok(proto::GetProjectSymbolsResponse {
10245 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10246 })
10247 }
10248
10249 pub async fn handle_restart_language_servers(
10250 this: Entity<Self>,
10251 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10252 mut cx: AsyncApp,
10253 ) -> Result<proto::Ack> {
10254 this.update(&mut cx, |lsp_store, cx| {
10255 let buffers =
10256 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10257 lsp_store.restart_language_servers_for_buffers(
10258 buffers,
10259 envelope
10260 .payload
10261 .only_servers
10262 .into_iter()
10263 .filter_map(|selector| {
10264 Some(match selector.selector? {
10265 proto::language_server_selector::Selector::ServerId(server_id) => {
10266 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10267 }
10268 proto::language_server_selector::Selector::Name(name) => {
10269 LanguageServerSelector::Name(LanguageServerName(
10270 SharedString::from(name),
10271 ))
10272 }
10273 })
10274 })
10275 .collect(),
10276 cx,
10277 );
10278 });
10279
10280 Ok(proto::Ack {})
10281 }
10282
10283 pub async fn handle_stop_language_servers(
10284 lsp_store: Entity<Self>,
10285 envelope: TypedEnvelope<proto::StopLanguageServers>,
10286 mut cx: AsyncApp,
10287 ) -> Result<proto::Ack> {
10288 lsp_store.update(&mut cx, |lsp_store, cx| {
10289 if envelope.payload.all
10290 && envelope.payload.also_servers.is_empty()
10291 && envelope.payload.buffer_ids.is_empty()
10292 {
10293 lsp_store.stop_all_language_servers(cx);
10294 } else {
10295 let buffers =
10296 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10297 lsp_store
10298 .stop_language_servers_for_buffers(
10299 buffers,
10300 envelope
10301 .payload
10302 .also_servers
10303 .into_iter()
10304 .filter_map(|selector| {
10305 Some(match selector.selector? {
10306 proto::language_server_selector::Selector::ServerId(
10307 server_id,
10308 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10309 server_id,
10310 )),
10311 proto::language_server_selector::Selector::Name(name) => {
10312 LanguageServerSelector::Name(LanguageServerName(
10313 SharedString::from(name),
10314 ))
10315 }
10316 })
10317 })
10318 .collect(),
10319 cx,
10320 )
10321 .detach_and_log_err(cx);
10322 }
10323 });
10324
10325 Ok(proto::Ack {})
10326 }
10327
10328 pub async fn handle_cancel_language_server_work(
10329 lsp_store: Entity<Self>,
10330 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10331 mut cx: AsyncApp,
10332 ) -> Result<proto::Ack> {
10333 lsp_store.update(&mut cx, |lsp_store, cx| {
10334 if let Some(work) = envelope.payload.work {
10335 match work {
10336 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10337 let buffers =
10338 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10339 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10340 }
10341 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10342 let server_id = LanguageServerId::from_proto(work.language_server_id);
10343 let token = work
10344 .token
10345 .map(|token| {
10346 ProgressToken::from_proto(token)
10347 .context("invalid work progress token")
10348 })
10349 .transpose()?;
10350 lsp_store.cancel_language_server_work(server_id, token, cx);
10351 }
10352 }
10353 }
10354 anyhow::Ok(())
10355 })?;
10356
10357 Ok(proto::Ack {})
10358 }
10359
10360 fn buffer_ids_to_buffers(
10361 &mut self,
10362 buffer_ids: impl Iterator<Item = u64>,
10363 cx: &mut Context<Self>,
10364 ) -> Vec<Entity<Buffer>> {
10365 buffer_ids
10366 .into_iter()
10367 .flat_map(|buffer_id| {
10368 self.buffer_store
10369 .read(cx)
10370 .get(BufferId::new(buffer_id).log_err()?)
10371 })
10372 .collect::<Vec<_>>()
10373 }
10374
10375 async fn handle_apply_additional_edits_for_completion(
10376 this: Entity<Self>,
10377 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10378 mut cx: AsyncApp,
10379 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10380 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10381 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10382 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10383 let completion = Self::deserialize_completion(
10384 envelope.payload.completion.context("invalid completion")?,
10385 )?;
10386 anyhow::Ok((buffer, completion))
10387 })?;
10388
10389 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10390 this.apply_additional_edits_for_completion(
10391 buffer,
10392 Rc::new(RefCell::new(Box::new([Completion {
10393 replace_range: completion.replace_range,
10394 new_text: completion.new_text,
10395 source: completion.source,
10396 documentation: None,
10397 label: CodeLabel::default(),
10398 match_start: None,
10399 snippet_deduplication_key: None,
10400 insert_text_mode: None,
10401 icon_path: None,
10402 confirm: None,
10403 }]))),
10404 0,
10405 false,
10406 cx,
10407 )
10408 });
10409
10410 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10411 transaction: apply_additional_edits
10412 .await?
10413 .as_ref()
10414 .map(language::proto::serialize_transaction),
10415 })
10416 }
10417
10418 pub fn last_formatting_failure(&self) -> Option<&str> {
10419 self.last_formatting_failure.as_deref()
10420 }
10421
10422 pub fn reset_last_formatting_failure(&mut self) {
10423 self.last_formatting_failure = None;
10424 }
10425
10426 pub fn environment_for_buffer(
10427 &self,
10428 buffer: &Entity<Buffer>,
10429 cx: &mut Context<Self>,
10430 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10431 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10432 environment.update(cx, |env, cx| {
10433 env.buffer_environment(buffer, &self.worktree_store, cx)
10434 })
10435 } else {
10436 Task::ready(None).shared()
10437 }
10438 }
10439
10440 pub fn format(
10441 &mut self,
10442 buffers: HashSet<Entity<Buffer>>,
10443 target: LspFormatTarget,
10444 push_to_history: bool,
10445 trigger: FormatTrigger,
10446 cx: &mut Context<Self>,
10447 ) -> Task<anyhow::Result<ProjectTransaction>> {
10448 let logger = zlog::scoped!("format");
10449 if self.as_local().is_some() {
10450 zlog::trace!(logger => "Formatting locally");
10451 let logger = zlog::scoped!(logger => "local");
10452 let buffers = buffers
10453 .into_iter()
10454 .map(|buffer_handle| {
10455 let buffer = buffer_handle.read(cx);
10456 let buffer_abs_path = File::from_dyn(buffer.file())
10457 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10458
10459 (buffer_handle, buffer_abs_path, buffer.remote_id())
10460 })
10461 .collect::<Vec<_>>();
10462
10463 cx.spawn(async move |lsp_store, cx| {
10464 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10465
10466 for (handle, abs_path, id) in buffers {
10467 let env = lsp_store
10468 .update(cx, |lsp_store, cx| {
10469 lsp_store.environment_for_buffer(&handle, cx)
10470 })?
10471 .await;
10472
10473 let ranges = match &target {
10474 LspFormatTarget::Buffers => None,
10475 LspFormatTarget::Ranges(ranges) => {
10476 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10477 }
10478 };
10479
10480 formattable_buffers.push(FormattableBuffer {
10481 handle,
10482 abs_path,
10483 env,
10484 ranges,
10485 });
10486 }
10487 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10488
10489 let format_timer = zlog::time!(logger => "Formatting buffers");
10490 let result = LocalLspStore::format_locally(
10491 lsp_store.clone(),
10492 formattable_buffers,
10493 push_to_history,
10494 trigger,
10495 logger,
10496 cx,
10497 )
10498 .await;
10499 format_timer.end();
10500
10501 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10502
10503 lsp_store.update(cx, |lsp_store, _| {
10504 lsp_store.update_last_formatting_failure(&result);
10505 })?;
10506
10507 result
10508 })
10509 } else if let Some((client, project_id)) = self.upstream_client() {
10510 zlog::trace!(logger => "Formatting remotely");
10511 let logger = zlog::scoped!(logger => "remote");
10512
10513 let buffer_ranges = match &target {
10514 LspFormatTarget::Buffers => Vec::new(),
10515 LspFormatTarget::Ranges(ranges) => ranges
10516 .iter()
10517 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10518 buffer_id: buffer_id.to_proto(),
10519 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10520 })
10521 .collect(),
10522 };
10523
10524 let buffer_store = self.buffer_store();
10525 cx.spawn(async move |lsp_store, cx| {
10526 zlog::trace!(logger => "Sending remote format request");
10527 let request_timer = zlog::time!(logger => "remote format request");
10528 let result = client
10529 .request(proto::FormatBuffers {
10530 project_id,
10531 trigger: trigger as i32,
10532 buffer_ids: buffers
10533 .iter()
10534 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10535 .collect(),
10536 buffer_ranges,
10537 })
10538 .await
10539 .and_then(|result| result.transaction.context("missing transaction"));
10540 request_timer.end();
10541
10542 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10543
10544 lsp_store.update(cx, |lsp_store, _| {
10545 lsp_store.update_last_formatting_failure(&result);
10546 })?;
10547
10548 let transaction_response = result?;
10549 let _timer = zlog::time!(logger => "deserializing project transaction");
10550 buffer_store
10551 .update(cx, |buffer_store, cx| {
10552 buffer_store.deserialize_project_transaction(
10553 transaction_response,
10554 push_to_history,
10555 cx,
10556 )
10557 })
10558 .await
10559 })
10560 } else {
10561 zlog::trace!(logger => "Not formatting");
10562 Task::ready(Ok(ProjectTransaction::default()))
10563 }
10564 }
10565
10566 async fn handle_format_buffers(
10567 this: Entity<Self>,
10568 envelope: TypedEnvelope<proto::FormatBuffers>,
10569 mut cx: AsyncApp,
10570 ) -> Result<proto::FormatBuffersResponse> {
10571 let sender_id = envelope.original_sender_id().unwrap_or_default();
10572 let format = this.update(&mut cx, |this, cx| {
10573 let mut buffers = HashSet::default();
10574 for buffer_id in &envelope.payload.buffer_ids {
10575 let buffer_id = BufferId::new(*buffer_id)?;
10576 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10577 }
10578
10579 let target = if envelope.payload.buffer_ranges.is_empty() {
10580 LspFormatTarget::Buffers
10581 } else {
10582 let mut ranges_map = BTreeMap::new();
10583 for buffer_range in &envelope.payload.buffer_ranges {
10584 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10585 let ranges: Result<Vec<_>> = buffer_range
10586 .ranges
10587 .iter()
10588 .map(|range| {
10589 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10590 })
10591 .collect();
10592 ranges_map.insert(buffer_id, ranges?);
10593 }
10594 LspFormatTarget::Ranges(ranges_map)
10595 };
10596
10597 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10598 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10599 })?;
10600
10601 let project_transaction = format.await?;
10602 let project_transaction = this.update(&mut cx, |this, cx| {
10603 this.buffer_store.update(cx, |buffer_store, cx| {
10604 buffer_store.serialize_project_transaction_for_peer(
10605 project_transaction,
10606 sender_id,
10607 cx,
10608 )
10609 })
10610 });
10611 Ok(proto::FormatBuffersResponse {
10612 transaction: Some(project_transaction),
10613 })
10614 }
10615
10616 async fn handle_apply_code_action_kind(
10617 this: Entity<Self>,
10618 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10619 mut cx: AsyncApp,
10620 ) -> Result<proto::ApplyCodeActionKindResponse> {
10621 let sender_id = envelope.original_sender_id().unwrap_or_default();
10622 let format = this.update(&mut cx, |this, cx| {
10623 let mut buffers = HashSet::default();
10624 for buffer_id in &envelope.payload.buffer_ids {
10625 let buffer_id = BufferId::new(*buffer_id)?;
10626 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10627 }
10628 let kind = match envelope.payload.kind.as_str() {
10629 "" => CodeActionKind::EMPTY,
10630 "quickfix" => CodeActionKind::QUICKFIX,
10631 "refactor" => CodeActionKind::REFACTOR,
10632 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10633 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10634 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10635 "source" => CodeActionKind::SOURCE,
10636 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10637 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10638 _ => anyhow::bail!(
10639 "Invalid code action kind {}",
10640 envelope.payload.kind.as_str()
10641 ),
10642 };
10643 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10644 })?;
10645
10646 let project_transaction = format.await?;
10647 let project_transaction = this.update(&mut cx, |this, cx| {
10648 this.buffer_store.update(cx, |buffer_store, cx| {
10649 buffer_store.serialize_project_transaction_for_peer(
10650 project_transaction,
10651 sender_id,
10652 cx,
10653 )
10654 })
10655 });
10656 Ok(proto::ApplyCodeActionKindResponse {
10657 transaction: Some(project_transaction),
10658 })
10659 }
10660
10661 async fn shutdown_language_server(
10662 server_state: Option<LanguageServerState>,
10663 name: LanguageServerName,
10664 cx: &mut AsyncApp,
10665 ) {
10666 let server = match server_state {
10667 Some(LanguageServerState::Starting { startup, .. }) => {
10668 let mut timer = cx
10669 .background_executor()
10670 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10671 .fuse();
10672
10673 select! {
10674 server = startup.fuse() => server,
10675 () = timer => {
10676 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10677 None
10678 },
10679 }
10680 }
10681
10682 Some(LanguageServerState::Running { server, .. }) => Some(server),
10683
10684 None => None,
10685 };
10686
10687 let Some(server) = server else { return };
10688 if let Some(shutdown) = server.shutdown() {
10689 shutdown.await;
10690 }
10691 }
10692
10693 // Returns a list of all of the worktrees which no longer have a language server and the root path
10694 // for the stopped server
10695 fn stop_local_language_server(
10696 &mut self,
10697 server_id: LanguageServerId,
10698 cx: &mut Context<Self>,
10699 ) -> Task<()> {
10700 let local = match &mut self.mode {
10701 LspStoreMode::Local(local) => local,
10702 _ => {
10703 return Task::ready(());
10704 }
10705 };
10706
10707 // Remove this server ID from all entries in the given worktree.
10708 local
10709 .language_server_ids
10710 .retain(|_, state| state.id != server_id);
10711 self.buffer_store.update(cx, |buffer_store, cx| {
10712 for buffer in buffer_store.buffers() {
10713 buffer.update(cx, |buffer, cx| {
10714 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10715 buffer.set_completion_triggers(server_id, Default::default(), cx);
10716 });
10717 }
10718 });
10719
10720 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10721 summaries.retain(|path, summaries_by_server_id| {
10722 if summaries_by_server_id.remove(&server_id).is_some() {
10723 if let Some((client, project_id)) = self.downstream_client.clone() {
10724 client
10725 .send(proto::UpdateDiagnosticSummary {
10726 project_id,
10727 worktree_id: worktree_id.to_proto(),
10728 summary: Some(proto::DiagnosticSummary {
10729 path: path.as_ref().to_proto(),
10730 language_server_id: server_id.0 as u64,
10731 error_count: 0,
10732 warning_count: 0,
10733 }),
10734 more_summaries: Vec::new(),
10735 })
10736 .log_err();
10737 }
10738 !summaries_by_server_id.is_empty()
10739 } else {
10740 true
10741 }
10742 });
10743 }
10744
10745 let local = self.as_local_mut().unwrap();
10746 for diagnostics in local.diagnostics.values_mut() {
10747 diagnostics.retain(|_, diagnostics_by_server_id| {
10748 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10749 diagnostics_by_server_id.remove(ix);
10750 !diagnostics_by_server_id.is_empty()
10751 } else {
10752 true
10753 }
10754 });
10755 }
10756 local.language_server_watched_paths.remove(&server_id);
10757
10758 let server_state = local.language_servers.remove(&server_id);
10759 self.cleanup_lsp_data(server_id);
10760 let name = self
10761 .language_server_statuses
10762 .remove(&server_id)
10763 .map(|status| status.name)
10764 .or_else(|| {
10765 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10766 Some(adapter.name())
10767 } else {
10768 None
10769 }
10770 });
10771
10772 if let Some(name) = name {
10773 log::info!("stopping language server {name}");
10774 self.languages
10775 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10776 cx.notify();
10777
10778 return cx.spawn(async move |lsp_store, cx| {
10779 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10780 lsp_store
10781 .update(cx, |lsp_store, cx| {
10782 lsp_store
10783 .languages
10784 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10785 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10786 cx.notify();
10787 })
10788 .ok();
10789 });
10790 }
10791
10792 if server_state.is_some() {
10793 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10794 }
10795 Task::ready(())
10796 }
10797
10798 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10799 self.shutdown_all_language_servers(cx).detach();
10800 }
10801
10802 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10803 if let Some((client, project_id)) = self.upstream_client() {
10804 let request = client.request(proto::StopLanguageServers {
10805 project_id,
10806 buffer_ids: Vec::new(),
10807 also_servers: Vec::new(),
10808 all: true,
10809 });
10810 cx.background_spawn(async move {
10811 request.await.ok();
10812 })
10813 } else {
10814 let Some(local) = self.as_local_mut() else {
10815 return Task::ready(());
10816 };
10817 let language_servers_to_stop = local
10818 .language_server_ids
10819 .values()
10820 .map(|state| state.id)
10821 .collect();
10822 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10823 let tasks = language_servers_to_stop
10824 .into_iter()
10825 .map(|server| self.stop_local_language_server(server, cx))
10826 .collect::<Vec<_>>();
10827 cx.background_spawn(async move {
10828 futures::future::join_all(tasks).await;
10829 })
10830 }
10831 }
10832
10833 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10834 let buffers = self.buffer_store.read(cx).buffers().collect();
10835 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10836 }
10837
10838 pub fn restart_language_servers_for_buffers(
10839 &mut self,
10840 buffers: Vec<Entity<Buffer>>,
10841 only_restart_servers: HashSet<LanguageServerSelector>,
10842 cx: &mut Context<Self>,
10843 ) {
10844 if let Some((client, project_id)) = self.upstream_client() {
10845 let request = client.request(proto::RestartLanguageServers {
10846 project_id,
10847 buffer_ids: buffers
10848 .into_iter()
10849 .map(|b| b.read(cx).remote_id().to_proto())
10850 .collect(),
10851 only_servers: only_restart_servers
10852 .into_iter()
10853 .map(|selector| {
10854 let selector = match selector {
10855 LanguageServerSelector::Id(language_server_id) => {
10856 proto::language_server_selector::Selector::ServerId(
10857 language_server_id.to_proto(),
10858 )
10859 }
10860 LanguageServerSelector::Name(language_server_name) => {
10861 proto::language_server_selector::Selector::Name(
10862 language_server_name.to_string(),
10863 )
10864 }
10865 };
10866 proto::LanguageServerSelector {
10867 selector: Some(selector),
10868 }
10869 })
10870 .collect(),
10871 all: false,
10872 });
10873 cx.background_spawn(request).detach_and_log_err(cx);
10874 } else {
10875 let stop_task = if only_restart_servers.is_empty() {
10876 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10877 } else {
10878 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10879 };
10880 cx.spawn(async move |lsp_store, cx| {
10881 stop_task.await;
10882 lsp_store.update(cx, |lsp_store, cx| {
10883 for buffer in buffers {
10884 lsp_store.register_buffer_with_language_servers(
10885 &buffer,
10886 only_restart_servers.clone(),
10887 true,
10888 cx,
10889 );
10890 }
10891 })
10892 })
10893 .detach();
10894 }
10895 }
10896
10897 pub fn stop_language_servers_for_buffers(
10898 &mut self,
10899 buffers: Vec<Entity<Buffer>>,
10900 also_stop_servers: HashSet<LanguageServerSelector>,
10901 cx: &mut Context<Self>,
10902 ) -> Task<Result<()>> {
10903 if let Some((client, project_id)) = self.upstream_client() {
10904 let request = client.request(proto::StopLanguageServers {
10905 project_id,
10906 buffer_ids: buffers
10907 .into_iter()
10908 .map(|b| b.read(cx).remote_id().to_proto())
10909 .collect(),
10910 also_servers: also_stop_servers
10911 .into_iter()
10912 .map(|selector| {
10913 let selector = match selector {
10914 LanguageServerSelector::Id(language_server_id) => {
10915 proto::language_server_selector::Selector::ServerId(
10916 language_server_id.to_proto(),
10917 )
10918 }
10919 LanguageServerSelector::Name(language_server_name) => {
10920 proto::language_server_selector::Selector::Name(
10921 language_server_name.to_string(),
10922 )
10923 }
10924 };
10925 proto::LanguageServerSelector {
10926 selector: Some(selector),
10927 }
10928 })
10929 .collect(),
10930 all: false,
10931 });
10932 cx.background_spawn(async move {
10933 let _ = request.await?;
10934 Ok(())
10935 })
10936 } else {
10937 let task =
10938 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10939 cx.background_spawn(async move {
10940 task.await;
10941 Ok(())
10942 })
10943 }
10944 }
10945
10946 fn stop_local_language_servers_for_buffers(
10947 &mut self,
10948 buffers: &[Entity<Buffer>],
10949 also_stop_servers: HashSet<LanguageServerSelector>,
10950 cx: &mut Context<Self>,
10951 ) -> Task<()> {
10952 let Some(local) = self.as_local_mut() else {
10953 return Task::ready(());
10954 };
10955 let mut language_server_names_to_stop = BTreeSet::default();
10956 let mut language_servers_to_stop = also_stop_servers
10957 .into_iter()
10958 .flat_map(|selector| match selector {
10959 LanguageServerSelector::Id(id) => Some(id),
10960 LanguageServerSelector::Name(name) => {
10961 language_server_names_to_stop.insert(name);
10962 None
10963 }
10964 })
10965 .collect::<BTreeSet<_>>();
10966
10967 let mut covered_worktrees = HashSet::default();
10968 for buffer in buffers {
10969 buffer.update(cx, |buffer, cx| {
10970 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10971 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10972 && covered_worktrees.insert(worktree_id)
10973 {
10974 language_server_names_to_stop.retain(|name| {
10975 let old_ids_count = language_servers_to_stop.len();
10976 let all_language_servers_with_this_name = local
10977 .language_server_ids
10978 .iter()
10979 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10980 language_servers_to_stop.extend(all_language_servers_with_this_name);
10981 old_ids_count == language_servers_to_stop.len()
10982 });
10983 }
10984 });
10985 }
10986 for name in language_server_names_to_stop {
10987 language_servers_to_stop.extend(
10988 local
10989 .language_server_ids
10990 .iter()
10991 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10992 );
10993 }
10994
10995 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10996 let tasks = language_servers_to_stop
10997 .into_iter()
10998 .map(|server| self.stop_local_language_server(server, cx))
10999 .collect::<Vec<_>>();
11000
11001 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11002 }
11003
11004 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11005 let (worktree, relative_path) =
11006 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11007
11008 let project_path = ProjectPath {
11009 worktree_id: worktree.read(cx).id(),
11010 path: relative_path,
11011 };
11012
11013 Some(
11014 self.buffer_store()
11015 .read(cx)
11016 .get_by_path(&project_path)?
11017 .read(cx),
11018 )
11019 }
11020
11021 #[cfg(any(test, feature = "test-support"))]
11022 pub fn update_diagnostics(
11023 &mut self,
11024 server_id: LanguageServerId,
11025 diagnostics: lsp::PublishDiagnosticsParams,
11026 result_id: Option<SharedString>,
11027 source_kind: DiagnosticSourceKind,
11028 disk_based_sources: &[String],
11029 cx: &mut Context<Self>,
11030 ) -> Result<()> {
11031 self.merge_lsp_diagnostics(
11032 source_kind,
11033 vec![DocumentDiagnosticsUpdate {
11034 diagnostics,
11035 result_id,
11036 server_id,
11037 disk_based_sources: Cow::Borrowed(disk_based_sources),
11038 registration_id: None,
11039 }],
11040 |_, _, _| false,
11041 cx,
11042 )
11043 }
11044
11045 pub fn merge_lsp_diagnostics(
11046 &mut self,
11047 source_kind: DiagnosticSourceKind,
11048 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11049 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11050 cx: &mut Context<Self>,
11051 ) -> Result<()> {
11052 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11053 let updates = lsp_diagnostics
11054 .into_iter()
11055 .filter_map(|update| {
11056 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11057 Some(DocumentDiagnosticsUpdate {
11058 diagnostics: self.lsp_to_document_diagnostics(
11059 abs_path,
11060 source_kind,
11061 update.server_id,
11062 update.diagnostics,
11063 &update.disk_based_sources,
11064 update.registration_id.clone(),
11065 ),
11066 result_id: update.result_id,
11067 server_id: update.server_id,
11068 disk_based_sources: update.disk_based_sources,
11069 registration_id: update.registration_id,
11070 })
11071 })
11072 .collect();
11073 self.merge_diagnostic_entries(updates, merge, cx)?;
11074 Ok(())
11075 }
11076
11077 fn lsp_to_document_diagnostics(
11078 &mut self,
11079 document_abs_path: PathBuf,
11080 source_kind: DiagnosticSourceKind,
11081 server_id: LanguageServerId,
11082 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11083 disk_based_sources: &[String],
11084 registration_id: Option<SharedString>,
11085 ) -> DocumentDiagnostics {
11086 let mut diagnostics = Vec::default();
11087 let mut primary_diagnostic_group_ids = HashMap::default();
11088 let mut sources_by_group_id = HashMap::default();
11089 let mut supporting_diagnostics = HashMap::default();
11090
11091 let adapter = self.language_server_adapter_for_id(server_id);
11092
11093 // Ensure that primary diagnostics are always the most severe
11094 lsp_diagnostics
11095 .diagnostics
11096 .sort_by_key(|item| item.severity);
11097
11098 for diagnostic in &lsp_diagnostics.diagnostics {
11099 let source = diagnostic.source.as_ref();
11100 let range = range_from_lsp(diagnostic.range);
11101 let is_supporting = diagnostic
11102 .related_information
11103 .as_ref()
11104 .is_some_and(|infos| {
11105 infos.iter().any(|info| {
11106 primary_diagnostic_group_ids.contains_key(&(
11107 source,
11108 diagnostic.code.clone(),
11109 range_from_lsp(info.location.range),
11110 ))
11111 })
11112 });
11113
11114 let is_unnecessary = diagnostic
11115 .tags
11116 .as_ref()
11117 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11118
11119 let underline = self
11120 .language_server_adapter_for_id(server_id)
11121 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11122
11123 if is_supporting {
11124 supporting_diagnostics.insert(
11125 (source, diagnostic.code.clone(), range),
11126 (diagnostic.severity, is_unnecessary),
11127 );
11128 } else {
11129 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11130 let is_disk_based =
11131 source.is_some_and(|source| disk_based_sources.contains(source));
11132
11133 sources_by_group_id.insert(group_id, source);
11134 primary_diagnostic_group_ids
11135 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11136
11137 diagnostics.push(DiagnosticEntry {
11138 range,
11139 diagnostic: Diagnostic {
11140 source: diagnostic.source.clone(),
11141 source_kind,
11142 code: diagnostic.code.clone(),
11143 code_description: diagnostic
11144 .code_description
11145 .as_ref()
11146 .and_then(|d| d.href.clone()),
11147 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11148 markdown: adapter.as_ref().and_then(|adapter| {
11149 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11150 }),
11151 message: diagnostic.message.trim().to_string(),
11152 group_id,
11153 is_primary: true,
11154 is_disk_based,
11155 is_unnecessary,
11156 underline,
11157 data: diagnostic.data.clone(),
11158 registration_id: registration_id.clone(),
11159 },
11160 });
11161 if let Some(infos) = &diagnostic.related_information {
11162 for info in infos {
11163 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11164 let range = range_from_lsp(info.location.range);
11165 diagnostics.push(DiagnosticEntry {
11166 range,
11167 diagnostic: Diagnostic {
11168 source: diagnostic.source.clone(),
11169 source_kind,
11170 code: diagnostic.code.clone(),
11171 code_description: diagnostic
11172 .code_description
11173 .as_ref()
11174 .and_then(|d| d.href.clone()),
11175 severity: DiagnosticSeverity::INFORMATION,
11176 markdown: adapter.as_ref().and_then(|adapter| {
11177 adapter.diagnostic_message_to_markdown(&info.message)
11178 }),
11179 message: info.message.trim().to_string(),
11180 group_id,
11181 is_primary: false,
11182 is_disk_based,
11183 is_unnecessary: false,
11184 underline,
11185 data: diagnostic.data.clone(),
11186 registration_id: registration_id.clone(),
11187 },
11188 });
11189 }
11190 }
11191 }
11192 }
11193 }
11194
11195 for entry in &mut diagnostics {
11196 let diagnostic = &mut entry.diagnostic;
11197 if !diagnostic.is_primary {
11198 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11199 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11200 source,
11201 diagnostic.code.clone(),
11202 entry.range.clone(),
11203 )) {
11204 if let Some(severity) = severity {
11205 diagnostic.severity = severity;
11206 }
11207 diagnostic.is_unnecessary = is_unnecessary;
11208 }
11209 }
11210 }
11211
11212 DocumentDiagnostics {
11213 diagnostics,
11214 document_abs_path,
11215 version: lsp_diagnostics.version,
11216 }
11217 }
11218
11219 fn insert_newly_running_language_server(
11220 &mut self,
11221 adapter: Arc<CachedLspAdapter>,
11222 language_server: Arc<LanguageServer>,
11223 server_id: LanguageServerId,
11224 key: LanguageServerSeed,
11225 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11226 cx: &mut Context<Self>,
11227 ) {
11228 let Some(local) = self.as_local_mut() else {
11229 return;
11230 };
11231 // If the language server for this key doesn't match the server id, don't store the
11232 // server. Which will cause it to be dropped, killing the process
11233 if local
11234 .language_server_ids
11235 .get(&key)
11236 .map(|state| state.id != server_id)
11237 .unwrap_or(false)
11238 {
11239 return;
11240 }
11241
11242 // Update language_servers collection with Running variant of LanguageServerState
11243 // indicating that the server is up and running and ready
11244 let workspace_folders = workspace_folders.lock().clone();
11245 language_server.set_workspace_folders(workspace_folders);
11246
11247 let workspace_diagnostics_refresh_tasks = language_server
11248 .capabilities()
11249 .diagnostic_provider
11250 .and_then(|provider| {
11251 local
11252 .language_server_dynamic_registrations
11253 .entry(server_id)
11254 .or_default()
11255 .diagnostics
11256 .entry(None)
11257 .or_insert(provider.clone());
11258 let workspace_refresher =
11259 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11260
11261 Some((None, workspace_refresher))
11262 })
11263 .into_iter()
11264 .collect();
11265 local.language_servers.insert(
11266 server_id,
11267 LanguageServerState::Running {
11268 workspace_diagnostics_refresh_tasks,
11269 adapter: adapter.clone(),
11270 server: language_server.clone(),
11271 simulate_disk_based_diagnostics_completion: None,
11272 },
11273 );
11274 local
11275 .languages
11276 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11277 if let Some(file_ops_caps) = language_server
11278 .capabilities()
11279 .workspace
11280 .as_ref()
11281 .and_then(|ws| ws.file_operations.as_ref())
11282 {
11283 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11284 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11285 if did_rename_caps.or(will_rename_caps).is_some() {
11286 let watcher = RenamePathsWatchedForServer::default()
11287 .with_did_rename_patterns(did_rename_caps)
11288 .with_will_rename_patterns(will_rename_caps);
11289 local
11290 .language_server_paths_watched_for_rename
11291 .insert(server_id, watcher);
11292 }
11293 }
11294
11295 self.language_server_statuses.insert(
11296 server_id,
11297 LanguageServerStatus {
11298 name: language_server.name(),
11299 server_version: language_server.version(),
11300 pending_work: Default::default(),
11301 has_pending_diagnostic_updates: false,
11302 progress_tokens: Default::default(),
11303 worktree: Some(key.worktree_id),
11304 binary: Some(language_server.binary().clone()),
11305 configuration: Some(language_server.configuration().clone()),
11306 workspace_folders: language_server.workspace_folders(),
11307 process_id: language_server.process_id(),
11308 },
11309 );
11310
11311 cx.emit(LspStoreEvent::LanguageServerAdded(
11312 server_id,
11313 language_server.name(),
11314 Some(key.worktree_id),
11315 ));
11316
11317 let server_capabilities = language_server.capabilities();
11318 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11319 downstream_client
11320 .send(proto::StartLanguageServer {
11321 project_id: *project_id,
11322 server: Some(proto::LanguageServer {
11323 id: server_id.to_proto(),
11324 name: language_server.name().to_string(),
11325 worktree_id: Some(key.worktree_id.to_proto()),
11326 }),
11327 capabilities: serde_json::to_string(&server_capabilities)
11328 .expect("serializing server LSP capabilities"),
11329 })
11330 .log_err();
11331 }
11332 self.lsp_server_capabilities
11333 .insert(server_id, server_capabilities);
11334
11335 // Tell the language server about every open buffer in the worktree that matches the language.
11336 // Also check for buffers in worktrees that reused this server
11337 let mut worktrees_using_server = vec![key.worktree_id];
11338 if let Some(local) = self.as_local() {
11339 // Find all worktrees that have this server in their language server tree
11340 for (worktree_id, servers) in &local.lsp_tree.instances {
11341 if *worktree_id != key.worktree_id {
11342 for server_map in servers.roots.values() {
11343 if server_map
11344 .values()
11345 .any(|(node, _)| node.id() == Some(server_id))
11346 {
11347 worktrees_using_server.push(*worktree_id);
11348 }
11349 }
11350 }
11351 }
11352 }
11353
11354 let mut buffer_paths_registered = Vec::new();
11355 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11356 let mut lsp_adapters = HashMap::default();
11357 for buffer_handle in buffer_store.buffers() {
11358 let buffer = buffer_handle.read(cx);
11359 let file = match File::from_dyn(buffer.file()) {
11360 Some(file) => file,
11361 None => continue,
11362 };
11363 let language = match buffer.language() {
11364 Some(language) => language,
11365 None => continue,
11366 };
11367
11368 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11369 || !lsp_adapters
11370 .entry(language.name())
11371 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11372 .iter()
11373 .any(|a| a.name == key.name)
11374 {
11375 continue;
11376 }
11377 // didOpen
11378 let file = match file.as_local() {
11379 Some(file) => file,
11380 None => continue,
11381 };
11382
11383 let local = self.as_local_mut().unwrap();
11384
11385 let buffer_id = buffer.remote_id();
11386 if local.registered_buffers.contains_key(&buffer_id) {
11387 let versions = local
11388 .buffer_snapshots
11389 .entry(buffer_id)
11390 .or_default()
11391 .entry(server_id)
11392 .and_modify(|_| {
11393 assert!(
11394 false,
11395 "There should not be an existing snapshot for a newly inserted buffer"
11396 )
11397 })
11398 .or_insert_with(|| {
11399 vec![LspBufferSnapshot {
11400 version: 0,
11401 snapshot: buffer.text_snapshot(),
11402 }]
11403 });
11404
11405 let snapshot = versions.last().unwrap();
11406 let version = snapshot.version;
11407 let initial_snapshot = &snapshot.snapshot;
11408 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11409 language_server.register_buffer(
11410 uri,
11411 adapter.language_id(&language.name()),
11412 version,
11413 initial_snapshot.text(),
11414 );
11415 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11416 local
11417 .buffers_opened_in_servers
11418 .entry(buffer_id)
11419 .or_default()
11420 .insert(server_id);
11421 }
11422 buffer_handle.update(cx, |buffer, cx| {
11423 buffer.set_completion_triggers(
11424 server_id,
11425 language_server
11426 .capabilities()
11427 .completion_provider
11428 .as_ref()
11429 .and_then(|provider| {
11430 provider
11431 .trigger_characters
11432 .as_ref()
11433 .map(|characters| characters.iter().cloned().collect())
11434 })
11435 .unwrap_or_default(),
11436 cx,
11437 )
11438 });
11439 }
11440 });
11441
11442 for (buffer_id, abs_path) in buffer_paths_registered {
11443 cx.emit(LspStoreEvent::LanguageServerUpdate {
11444 language_server_id: server_id,
11445 name: Some(adapter.name()),
11446 message: proto::update_language_server::Variant::RegisteredForBuffer(
11447 proto::RegisteredForBuffer {
11448 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11449 buffer_id: buffer_id.to_proto(),
11450 },
11451 ),
11452 });
11453 }
11454
11455 cx.notify();
11456 }
11457
11458 pub fn language_servers_running_disk_based_diagnostics(
11459 &self,
11460 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11461 self.language_server_statuses
11462 .iter()
11463 .filter_map(|(id, status)| {
11464 if status.has_pending_diagnostic_updates {
11465 Some(*id)
11466 } else {
11467 None
11468 }
11469 })
11470 }
11471
11472 pub(crate) fn cancel_language_server_work_for_buffers(
11473 &mut self,
11474 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11475 cx: &mut Context<Self>,
11476 ) {
11477 if let Some((client, project_id)) = self.upstream_client() {
11478 let request = client.request(proto::CancelLanguageServerWork {
11479 project_id,
11480 work: Some(proto::cancel_language_server_work::Work::Buffers(
11481 proto::cancel_language_server_work::Buffers {
11482 buffer_ids: buffers
11483 .into_iter()
11484 .map(|b| b.read(cx).remote_id().to_proto())
11485 .collect(),
11486 },
11487 )),
11488 });
11489 cx.background_spawn(request).detach_and_log_err(cx);
11490 } else if let Some(local) = self.as_local() {
11491 let servers = buffers
11492 .into_iter()
11493 .flat_map(|buffer| {
11494 buffer.update(cx, |buffer, cx| {
11495 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11496 })
11497 })
11498 .collect::<HashSet<_>>();
11499 for server_id in servers {
11500 self.cancel_language_server_work(server_id, None, cx);
11501 }
11502 }
11503 }
11504
11505 pub(crate) fn cancel_language_server_work(
11506 &mut self,
11507 server_id: LanguageServerId,
11508 token_to_cancel: Option<ProgressToken>,
11509 cx: &mut Context<Self>,
11510 ) {
11511 if let Some(local) = self.as_local() {
11512 let status = self.language_server_statuses.get(&server_id);
11513 let server = local.language_servers.get(&server_id);
11514 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11515 {
11516 for (token, progress) in &status.pending_work {
11517 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11518 && token != token_to_cancel
11519 {
11520 continue;
11521 }
11522 if progress.is_cancellable {
11523 server
11524 .notify::<lsp::notification::WorkDoneProgressCancel>(
11525 WorkDoneProgressCancelParams {
11526 token: token.to_lsp(),
11527 },
11528 )
11529 .ok();
11530 }
11531 }
11532 }
11533 } else if let Some((client, project_id)) = self.upstream_client() {
11534 let request = client.request(proto::CancelLanguageServerWork {
11535 project_id,
11536 work: Some(
11537 proto::cancel_language_server_work::Work::LanguageServerWork(
11538 proto::cancel_language_server_work::LanguageServerWork {
11539 language_server_id: server_id.to_proto(),
11540 token: token_to_cancel.map(|token| token.to_proto()),
11541 },
11542 ),
11543 ),
11544 });
11545 cx.background_spawn(request).detach_and_log_err(cx);
11546 }
11547 }
11548
11549 fn register_supplementary_language_server(
11550 &mut self,
11551 id: LanguageServerId,
11552 name: LanguageServerName,
11553 server: Arc<LanguageServer>,
11554 cx: &mut Context<Self>,
11555 ) {
11556 if let Some(local) = self.as_local_mut() {
11557 local
11558 .supplementary_language_servers
11559 .insert(id, (name.clone(), server));
11560 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11561 }
11562 }
11563
11564 fn unregister_supplementary_language_server(
11565 &mut self,
11566 id: LanguageServerId,
11567 cx: &mut Context<Self>,
11568 ) {
11569 if let Some(local) = self.as_local_mut() {
11570 local.supplementary_language_servers.remove(&id);
11571 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11572 }
11573 }
11574
11575 pub(crate) fn supplementary_language_servers(
11576 &self,
11577 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11578 self.as_local().into_iter().flat_map(|local| {
11579 local
11580 .supplementary_language_servers
11581 .iter()
11582 .map(|(id, (name, _))| (*id, name.clone()))
11583 })
11584 }
11585
11586 pub fn language_server_adapter_for_id(
11587 &self,
11588 id: LanguageServerId,
11589 ) -> Option<Arc<CachedLspAdapter>> {
11590 self.as_local()
11591 .and_then(|local| local.language_servers.get(&id))
11592 .and_then(|language_server_state| match language_server_state {
11593 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11594 _ => None,
11595 })
11596 }
11597
11598 pub(super) fn update_local_worktree_language_servers(
11599 &mut self,
11600 worktree_handle: &Entity<Worktree>,
11601 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11602 cx: &mut Context<Self>,
11603 ) {
11604 if changes.is_empty() {
11605 return;
11606 }
11607
11608 let Some(local) = self.as_local() else { return };
11609
11610 local.prettier_store.update(cx, |prettier_store, cx| {
11611 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11612 });
11613
11614 let worktree_id = worktree_handle.read(cx).id();
11615 let mut language_server_ids = local
11616 .language_server_ids
11617 .iter()
11618 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11619 .collect::<Vec<_>>();
11620 language_server_ids.sort();
11621 language_server_ids.dedup();
11622
11623 // let abs_path = worktree_handle.read(cx).abs_path();
11624 for server_id in &language_server_ids {
11625 if let Some(LanguageServerState::Running { server, .. }) =
11626 local.language_servers.get(server_id)
11627 && let Some(watched_paths) = local
11628 .language_server_watched_paths
11629 .get(server_id)
11630 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11631 {
11632 let params = lsp::DidChangeWatchedFilesParams {
11633 changes: changes
11634 .iter()
11635 .filter_map(|(path, _, change)| {
11636 if !watched_paths.is_match(path.as_std_path()) {
11637 return None;
11638 }
11639 let typ = match change {
11640 PathChange::Loaded => return None,
11641 PathChange::Added => lsp::FileChangeType::CREATED,
11642 PathChange::Removed => lsp::FileChangeType::DELETED,
11643 PathChange::Updated => lsp::FileChangeType::CHANGED,
11644 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11645 };
11646 let uri = lsp::Uri::from_file_path(
11647 worktree_handle.read(cx).absolutize(&path),
11648 )
11649 .ok()?;
11650 Some(lsp::FileEvent { uri, typ })
11651 })
11652 .collect(),
11653 };
11654 if !params.changes.is_empty() {
11655 server
11656 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11657 .ok();
11658 }
11659 }
11660 }
11661 for (path, _, _) in changes {
11662 if let Some(file_name) = path.file_name()
11663 && local.watched_manifest_filenames.contains(file_name)
11664 {
11665 self.request_workspace_config_refresh();
11666 break;
11667 }
11668 }
11669 }
11670
11671 pub fn wait_for_remote_buffer(
11672 &mut self,
11673 id: BufferId,
11674 cx: &mut Context<Self>,
11675 ) -> Task<Result<Entity<Buffer>>> {
11676 self.buffer_store.update(cx, |buffer_store, cx| {
11677 buffer_store.wait_for_remote_buffer(id, cx)
11678 })
11679 }
11680
11681 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11682 let mut result = proto::Symbol {
11683 language_server_name: symbol.language_server_name.0.to_string(),
11684 source_worktree_id: symbol.source_worktree_id.to_proto(),
11685 language_server_id: symbol.source_language_server_id.to_proto(),
11686 name: symbol.name.clone(),
11687 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11688 start: Some(proto::PointUtf16 {
11689 row: symbol.range.start.0.row,
11690 column: symbol.range.start.0.column,
11691 }),
11692 end: Some(proto::PointUtf16 {
11693 row: symbol.range.end.0.row,
11694 column: symbol.range.end.0.column,
11695 }),
11696 worktree_id: Default::default(),
11697 path: Default::default(),
11698 signature: Default::default(),
11699 container_name: symbol.container_name.clone(),
11700 };
11701 match &symbol.path {
11702 SymbolLocation::InProject(path) => {
11703 result.worktree_id = path.worktree_id.to_proto();
11704 result.path = path.path.to_proto();
11705 }
11706 SymbolLocation::OutsideProject {
11707 abs_path,
11708 signature,
11709 } => {
11710 result.path = abs_path.to_string_lossy().into_owned();
11711 result.signature = signature.to_vec();
11712 }
11713 }
11714 result
11715 }
11716
11717 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11718 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11719 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11720 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11721
11722 let path = if serialized_symbol.signature.is_empty() {
11723 SymbolLocation::InProject(ProjectPath {
11724 worktree_id,
11725 path: RelPath::from_proto(&serialized_symbol.path)
11726 .context("invalid symbol path")?,
11727 })
11728 } else {
11729 SymbolLocation::OutsideProject {
11730 abs_path: Path::new(&serialized_symbol.path).into(),
11731 signature: serialized_symbol
11732 .signature
11733 .try_into()
11734 .map_err(|_| anyhow!("invalid signature"))?,
11735 }
11736 };
11737
11738 let start = serialized_symbol.start.context("invalid start")?;
11739 let end = serialized_symbol.end.context("invalid end")?;
11740 Ok(CoreSymbol {
11741 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11742 source_worktree_id,
11743 source_language_server_id: LanguageServerId::from_proto(
11744 serialized_symbol.language_server_id,
11745 ),
11746 path,
11747 name: serialized_symbol.name,
11748 range: Unclipped(PointUtf16::new(start.row, start.column))
11749 ..Unclipped(PointUtf16::new(end.row, end.column)),
11750 kind,
11751 container_name: serialized_symbol.container_name,
11752 })
11753 }
11754
11755 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11756 let mut serialized_completion = proto::Completion {
11757 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11758 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11759 new_text: completion.new_text.clone(),
11760 ..proto::Completion::default()
11761 };
11762 match &completion.source {
11763 CompletionSource::Lsp {
11764 insert_range,
11765 server_id,
11766 lsp_completion,
11767 lsp_defaults,
11768 resolved,
11769 } => {
11770 let (old_insert_start, old_insert_end) = insert_range
11771 .as_ref()
11772 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11773 .unzip();
11774
11775 serialized_completion.old_insert_start = old_insert_start;
11776 serialized_completion.old_insert_end = old_insert_end;
11777 serialized_completion.source = proto::completion::Source::Lsp as i32;
11778 serialized_completion.server_id = server_id.0 as u64;
11779 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11780 serialized_completion.lsp_defaults = lsp_defaults
11781 .as_deref()
11782 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11783 serialized_completion.resolved = *resolved;
11784 }
11785 CompletionSource::BufferWord {
11786 word_range,
11787 resolved,
11788 } => {
11789 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11790 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11791 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11792 serialized_completion.resolved = *resolved;
11793 }
11794 CompletionSource::Custom => {
11795 serialized_completion.source = proto::completion::Source::Custom as i32;
11796 serialized_completion.resolved = true;
11797 }
11798 CompletionSource::Dap { sort_text } => {
11799 serialized_completion.source = proto::completion::Source::Dap as i32;
11800 serialized_completion.sort_text = Some(sort_text.clone());
11801 }
11802 }
11803
11804 serialized_completion
11805 }
11806
11807 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11808 let old_replace_start = completion
11809 .old_replace_start
11810 .and_then(deserialize_anchor)
11811 .context("invalid old start")?;
11812 let old_replace_end = completion
11813 .old_replace_end
11814 .and_then(deserialize_anchor)
11815 .context("invalid old end")?;
11816 let insert_range = {
11817 match completion.old_insert_start.zip(completion.old_insert_end) {
11818 Some((start, end)) => {
11819 let start = deserialize_anchor(start).context("invalid insert old start")?;
11820 let end = deserialize_anchor(end).context("invalid insert old end")?;
11821 Some(start..end)
11822 }
11823 None => None,
11824 }
11825 };
11826 Ok(CoreCompletion {
11827 replace_range: old_replace_start..old_replace_end,
11828 new_text: completion.new_text,
11829 source: match proto::completion::Source::from_i32(completion.source) {
11830 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11831 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11832 insert_range,
11833 server_id: LanguageServerId::from_proto(completion.server_id),
11834 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11835 lsp_defaults: completion
11836 .lsp_defaults
11837 .as_deref()
11838 .map(serde_json::from_slice)
11839 .transpose()?,
11840 resolved: completion.resolved,
11841 },
11842 Some(proto::completion::Source::BufferWord) => {
11843 let word_range = completion
11844 .buffer_word_start
11845 .and_then(deserialize_anchor)
11846 .context("invalid buffer word start")?
11847 ..completion
11848 .buffer_word_end
11849 .and_then(deserialize_anchor)
11850 .context("invalid buffer word end")?;
11851 CompletionSource::BufferWord {
11852 word_range,
11853 resolved: completion.resolved,
11854 }
11855 }
11856 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11857 sort_text: completion
11858 .sort_text
11859 .context("expected sort text to exist")?,
11860 },
11861 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11862 },
11863 })
11864 }
11865
11866 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11867 let (kind, lsp_action) = match &action.lsp_action {
11868 LspAction::Action(code_action) => (
11869 proto::code_action::Kind::Action as i32,
11870 serde_json::to_vec(code_action).unwrap(),
11871 ),
11872 LspAction::Command(command) => (
11873 proto::code_action::Kind::Command as i32,
11874 serde_json::to_vec(command).unwrap(),
11875 ),
11876 LspAction::CodeLens(code_lens) => (
11877 proto::code_action::Kind::CodeLens as i32,
11878 serde_json::to_vec(code_lens).unwrap(),
11879 ),
11880 };
11881
11882 proto::CodeAction {
11883 server_id: action.server_id.0 as u64,
11884 start: Some(serialize_anchor(&action.range.start)),
11885 end: Some(serialize_anchor(&action.range.end)),
11886 lsp_action,
11887 kind,
11888 resolved: action.resolved,
11889 }
11890 }
11891
11892 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11893 let start = action
11894 .start
11895 .and_then(deserialize_anchor)
11896 .context("invalid start")?;
11897 let end = action
11898 .end
11899 .and_then(deserialize_anchor)
11900 .context("invalid end")?;
11901 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11902 Some(proto::code_action::Kind::Action) => {
11903 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11904 }
11905 Some(proto::code_action::Kind::Command) => {
11906 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11907 }
11908 Some(proto::code_action::Kind::CodeLens) => {
11909 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11910 }
11911 None => anyhow::bail!("Unknown action kind {}", action.kind),
11912 };
11913 Ok(CodeAction {
11914 server_id: LanguageServerId(action.server_id as usize),
11915 range: start..end,
11916 resolved: action.resolved,
11917 lsp_action,
11918 })
11919 }
11920
11921 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11922 match &formatting_result {
11923 Ok(_) => self.last_formatting_failure = None,
11924 Err(error) => {
11925 let error_string = format!("{error:#}");
11926 log::error!("Formatting failed: {error_string}");
11927 self.last_formatting_failure
11928 .replace(error_string.lines().join(" "));
11929 }
11930 }
11931 }
11932
11933 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11934 self.lsp_server_capabilities.remove(&for_server);
11935 self.semantic_token_config.remove_server_data(for_server);
11936 for lsp_data in self.lsp_data.values_mut() {
11937 lsp_data.remove_server_data(for_server);
11938 }
11939 if let Some(local) = self.as_local_mut() {
11940 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11941 local
11942 .workspace_pull_diagnostics_result_ids
11943 .remove(&for_server);
11944 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11945 buffer_servers.remove(&for_server);
11946 }
11947 }
11948 }
11949
11950 pub fn result_id_for_buffer_pull(
11951 &self,
11952 server_id: LanguageServerId,
11953 buffer_id: BufferId,
11954 registration_id: &Option<SharedString>,
11955 cx: &App,
11956 ) -> Option<SharedString> {
11957 let abs_path = self
11958 .buffer_store
11959 .read(cx)
11960 .get(buffer_id)
11961 .and_then(|b| File::from_dyn(b.read(cx).file()))
11962 .map(|f| f.abs_path(cx))?;
11963 self.as_local()?
11964 .buffer_pull_diagnostics_result_ids
11965 .get(&server_id)?
11966 .get(registration_id)?
11967 .get(&abs_path)?
11968 .clone()
11969 }
11970
11971 /// Gets all result_ids for a workspace diagnostics pull request.
11972 /// 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.
11973 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
11974 pub fn result_ids_for_workspace_refresh(
11975 &self,
11976 server_id: LanguageServerId,
11977 registration_id: &Option<SharedString>,
11978 ) -> HashMap<PathBuf, SharedString> {
11979 let Some(local) = self.as_local() else {
11980 return HashMap::default();
11981 };
11982 local
11983 .workspace_pull_diagnostics_result_ids
11984 .get(&server_id)
11985 .into_iter()
11986 .filter_map(|diagnostics| diagnostics.get(registration_id))
11987 .flatten()
11988 .filter_map(|(abs_path, result_id)| {
11989 let result_id = local
11990 .buffer_pull_diagnostics_result_ids
11991 .get(&server_id)
11992 .and_then(|buffer_ids_result_ids| {
11993 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
11994 })
11995 .cloned()
11996 .flatten()
11997 .or_else(|| result_id.clone())?;
11998 Some((abs_path.clone(), result_id))
11999 })
12000 .collect()
12001 }
12002
12003 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12004 if let Some(LanguageServerState::Running {
12005 workspace_diagnostics_refresh_tasks,
12006 ..
12007 }) = self
12008 .as_local_mut()
12009 .and_then(|local| local.language_servers.get_mut(&server_id))
12010 {
12011 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12012 diagnostics.refresh_tx.try_send(()).ok();
12013 }
12014 }
12015 }
12016
12017 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12018 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12019 /// which requires refreshing both workspace and document diagnostics.
12020 pub fn pull_document_diagnostics_for_server(
12021 &mut self,
12022 server_id: LanguageServerId,
12023 source_buffer_id: Option<BufferId>,
12024 cx: &mut Context<Self>,
12025 ) -> Shared<Task<()>> {
12026 let Some(local) = self.as_local_mut() else {
12027 return Task::ready(()).shared();
12028 };
12029 let mut buffers_to_refresh = HashSet::default();
12030 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12031 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12032 buffers_to_refresh.insert(*buffer_id);
12033 }
12034 }
12035
12036 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12037 }
12038
12039 pub fn pull_document_diagnostics_for_buffer_edit(
12040 &mut self,
12041 buffer_id: BufferId,
12042 cx: &mut Context<Self>,
12043 ) {
12044 let Some(local) = self.as_local_mut() else {
12045 return;
12046 };
12047 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12048 else {
12049 return;
12050 };
12051 for server_id in languages_servers {
12052 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12053 }
12054 }
12055
12056 fn apply_workspace_diagnostic_report(
12057 &mut self,
12058 server_id: LanguageServerId,
12059 report: lsp::WorkspaceDiagnosticReportResult,
12060 registration_id: Option<SharedString>,
12061 cx: &mut Context<Self>,
12062 ) {
12063 let mut workspace_diagnostics =
12064 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12065 report,
12066 server_id,
12067 registration_id,
12068 );
12069 workspace_diagnostics.retain(|d| match &d.diagnostics {
12070 LspPullDiagnostics::Response {
12071 server_id,
12072 registration_id,
12073 ..
12074 } => self.diagnostic_registration_exists(*server_id, registration_id),
12075 LspPullDiagnostics::Default => false,
12076 });
12077 let mut unchanged_buffers = HashMap::default();
12078 let workspace_diagnostics_updates = workspace_diagnostics
12079 .into_iter()
12080 .filter_map(
12081 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12082 LspPullDiagnostics::Response {
12083 server_id,
12084 uri,
12085 diagnostics,
12086 registration_id,
12087 } => Some((
12088 server_id,
12089 uri,
12090 diagnostics,
12091 workspace_diagnostics.version,
12092 registration_id,
12093 )),
12094 LspPullDiagnostics::Default => None,
12095 },
12096 )
12097 .fold(
12098 HashMap::default(),
12099 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12100 let (result_id, diagnostics) = match diagnostics {
12101 PulledDiagnostics::Unchanged { result_id } => {
12102 unchanged_buffers
12103 .entry(new_registration_id.clone())
12104 .or_insert_with(HashSet::default)
12105 .insert(uri.clone());
12106 (Some(result_id), Vec::new())
12107 }
12108 PulledDiagnostics::Changed {
12109 result_id,
12110 diagnostics,
12111 } => (result_id, diagnostics),
12112 };
12113 let disk_based_sources = Cow::Owned(
12114 self.language_server_adapter_for_id(server_id)
12115 .as_ref()
12116 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12117 .unwrap_or(&[])
12118 .to_vec(),
12119 );
12120
12121 let Some(abs_path) = uri.to_file_path().ok() else {
12122 return acc;
12123 };
12124 let Some((worktree, relative_path)) =
12125 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12126 else {
12127 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12128 return acc;
12129 };
12130 let worktree_id = worktree.read(cx).id();
12131 let project_path = ProjectPath {
12132 worktree_id,
12133 path: relative_path,
12134 };
12135 if let Some(local_lsp_store) = self.as_local_mut() {
12136 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12137 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12138 }
12139 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12140 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12141 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12142 acc.entry(server_id)
12143 .or_insert_with(HashMap::default)
12144 .entry(new_registration_id.clone())
12145 .or_insert_with(Vec::new)
12146 .push(DocumentDiagnosticsUpdate {
12147 server_id,
12148 diagnostics: lsp::PublishDiagnosticsParams {
12149 uri,
12150 diagnostics,
12151 version,
12152 },
12153 result_id: result_id.map(SharedString::new),
12154 disk_based_sources,
12155 registration_id: new_registration_id,
12156 });
12157 }
12158 acc
12159 },
12160 );
12161
12162 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12163 for (registration_id, diagnostic_updates) in diagnostic_updates {
12164 self.merge_lsp_diagnostics(
12165 DiagnosticSourceKind::Pulled,
12166 diagnostic_updates,
12167 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12168 DiagnosticSourceKind::Pulled => {
12169 old_diagnostic.registration_id != registration_id
12170 || unchanged_buffers
12171 .get(&old_diagnostic.registration_id)
12172 .is_some_and(|unchanged_buffers| {
12173 unchanged_buffers.contains(&document_uri)
12174 })
12175 }
12176 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12177 },
12178 cx,
12179 )
12180 .log_err();
12181 }
12182 }
12183 }
12184
12185 fn register_server_capabilities(
12186 &mut self,
12187 server_id: LanguageServerId,
12188 params: lsp::RegistrationParams,
12189 cx: &mut Context<Self>,
12190 ) -> anyhow::Result<()> {
12191 let server = self
12192 .language_server_for_id(server_id)
12193 .with_context(|| format!("no server {server_id} found"))?;
12194 for reg in params.registrations {
12195 match reg.method.as_str() {
12196 "workspace/didChangeWatchedFiles" => {
12197 if let Some(options) = reg.register_options {
12198 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12199 let caps = serde_json::from_value(options)?;
12200 local_lsp_store
12201 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12202 true
12203 } else {
12204 false
12205 };
12206 if notify {
12207 notify_server_capabilities_updated(&server, cx);
12208 }
12209 }
12210 }
12211 "workspace/didChangeConfiguration" => {
12212 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12213 }
12214 "workspace/didChangeWorkspaceFolders" => {
12215 // In this case register options is an empty object, we can ignore it
12216 let caps = lsp::WorkspaceFoldersServerCapabilities {
12217 supported: Some(true),
12218 change_notifications: Some(OneOf::Right(reg.id)),
12219 };
12220 server.update_capabilities(|capabilities| {
12221 capabilities
12222 .workspace
12223 .get_or_insert_default()
12224 .workspace_folders = Some(caps);
12225 });
12226 notify_server_capabilities_updated(&server, cx);
12227 }
12228 "workspace/symbol" => {
12229 let options = parse_register_capabilities(reg)?;
12230 server.update_capabilities(|capabilities| {
12231 capabilities.workspace_symbol_provider = Some(options);
12232 });
12233 notify_server_capabilities_updated(&server, cx);
12234 }
12235 "workspace/fileOperations" => {
12236 if let Some(options) = reg.register_options {
12237 let caps = serde_json::from_value(options)?;
12238 server.update_capabilities(|capabilities| {
12239 capabilities
12240 .workspace
12241 .get_or_insert_default()
12242 .file_operations = Some(caps);
12243 });
12244 notify_server_capabilities_updated(&server, cx);
12245 }
12246 }
12247 "workspace/executeCommand" => {
12248 if let Some(options) = reg.register_options {
12249 let options = serde_json::from_value(options)?;
12250 server.update_capabilities(|capabilities| {
12251 capabilities.execute_command_provider = Some(options);
12252 });
12253 notify_server_capabilities_updated(&server, cx);
12254 }
12255 }
12256 "textDocument/rangeFormatting" => {
12257 let options = parse_register_capabilities(reg)?;
12258 server.update_capabilities(|capabilities| {
12259 capabilities.document_range_formatting_provider = Some(options);
12260 });
12261 notify_server_capabilities_updated(&server, cx);
12262 }
12263 "textDocument/onTypeFormatting" => {
12264 if let Some(options) = reg
12265 .register_options
12266 .map(serde_json::from_value)
12267 .transpose()?
12268 {
12269 server.update_capabilities(|capabilities| {
12270 capabilities.document_on_type_formatting_provider = Some(options);
12271 });
12272 notify_server_capabilities_updated(&server, cx);
12273 }
12274 }
12275 "textDocument/formatting" => {
12276 let options = parse_register_capabilities(reg)?;
12277 server.update_capabilities(|capabilities| {
12278 capabilities.document_formatting_provider = Some(options);
12279 });
12280 notify_server_capabilities_updated(&server, cx);
12281 }
12282 "textDocument/rename" => {
12283 let options = parse_register_capabilities(reg)?;
12284 server.update_capabilities(|capabilities| {
12285 capabilities.rename_provider = Some(options);
12286 });
12287 notify_server_capabilities_updated(&server, cx);
12288 }
12289 "textDocument/inlayHint" => {
12290 let options = parse_register_capabilities(reg)?;
12291 server.update_capabilities(|capabilities| {
12292 capabilities.inlay_hint_provider = Some(options);
12293 });
12294 notify_server_capabilities_updated(&server, cx);
12295 }
12296 "textDocument/documentSymbol" => {
12297 let options = parse_register_capabilities(reg)?;
12298 server.update_capabilities(|capabilities| {
12299 capabilities.document_symbol_provider = Some(options);
12300 });
12301 notify_server_capabilities_updated(&server, cx);
12302 }
12303 "textDocument/codeAction" => {
12304 let options = parse_register_capabilities(reg)?;
12305 let provider = match options {
12306 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12307 OneOf::Right(caps) => caps,
12308 };
12309 server.update_capabilities(|capabilities| {
12310 capabilities.code_action_provider = Some(provider);
12311 });
12312 notify_server_capabilities_updated(&server, cx);
12313 }
12314 "textDocument/definition" => {
12315 let options = parse_register_capabilities(reg)?;
12316 server.update_capabilities(|capabilities| {
12317 capabilities.definition_provider = Some(options);
12318 });
12319 notify_server_capabilities_updated(&server, cx);
12320 }
12321 "textDocument/completion" => {
12322 if let Some(caps) = reg
12323 .register_options
12324 .map(serde_json::from_value::<CompletionOptions>)
12325 .transpose()?
12326 {
12327 server.update_capabilities(|capabilities| {
12328 capabilities.completion_provider = Some(caps.clone());
12329 });
12330
12331 if let Some(local) = self.as_local() {
12332 let mut buffers_with_language_server = Vec::new();
12333 for handle in self.buffer_store.read(cx).buffers() {
12334 let buffer_id = handle.read(cx).remote_id();
12335 if local
12336 .buffers_opened_in_servers
12337 .get(&buffer_id)
12338 .filter(|s| s.contains(&server_id))
12339 .is_some()
12340 {
12341 buffers_with_language_server.push(handle);
12342 }
12343 }
12344 let triggers = caps
12345 .trigger_characters
12346 .unwrap_or_default()
12347 .into_iter()
12348 .collect::<BTreeSet<_>>();
12349 for handle in buffers_with_language_server {
12350 let triggers = triggers.clone();
12351 let _ = handle.update(cx, move |buffer, cx| {
12352 buffer.set_completion_triggers(server_id, triggers, cx);
12353 });
12354 }
12355 }
12356 notify_server_capabilities_updated(&server, cx);
12357 }
12358 }
12359 "textDocument/hover" => {
12360 let options = parse_register_capabilities(reg)?;
12361 let provider = match options {
12362 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12363 OneOf::Right(caps) => caps,
12364 };
12365 server.update_capabilities(|capabilities| {
12366 capabilities.hover_provider = Some(provider);
12367 });
12368 notify_server_capabilities_updated(&server, cx);
12369 }
12370 "textDocument/signatureHelp" => {
12371 if let Some(caps) = reg
12372 .register_options
12373 .map(serde_json::from_value)
12374 .transpose()?
12375 {
12376 server.update_capabilities(|capabilities| {
12377 capabilities.signature_help_provider = Some(caps);
12378 });
12379 notify_server_capabilities_updated(&server, cx);
12380 }
12381 }
12382 "textDocument/didChange" => {
12383 if let Some(sync_kind) = reg
12384 .register_options
12385 .and_then(|opts| opts.get("syncKind").cloned())
12386 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12387 .transpose()?
12388 {
12389 server.update_capabilities(|capabilities| {
12390 let mut sync_options =
12391 Self::take_text_document_sync_options(capabilities);
12392 sync_options.change = Some(sync_kind);
12393 capabilities.text_document_sync =
12394 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12395 });
12396 notify_server_capabilities_updated(&server, cx);
12397 }
12398 }
12399 "textDocument/didSave" => {
12400 if let Some(include_text) = reg
12401 .register_options
12402 .map(|opts| {
12403 let transpose = opts
12404 .get("includeText")
12405 .cloned()
12406 .map(serde_json::from_value::<Option<bool>>)
12407 .transpose();
12408 match transpose {
12409 Ok(value) => Ok(value.flatten()),
12410 Err(e) => Err(e),
12411 }
12412 })
12413 .transpose()?
12414 {
12415 server.update_capabilities(|capabilities| {
12416 let mut sync_options =
12417 Self::take_text_document_sync_options(capabilities);
12418 sync_options.save =
12419 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12420 include_text,
12421 }));
12422 capabilities.text_document_sync =
12423 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12424 });
12425 notify_server_capabilities_updated(&server, cx);
12426 }
12427 }
12428 "textDocument/codeLens" => {
12429 if let Some(caps) = reg
12430 .register_options
12431 .map(serde_json::from_value)
12432 .transpose()?
12433 {
12434 server.update_capabilities(|capabilities| {
12435 capabilities.code_lens_provider = Some(caps);
12436 });
12437 notify_server_capabilities_updated(&server, cx);
12438 }
12439 }
12440 "textDocument/diagnostic" => {
12441 if let Some(caps) = reg
12442 .register_options
12443 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12444 .transpose()?
12445 {
12446 let local = self
12447 .as_local_mut()
12448 .context("Expected LSP Store to be local")?;
12449 let state = local
12450 .language_servers
12451 .get_mut(&server_id)
12452 .context("Could not obtain Language Servers state")?;
12453 local
12454 .language_server_dynamic_registrations
12455 .entry(server_id)
12456 .or_default()
12457 .diagnostics
12458 .insert(Some(reg.id.clone()), caps.clone());
12459
12460 let supports_workspace_diagnostics =
12461 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12462 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12463 diagnostic_options.workspace_diagnostics
12464 }
12465 DiagnosticServerCapabilities::RegistrationOptions(
12466 diagnostic_registration_options,
12467 ) => {
12468 diagnostic_registration_options
12469 .diagnostic_options
12470 .workspace_diagnostics
12471 }
12472 };
12473
12474 if supports_workspace_diagnostics(&caps) {
12475 if let LanguageServerState::Running {
12476 workspace_diagnostics_refresh_tasks,
12477 ..
12478 } = state
12479 && let Some(task) = lsp_workspace_diagnostics_refresh(
12480 Some(reg.id.clone()),
12481 caps.clone(),
12482 server.clone(),
12483 cx,
12484 )
12485 {
12486 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12487 }
12488 }
12489
12490 server.update_capabilities(|capabilities| {
12491 capabilities.diagnostic_provider = Some(caps);
12492 });
12493
12494 notify_server_capabilities_updated(&server, cx);
12495
12496 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12497 }
12498 }
12499 "textDocument/documentColor" => {
12500 let options = parse_register_capabilities(reg)?;
12501 let provider = match options {
12502 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12503 OneOf::Right(caps) => caps,
12504 };
12505 server.update_capabilities(|capabilities| {
12506 capabilities.color_provider = Some(provider);
12507 });
12508 notify_server_capabilities_updated(&server, cx);
12509 }
12510 "textDocument/foldingRange" => {
12511 let options = parse_register_capabilities(reg)?;
12512 let provider = match options {
12513 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12514 OneOf::Right(caps) => caps,
12515 };
12516 server.update_capabilities(|capabilities| {
12517 capabilities.folding_range_provider = Some(provider);
12518 });
12519 notify_server_capabilities_updated(&server, cx);
12520 }
12521 _ => log::warn!("unhandled capability registration: {reg:?}"),
12522 }
12523 }
12524
12525 Ok(())
12526 }
12527
12528 fn unregister_server_capabilities(
12529 &mut self,
12530 server_id: LanguageServerId,
12531 params: lsp::UnregistrationParams,
12532 cx: &mut Context<Self>,
12533 ) -> anyhow::Result<()> {
12534 let server = self
12535 .language_server_for_id(server_id)
12536 .with_context(|| format!("no server {server_id} found"))?;
12537 for unreg in params.unregisterations.iter() {
12538 match unreg.method.as_str() {
12539 "workspace/didChangeWatchedFiles" => {
12540 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12541 local_lsp_store
12542 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12543 true
12544 } else {
12545 false
12546 };
12547 if notify {
12548 notify_server_capabilities_updated(&server, cx);
12549 }
12550 }
12551 "workspace/didChangeConfiguration" => {
12552 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12553 }
12554 "workspace/didChangeWorkspaceFolders" => {
12555 server.update_capabilities(|capabilities| {
12556 capabilities
12557 .workspace
12558 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12559 workspace_folders: None,
12560 file_operations: None,
12561 })
12562 .workspace_folders = None;
12563 });
12564 notify_server_capabilities_updated(&server, cx);
12565 }
12566 "workspace/symbol" => {
12567 server.update_capabilities(|capabilities| {
12568 capabilities.workspace_symbol_provider = None
12569 });
12570 notify_server_capabilities_updated(&server, cx);
12571 }
12572 "workspace/fileOperations" => {
12573 server.update_capabilities(|capabilities| {
12574 capabilities
12575 .workspace
12576 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12577 workspace_folders: None,
12578 file_operations: None,
12579 })
12580 .file_operations = None;
12581 });
12582 notify_server_capabilities_updated(&server, cx);
12583 }
12584 "workspace/executeCommand" => {
12585 server.update_capabilities(|capabilities| {
12586 capabilities.execute_command_provider = None;
12587 });
12588 notify_server_capabilities_updated(&server, cx);
12589 }
12590 "textDocument/rangeFormatting" => {
12591 server.update_capabilities(|capabilities| {
12592 capabilities.document_range_formatting_provider = None
12593 });
12594 notify_server_capabilities_updated(&server, cx);
12595 }
12596 "textDocument/onTypeFormatting" => {
12597 server.update_capabilities(|capabilities| {
12598 capabilities.document_on_type_formatting_provider = None;
12599 });
12600 notify_server_capabilities_updated(&server, cx);
12601 }
12602 "textDocument/formatting" => {
12603 server.update_capabilities(|capabilities| {
12604 capabilities.document_formatting_provider = None;
12605 });
12606 notify_server_capabilities_updated(&server, cx);
12607 }
12608 "textDocument/rename" => {
12609 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12610 notify_server_capabilities_updated(&server, cx);
12611 }
12612 "textDocument/codeAction" => {
12613 server.update_capabilities(|capabilities| {
12614 capabilities.code_action_provider = None;
12615 });
12616 notify_server_capabilities_updated(&server, cx);
12617 }
12618 "textDocument/definition" => {
12619 server.update_capabilities(|capabilities| {
12620 capabilities.definition_provider = None;
12621 });
12622 notify_server_capabilities_updated(&server, cx);
12623 }
12624 "textDocument/completion" => {
12625 server.update_capabilities(|capabilities| {
12626 capabilities.completion_provider = None;
12627 });
12628 notify_server_capabilities_updated(&server, cx);
12629 }
12630 "textDocument/hover" => {
12631 server.update_capabilities(|capabilities| {
12632 capabilities.hover_provider = None;
12633 });
12634 notify_server_capabilities_updated(&server, cx);
12635 }
12636 "textDocument/signatureHelp" => {
12637 server.update_capabilities(|capabilities| {
12638 capabilities.signature_help_provider = None;
12639 });
12640 notify_server_capabilities_updated(&server, cx);
12641 }
12642 "textDocument/didChange" => {
12643 server.update_capabilities(|capabilities| {
12644 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12645 sync_options.change = None;
12646 capabilities.text_document_sync =
12647 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12648 });
12649 notify_server_capabilities_updated(&server, cx);
12650 }
12651 "textDocument/didSave" => {
12652 server.update_capabilities(|capabilities| {
12653 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12654 sync_options.save = None;
12655 capabilities.text_document_sync =
12656 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12657 });
12658 notify_server_capabilities_updated(&server, cx);
12659 }
12660 "textDocument/codeLens" => {
12661 server.update_capabilities(|capabilities| {
12662 capabilities.code_lens_provider = None;
12663 });
12664 notify_server_capabilities_updated(&server, cx);
12665 }
12666 "textDocument/diagnostic" => {
12667 let local = self
12668 .as_local_mut()
12669 .context("Expected LSP Store to be local")?;
12670
12671 let state = local
12672 .language_servers
12673 .get_mut(&server_id)
12674 .context("Could not obtain Language Servers state")?;
12675 let registrations = local
12676 .language_server_dynamic_registrations
12677 .get_mut(&server_id)
12678 .with_context(|| {
12679 format!("Expected dynamic registration to exist for server {server_id}")
12680 })?;
12681 registrations.diagnostics
12682 .remove(&Some(unreg.id.clone()))
12683 .with_context(|| format!(
12684 "Attempted to unregister non-existent diagnostic registration with ID {}",
12685 unreg.id)
12686 )?;
12687 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12688
12689 if let LanguageServerState::Running {
12690 workspace_diagnostics_refresh_tasks,
12691 ..
12692 } = state
12693 {
12694 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12695 }
12696
12697 self.clear_unregistered_diagnostics(
12698 server_id,
12699 SharedString::from(unreg.id.clone()),
12700 cx,
12701 )?;
12702
12703 if removed_last_diagnostic_provider {
12704 server.update_capabilities(|capabilities| {
12705 debug_assert!(capabilities.diagnostic_provider.is_some());
12706 capabilities.diagnostic_provider = None;
12707 });
12708 }
12709
12710 notify_server_capabilities_updated(&server, cx);
12711 }
12712 "textDocument/documentColor" => {
12713 server.update_capabilities(|capabilities| {
12714 capabilities.color_provider = None;
12715 });
12716 notify_server_capabilities_updated(&server, cx);
12717 }
12718 "textDocument/foldingRange" => {
12719 server.update_capabilities(|capabilities| {
12720 capabilities.folding_range_provider = None;
12721 });
12722 notify_server_capabilities_updated(&server, cx);
12723 }
12724 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12725 }
12726 }
12727
12728 Ok(())
12729 }
12730
12731 fn clear_unregistered_diagnostics(
12732 &mut self,
12733 server_id: LanguageServerId,
12734 cleared_registration_id: SharedString,
12735 cx: &mut Context<Self>,
12736 ) -> anyhow::Result<()> {
12737 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12738
12739 self.buffer_store.update(cx, |buffer_store, cx| {
12740 for buffer_handle in buffer_store.buffers() {
12741 let buffer = buffer_handle.read(cx);
12742 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12743 let Some(abs_path) = abs_path else {
12744 continue;
12745 };
12746 affected_abs_paths.insert(abs_path);
12747 }
12748 });
12749
12750 let local = self.as_local().context("Expected LSP Store to be local")?;
12751 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12752 let Some(worktree) = self
12753 .worktree_store
12754 .read(cx)
12755 .worktree_for_id(*worktree_id, cx)
12756 else {
12757 continue;
12758 };
12759
12760 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12761 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12762 let has_matching_registration =
12763 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12764 entry.diagnostic.registration_id.as_ref()
12765 == Some(&cleared_registration_id)
12766 });
12767 if has_matching_registration {
12768 let abs_path = worktree.read(cx).absolutize(rel_path);
12769 affected_abs_paths.insert(abs_path);
12770 }
12771 }
12772 }
12773 }
12774
12775 if affected_abs_paths.is_empty() {
12776 return Ok(());
12777 }
12778
12779 // Send a fake diagnostic update which clears the state for the registration ID
12780 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12781 affected_abs_paths
12782 .into_iter()
12783 .map(|abs_path| DocumentDiagnosticsUpdate {
12784 diagnostics: DocumentDiagnostics {
12785 diagnostics: Vec::new(),
12786 document_abs_path: abs_path,
12787 version: None,
12788 },
12789 result_id: None,
12790 registration_id: Some(cleared_registration_id.clone()),
12791 server_id,
12792 disk_based_sources: Cow::Borrowed(&[]),
12793 })
12794 .collect();
12795
12796 let merge_registration_id = cleared_registration_id.clone();
12797 self.merge_diagnostic_entries(
12798 clears,
12799 move |_, diagnostic, _| {
12800 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12801 diagnostic.registration_id != Some(merge_registration_id.clone())
12802 } else {
12803 true
12804 }
12805 },
12806 cx,
12807 )?;
12808
12809 Ok(())
12810 }
12811
12812 async fn deduplicate_range_based_lsp_requests<T>(
12813 lsp_store: &Entity<Self>,
12814 server_id: Option<LanguageServerId>,
12815 lsp_request_id: LspRequestId,
12816 proto_request: &T::ProtoRequest,
12817 range: Range<Anchor>,
12818 cx: &mut AsyncApp,
12819 ) -> Result<()>
12820 where
12821 T: LspCommand,
12822 T::ProtoRequest: proto::LspRequestMessage,
12823 {
12824 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12825 let version = deserialize_version(proto_request.buffer_version());
12826 let buffer = lsp_store.update(cx, |this, cx| {
12827 this.buffer_store.read(cx).get_existing(buffer_id)
12828 })?;
12829 buffer
12830 .update(cx, |buffer, _| buffer.wait_for_version(version))
12831 .await?;
12832 lsp_store.update(cx, |lsp_store, cx| {
12833 let buffer_snapshot = buffer.read(cx).snapshot();
12834 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12835 let chunks_queried_for = lsp_data
12836 .inlay_hints
12837 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12838 .collect::<Vec<_>>();
12839 match chunks_queried_for.as_slice() {
12840 &[chunk] => {
12841 let key = LspKey {
12842 request_type: TypeId::of::<T>(),
12843 server_queried: server_id,
12844 };
12845 let previous_request = lsp_data
12846 .chunk_lsp_requests
12847 .entry(key)
12848 .or_default()
12849 .insert(chunk, lsp_request_id);
12850 if let Some((previous_request, running_requests)) =
12851 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12852 {
12853 running_requests.remove(&previous_request);
12854 }
12855 }
12856 _ambiguous_chunks => {
12857 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12858 // there, a buffer version-based check will be performed and outdated requests discarded.
12859 }
12860 }
12861 anyhow::Ok(())
12862 })?;
12863
12864 Ok(())
12865 }
12866
12867 async fn query_lsp_locally<T>(
12868 lsp_store: Entity<Self>,
12869 for_server_id: Option<LanguageServerId>,
12870 sender_id: proto::PeerId,
12871 lsp_request_id: LspRequestId,
12872 proto_request: T::ProtoRequest,
12873 position: Option<Anchor>,
12874 cx: &mut AsyncApp,
12875 ) -> Result<()>
12876 where
12877 T: LspCommand + Clone,
12878 T::ProtoRequest: proto::LspRequestMessage,
12879 <T::ProtoRequest as proto::RequestMessage>::Response:
12880 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12881 {
12882 let (buffer_version, buffer) =
12883 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12884 let request =
12885 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12886 let key = LspKey {
12887 request_type: TypeId::of::<T>(),
12888 server_queried: for_server_id,
12889 };
12890 lsp_store.update(cx, |lsp_store, cx| {
12891 let request_task = match for_server_id {
12892 Some(server_id) => {
12893 let server_task = lsp_store.request_lsp(
12894 buffer.clone(),
12895 LanguageServerToQuery::Other(server_id),
12896 request.clone(),
12897 cx,
12898 );
12899 cx.background_spawn(async move {
12900 let mut responses = Vec::new();
12901 match server_task.await {
12902 Ok(response) => responses.push((server_id, response)),
12903 // rust-analyzer likes to error with this when its still loading up
12904 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12905 Err(e) => log::error!(
12906 "Error handling response for request {request:?}: {e:#}"
12907 ),
12908 }
12909 responses
12910 })
12911 }
12912 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12913 };
12914 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12915 if T::ProtoRequest::stop_previous_requests() {
12916 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12917 lsp_requests.clear();
12918 }
12919 }
12920 lsp_data.lsp_requests.entry(key).or_default().insert(
12921 lsp_request_id,
12922 cx.spawn(async move |lsp_store, cx| {
12923 let response = request_task.await;
12924 lsp_store
12925 .update(cx, |lsp_store, cx| {
12926 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12927 {
12928 let response = response
12929 .into_iter()
12930 .map(|(server_id, response)| {
12931 (
12932 server_id.to_proto(),
12933 T::response_to_proto(
12934 response,
12935 lsp_store,
12936 sender_id,
12937 &buffer_version,
12938 cx,
12939 )
12940 .into(),
12941 )
12942 })
12943 .collect::<HashMap<_, _>>();
12944 match client.send_lsp_response::<T::ProtoRequest>(
12945 project_id,
12946 lsp_request_id,
12947 response,
12948 ) {
12949 Ok(()) => {}
12950 Err(e) => {
12951 log::error!("Failed to send LSP response: {e:#}",)
12952 }
12953 }
12954 }
12955 })
12956 .ok();
12957 }),
12958 );
12959 });
12960 Ok(())
12961 }
12962
12963 async fn wait_for_buffer_version<T>(
12964 lsp_store: &Entity<Self>,
12965 proto_request: &T::ProtoRequest,
12966 cx: &mut AsyncApp,
12967 ) -> Result<(Global, Entity<Buffer>)>
12968 where
12969 T: LspCommand,
12970 T::ProtoRequest: proto::LspRequestMessage,
12971 {
12972 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12973 let version = deserialize_version(proto_request.buffer_version());
12974 let buffer = lsp_store.update(cx, |this, cx| {
12975 this.buffer_store.read(cx).get_existing(buffer_id)
12976 })?;
12977 buffer
12978 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
12979 .await?;
12980 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
12981 Ok((buffer_version, buffer))
12982 }
12983
12984 fn take_text_document_sync_options(
12985 capabilities: &mut lsp::ServerCapabilities,
12986 ) -> lsp::TextDocumentSyncOptions {
12987 match capabilities.text_document_sync.take() {
12988 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12989 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12990 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12991 sync_options.change = Some(sync_kind);
12992 sync_options
12993 }
12994 None => lsp::TextDocumentSyncOptions::default(),
12995 }
12996 }
12997
12998 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12999 self.downstream_client.clone()
13000 }
13001
13002 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13003 self.worktree_store.clone()
13004 }
13005
13006 /// Gets what's stored in the LSP data for the given buffer.
13007 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13008 self.lsp_data.get_mut(&buffer_id)
13009 }
13010
13011 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13012 /// new [`BufferLspData`] will be created to replace the previous state.
13013 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13014 let (buffer_id, buffer_version) =
13015 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13016 let lsp_data = self
13017 .lsp_data
13018 .entry(buffer_id)
13019 .or_insert_with(|| BufferLspData::new(buffer, cx));
13020 if buffer_version.changed_since(&lsp_data.buffer_version) {
13021 // To send delta requests for semantic tokens, the previous tokens
13022 // need to be kept between buffer changes.
13023 let semantic_tokens = lsp_data.semantic_tokens.take();
13024 *lsp_data = BufferLspData::new(buffer, cx);
13025 lsp_data.semantic_tokens = semantic_tokens;
13026 }
13027 lsp_data
13028 }
13029}
13030
13031// Registration with registerOptions as null, should fallback to true.
13032// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13033fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13034 reg: lsp::Registration,
13035) -> Result<OneOf<bool, T>> {
13036 Ok(match reg.register_options {
13037 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13038 None => OneOf::Left(true),
13039 })
13040}
13041
13042fn subscribe_to_binary_statuses(
13043 languages: &Arc<LanguageRegistry>,
13044 cx: &mut Context<'_, LspStore>,
13045) -> Task<()> {
13046 let mut server_statuses = languages.language_server_binary_statuses();
13047 cx.spawn(async move |lsp_store, cx| {
13048 while let Some((server_name, binary_status)) = server_statuses.next().await {
13049 if lsp_store
13050 .update(cx, |_, cx| {
13051 let mut message = None;
13052 let binary_status = match binary_status {
13053 BinaryStatus::None => proto::ServerBinaryStatus::None,
13054 BinaryStatus::CheckingForUpdate => {
13055 proto::ServerBinaryStatus::CheckingForUpdate
13056 }
13057 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13058 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13059 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13060 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13061 BinaryStatus::Failed { error } => {
13062 message = Some(error);
13063 proto::ServerBinaryStatus::Failed
13064 }
13065 };
13066 cx.emit(LspStoreEvent::LanguageServerUpdate {
13067 // Binary updates are about the binary that might not have any language server id at that point.
13068 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13069 language_server_id: LanguageServerId(0),
13070 name: Some(server_name),
13071 message: proto::update_language_server::Variant::StatusUpdate(
13072 proto::StatusUpdate {
13073 message,
13074 status: Some(proto::status_update::Status::Binary(
13075 binary_status as i32,
13076 )),
13077 },
13078 ),
13079 });
13080 })
13081 .is_err()
13082 {
13083 break;
13084 }
13085 }
13086 })
13087}
13088
13089fn lsp_workspace_diagnostics_refresh(
13090 registration_id: Option<String>,
13091 options: DiagnosticServerCapabilities,
13092 server: Arc<LanguageServer>,
13093 cx: &mut Context<'_, LspStore>,
13094) -> Option<WorkspaceRefreshTask> {
13095 let identifier = workspace_diagnostic_identifier(&options)?;
13096 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13097
13098 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13099 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13100 refresh_tx.try_send(()).ok();
13101
13102 let request_timeout = ProjectSettings::get_global(cx)
13103 .global_lsp_settings
13104 .get_request_timeout();
13105
13106 // 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.
13107 // This allows users to increase the duration if need be
13108 let timeout = if request_timeout != Duration::ZERO {
13109 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13110 } else {
13111 request_timeout
13112 };
13113
13114 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13115 let mut attempts = 0;
13116 let max_attempts = 50;
13117 let mut requests = 0;
13118
13119 loop {
13120 let Some(()) = refresh_rx.recv().await else {
13121 return;
13122 };
13123
13124 'request: loop {
13125 requests += 1;
13126 if attempts > max_attempts {
13127 log::error!(
13128 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13129 );
13130 return;
13131 }
13132 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13133 cx.background_executor()
13134 .timer(Duration::from_millis(backoff_millis))
13135 .await;
13136 attempts += 1;
13137
13138 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13139 lsp_store
13140 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13141 .into_iter()
13142 .filter_map(|(abs_path, result_id)| {
13143 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13144 Some(lsp::PreviousResultId {
13145 uri,
13146 value: result_id.to_string(),
13147 })
13148 })
13149 .collect()
13150 }) else {
13151 return;
13152 };
13153
13154 let token = if let Some(registration_id) = ®istration_id {
13155 format!(
13156 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13157 server.server_id(),
13158 )
13159 } else {
13160 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13161 };
13162
13163 progress_rx.try_recv().ok();
13164 let timer = server.request_timer(timeout).fuse();
13165 let progress = pin!(progress_rx.recv().fuse());
13166 let response_result = server
13167 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13168 lsp::WorkspaceDiagnosticParams {
13169 previous_result_ids,
13170 identifier: identifier.clone(),
13171 work_done_progress_params: Default::default(),
13172 partial_result_params: lsp::PartialResultParams {
13173 partial_result_token: Some(lsp::ProgressToken::String(token)),
13174 },
13175 },
13176 select(timer, progress).then(|either| match either {
13177 Either::Left((message, ..)) => ready(message).left_future(),
13178 Either::Right(..) => pending::<String>().right_future(),
13179 }),
13180 )
13181 .await;
13182
13183 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13184 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13185 match response_result {
13186 ConnectionResult::Timeout => {
13187 log::error!("Timeout during workspace diagnostics pull");
13188 continue 'request;
13189 }
13190 ConnectionResult::ConnectionReset => {
13191 log::error!("Server closed a workspace diagnostics pull request");
13192 continue 'request;
13193 }
13194 ConnectionResult::Result(Err(e)) => {
13195 log::error!("Error during workspace diagnostics pull: {e:#}");
13196 break 'request;
13197 }
13198 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13199 attempts = 0;
13200 if lsp_store
13201 .update(cx, |lsp_store, cx| {
13202 lsp_store.apply_workspace_diagnostic_report(
13203 server.server_id(),
13204 pulled_diagnostics,
13205 registration_id_shared.clone(),
13206 cx,
13207 )
13208 })
13209 .is_err()
13210 {
13211 return;
13212 }
13213 break 'request;
13214 }
13215 }
13216 }
13217 }
13218 });
13219
13220 Some(WorkspaceRefreshTask {
13221 refresh_tx,
13222 progress_tx,
13223 task: workspace_query_language_server,
13224 })
13225}
13226
13227fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13228 match &options {
13229 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13230 .identifier
13231 .as_deref()
13232 .map(SharedString::new),
13233 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13234 let diagnostic_options = ®istration_options.diagnostic_options;
13235 diagnostic_options
13236 .identifier
13237 .as_deref()
13238 .map(SharedString::new)
13239 }
13240 }
13241}
13242
13243fn workspace_diagnostic_identifier(
13244 options: &DiagnosticServerCapabilities,
13245) -> Option<Option<String>> {
13246 match &options {
13247 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13248 if !diagnostic_options.workspace_diagnostics {
13249 return None;
13250 }
13251 Some(diagnostic_options.identifier.clone())
13252 }
13253 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13254 let diagnostic_options = ®istration_options.diagnostic_options;
13255 if !diagnostic_options.workspace_diagnostics {
13256 return None;
13257 }
13258 Some(diagnostic_options.identifier.clone())
13259 }
13260 }
13261}
13262
13263fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13264 let CompletionSource::BufferWord {
13265 word_range,
13266 resolved,
13267 } = &mut completion.source
13268 else {
13269 return;
13270 };
13271 if *resolved {
13272 return;
13273 }
13274
13275 if completion.new_text
13276 != snapshot
13277 .text_for_range(word_range.clone())
13278 .collect::<String>()
13279 {
13280 return;
13281 }
13282
13283 let mut offset = 0;
13284 for chunk in snapshot.chunks(word_range.clone(), true) {
13285 let end_offset = offset + chunk.text.len();
13286 if let Some(highlight_id) = chunk.syntax_highlight_id {
13287 completion
13288 .label
13289 .runs
13290 .push((offset..end_offset, highlight_id));
13291 }
13292 offset = end_offset;
13293 }
13294 *resolved = true;
13295}
13296
13297impl EventEmitter<LspStoreEvent> for LspStore {}
13298
13299fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13300 hover
13301 .contents
13302 .retain(|hover_block| !hover_block.text.trim().is_empty());
13303 if hover.contents.is_empty() {
13304 None
13305 } else {
13306 Some(hover)
13307 }
13308}
13309
13310async fn populate_labels_for_completions(
13311 new_completions: Vec<CoreCompletion>,
13312 language: Option<Arc<Language>>,
13313 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13314) -> Vec<Completion> {
13315 let lsp_completions = new_completions
13316 .iter()
13317 .filter_map(|new_completion| {
13318 new_completion
13319 .source
13320 .lsp_completion(true)
13321 .map(|lsp_completion| lsp_completion.into_owned())
13322 })
13323 .collect::<Vec<_>>();
13324
13325 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13326 lsp_adapter
13327 .labels_for_completions(&lsp_completions, language)
13328 .await
13329 .log_err()
13330 .unwrap_or_default()
13331 } else {
13332 Vec::new()
13333 }
13334 .into_iter()
13335 .fuse();
13336
13337 let mut completions = Vec::new();
13338 for completion in new_completions {
13339 match completion.source.lsp_completion(true) {
13340 Some(lsp_completion) => {
13341 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13342
13343 let mut label = labels.next().flatten().unwrap_or_else(|| {
13344 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13345 });
13346 ensure_uniform_list_compatible_label(&mut label);
13347 completions.push(Completion {
13348 label,
13349 documentation,
13350 replace_range: completion.replace_range,
13351 new_text: completion.new_text,
13352 insert_text_mode: lsp_completion.insert_text_mode,
13353 source: completion.source,
13354 icon_path: None,
13355 confirm: None,
13356 match_start: None,
13357 snippet_deduplication_key: None,
13358 });
13359 }
13360 None => {
13361 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13362 ensure_uniform_list_compatible_label(&mut label);
13363 completions.push(Completion {
13364 label,
13365 documentation: None,
13366 replace_range: completion.replace_range,
13367 new_text: completion.new_text,
13368 source: completion.source,
13369 insert_text_mode: None,
13370 icon_path: None,
13371 confirm: None,
13372 match_start: None,
13373 snippet_deduplication_key: None,
13374 });
13375 }
13376 }
13377 }
13378 completions
13379}
13380
13381#[derive(Debug)]
13382pub enum LanguageServerToQuery {
13383 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13384 FirstCapable,
13385 /// Query a specific language server.
13386 Other(LanguageServerId),
13387}
13388
13389#[derive(Default)]
13390struct RenamePathsWatchedForServer {
13391 did_rename: Vec<RenameActionPredicate>,
13392 will_rename: Vec<RenameActionPredicate>,
13393}
13394
13395impl RenamePathsWatchedForServer {
13396 fn with_did_rename_patterns(
13397 mut self,
13398 did_rename: Option<&FileOperationRegistrationOptions>,
13399 ) -> Self {
13400 if let Some(did_rename) = did_rename {
13401 self.did_rename = did_rename
13402 .filters
13403 .iter()
13404 .filter_map(|filter| filter.try_into().log_err())
13405 .collect();
13406 }
13407 self
13408 }
13409 fn with_will_rename_patterns(
13410 mut self,
13411 will_rename: Option<&FileOperationRegistrationOptions>,
13412 ) -> Self {
13413 if let Some(will_rename) = will_rename {
13414 self.will_rename = will_rename
13415 .filters
13416 .iter()
13417 .filter_map(|filter| filter.try_into().log_err())
13418 .collect();
13419 }
13420 self
13421 }
13422
13423 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13424 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13425 }
13426 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13427 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13428 }
13429}
13430
13431impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13432 type Error = globset::Error;
13433 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13434 Ok(Self {
13435 kind: ops.pattern.matches.clone(),
13436 glob: GlobBuilder::new(&ops.pattern.glob)
13437 .case_insensitive(
13438 ops.pattern
13439 .options
13440 .as_ref()
13441 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13442 )
13443 .build()?
13444 .compile_matcher(),
13445 })
13446 }
13447}
13448struct RenameActionPredicate {
13449 glob: GlobMatcher,
13450 kind: Option<FileOperationPatternKind>,
13451}
13452
13453impl RenameActionPredicate {
13454 // Returns true if language server should be notified
13455 fn eval(&self, path: &str, is_dir: bool) -> bool {
13456 self.kind.as_ref().is_none_or(|kind| {
13457 let expected_kind = if is_dir {
13458 FileOperationPatternKind::Folder
13459 } else {
13460 FileOperationPatternKind::File
13461 };
13462 kind == &expected_kind
13463 }) && self.glob.is_match(path)
13464 }
13465}
13466
13467#[derive(Default)]
13468struct LanguageServerWatchedPaths {
13469 worktree_paths: HashMap<WorktreeId, GlobSet>,
13470 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13471}
13472
13473#[derive(Default)]
13474struct LanguageServerWatchedPathsBuilder {
13475 worktree_paths: HashMap<WorktreeId, GlobSet>,
13476 abs_paths: HashMap<Arc<Path>, GlobSet>,
13477}
13478
13479impl LanguageServerWatchedPathsBuilder {
13480 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13481 self.worktree_paths.insert(worktree_id, glob_set);
13482 }
13483 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13484 self.abs_paths.insert(path, glob_set);
13485 }
13486 fn build(
13487 self,
13488 fs: Arc<dyn Fs>,
13489 language_server_id: LanguageServerId,
13490 cx: &mut Context<LspStore>,
13491 ) -> LanguageServerWatchedPaths {
13492 let lsp_store = cx.weak_entity();
13493
13494 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13495 let abs_paths = self
13496 .abs_paths
13497 .into_iter()
13498 .map(|(abs_path, globset)| {
13499 let task = cx.spawn({
13500 let abs_path = abs_path.clone();
13501 let fs = fs.clone();
13502
13503 let lsp_store = lsp_store.clone();
13504 async move |_, cx| {
13505 maybe!(async move {
13506 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13507 while let Some(update) = push_updates.0.next().await {
13508 let action = lsp_store
13509 .update(cx, |this, _| {
13510 let Some(local) = this.as_local() else {
13511 return ControlFlow::Break(());
13512 };
13513 let Some(watcher) = local
13514 .language_server_watched_paths
13515 .get(&language_server_id)
13516 else {
13517 return ControlFlow::Break(());
13518 };
13519 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13520 "Watched abs path is not registered with a watcher",
13521 );
13522 let matching_entries = update
13523 .into_iter()
13524 .filter(|event| globs.is_match(&event.path))
13525 .collect::<Vec<_>>();
13526 this.lsp_notify_abs_paths_changed(
13527 language_server_id,
13528 matching_entries,
13529 );
13530 ControlFlow::Continue(())
13531 })
13532 .ok()?;
13533
13534 if action.is_break() {
13535 break;
13536 }
13537 }
13538 Some(())
13539 })
13540 .await;
13541 }
13542 });
13543 (abs_path, (globset, task))
13544 })
13545 .collect();
13546 LanguageServerWatchedPaths {
13547 worktree_paths: self.worktree_paths,
13548 abs_paths,
13549 }
13550 }
13551}
13552
13553struct LspBufferSnapshot {
13554 version: i32,
13555 snapshot: TextBufferSnapshot,
13556}
13557
13558/// A prompt requested by LSP server.
13559#[derive(Clone, Debug)]
13560pub struct LanguageServerPromptRequest {
13561 pub id: usize,
13562 pub level: PromptLevel,
13563 pub message: String,
13564 pub actions: Vec<MessageActionItem>,
13565 pub lsp_name: String,
13566 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13567}
13568
13569impl LanguageServerPromptRequest {
13570 pub fn new(
13571 level: PromptLevel,
13572 message: String,
13573 actions: Vec<MessageActionItem>,
13574 lsp_name: String,
13575 response_channel: smol::channel::Sender<MessageActionItem>,
13576 ) -> Self {
13577 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13578 LanguageServerPromptRequest {
13579 id,
13580 level,
13581 message,
13582 actions,
13583 lsp_name,
13584 response_channel,
13585 }
13586 }
13587 pub async fn respond(self, index: usize) -> Option<()> {
13588 if let Some(response) = self.actions.into_iter().nth(index) {
13589 self.response_channel.send(response).await.ok()
13590 } else {
13591 None
13592 }
13593 }
13594
13595 #[cfg(any(test, feature = "test-support"))]
13596 pub fn test(
13597 level: PromptLevel,
13598 message: String,
13599 actions: Vec<MessageActionItem>,
13600 lsp_name: String,
13601 ) -> Self {
13602 let (tx, _rx) = smol::channel::unbounded();
13603 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13604 }
13605}
13606impl PartialEq for LanguageServerPromptRequest {
13607 fn eq(&self, other: &Self) -> bool {
13608 self.message == other.message && self.actions == other.actions
13609 }
13610}
13611
13612#[derive(Clone, Debug, PartialEq)]
13613pub enum LanguageServerLogType {
13614 Log(MessageType),
13615 Trace { verbose_info: Option<String> },
13616 Rpc { received: bool },
13617}
13618
13619impl LanguageServerLogType {
13620 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13621 match self {
13622 Self::Log(log_type) => {
13623 use proto::log_message::LogLevel;
13624 let level = match *log_type {
13625 MessageType::ERROR => LogLevel::Error,
13626 MessageType::WARNING => LogLevel::Warning,
13627 MessageType::INFO => LogLevel::Info,
13628 MessageType::LOG => LogLevel::Log,
13629 other => {
13630 log::warn!("Unknown lsp log message type: {other:?}");
13631 LogLevel::Log
13632 }
13633 };
13634 proto::language_server_log::LogType::Log(proto::LogMessage {
13635 level: level as i32,
13636 })
13637 }
13638 Self::Trace { verbose_info } => {
13639 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13640 verbose_info: verbose_info.to_owned(),
13641 })
13642 }
13643 Self::Rpc { received } => {
13644 let kind = if *received {
13645 proto::rpc_message::Kind::Received
13646 } else {
13647 proto::rpc_message::Kind::Sent
13648 };
13649 let kind = kind as i32;
13650 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13651 }
13652 }
13653 }
13654
13655 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13656 use proto::log_message::LogLevel;
13657 use proto::rpc_message;
13658 match log_type {
13659 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13660 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13661 LogLevel::Error => MessageType::ERROR,
13662 LogLevel::Warning => MessageType::WARNING,
13663 LogLevel::Info => MessageType::INFO,
13664 LogLevel::Log => MessageType::LOG,
13665 },
13666 ),
13667 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13668 verbose_info: trace_message.verbose_info,
13669 },
13670 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13671 received: match rpc_message::Kind::from_i32(message.kind)
13672 .unwrap_or(rpc_message::Kind::Received)
13673 {
13674 rpc_message::Kind::Received => true,
13675 rpc_message::Kind::Sent => false,
13676 },
13677 },
13678 }
13679 }
13680}
13681
13682pub struct WorkspaceRefreshTask {
13683 refresh_tx: mpsc::Sender<()>,
13684 progress_tx: mpsc::Sender<()>,
13685 #[allow(dead_code)]
13686 task: Task<()>,
13687}
13688
13689pub enum LanguageServerState {
13690 Starting {
13691 startup: Task<Option<Arc<LanguageServer>>>,
13692 /// List of language servers that will be added to the workspace once it's initialization completes.
13693 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13694 },
13695
13696 Running {
13697 adapter: Arc<CachedLspAdapter>,
13698 server: Arc<LanguageServer>,
13699 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13700 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13701 },
13702}
13703
13704impl LanguageServerState {
13705 fn add_workspace_folder(&self, uri: Uri) {
13706 match self {
13707 LanguageServerState::Starting {
13708 pending_workspace_folders,
13709 ..
13710 } => {
13711 pending_workspace_folders.lock().insert(uri);
13712 }
13713 LanguageServerState::Running { server, .. } => {
13714 server.add_workspace_folder(uri);
13715 }
13716 }
13717 }
13718 fn _remove_workspace_folder(&self, uri: Uri) {
13719 match self {
13720 LanguageServerState::Starting {
13721 pending_workspace_folders,
13722 ..
13723 } => {
13724 pending_workspace_folders.lock().remove(&uri);
13725 }
13726 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13727 }
13728 }
13729}
13730
13731impl std::fmt::Debug for LanguageServerState {
13732 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13733 match self {
13734 LanguageServerState::Starting { .. } => {
13735 f.debug_struct("LanguageServerState::Starting").finish()
13736 }
13737 LanguageServerState::Running { .. } => {
13738 f.debug_struct("LanguageServerState::Running").finish()
13739 }
13740 }
13741 }
13742}
13743
13744#[derive(Clone, Debug, Serialize)]
13745pub struct LanguageServerProgress {
13746 pub is_disk_based_diagnostics_progress: bool,
13747 pub is_cancellable: bool,
13748 pub title: Option<String>,
13749 pub message: Option<String>,
13750 pub percentage: Option<usize>,
13751 #[serde(skip_serializing)]
13752 pub last_update_at: Instant,
13753}
13754
13755#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13756pub struct DiagnosticSummary {
13757 pub error_count: usize,
13758 pub warning_count: usize,
13759}
13760
13761impl DiagnosticSummary {
13762 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13763 let mut this = Self {
13764 error_count: 0,
13765 warning_count: 0,
13766 };
13767
13768 for entry in diagnostics {
13769 if entry.diagnostic.is_primary {
13770 match entry.diagnostic.severity {
13771 DiagnosticSeverity::ERROR => this.error_count += 1,
13772 DiagnosticSeverity::WARNING => this.warning_count += 1,
13773 _ => {}
13774 }
13775 }
13776 }
13777
13778 this
13779 }
13780
13781 pub fn is_empty(&self) -> bool {
13782 self.error_count == 0 && self.warning_count == 0
13783 }
13784
13785 pub fn to_proto(
13786 self,
13787 language_server_id: LanguageServerId,
13788 path: &RelPath,
13789 ) -> proto::DiagnosticSummary {
13790 proto::DiagnosticSummary {
13791 path: path.to_proto(),
13792 language_server_id: language_server_id.0 as u64,
13793 error_count: self.error_count as u32,
13794 warning_count: self.warning_count as u32,
13795 }
13796 }
13797}
13798
13799#[derive(Clone, Debug)]
13800pub enum CompletionDocumentation {
13801 /// There is no documentation for this completion.
13802 Undocumented,
13803 /// A single line of documentation.
13804 SingleLine(SharedString),
13805 /// Multiple lines of plain text documentation.
13806 MultiLinePlainText(SharedString),
13807 /// Markdown documentation.
13808 MultiLineMarkdown(SharedString),
13809 /// Both single line and multiple lines of plain text documentation.
13810 SingleLineAndMultiLinePlainText {
13811 single_line: SharedString,
13812 plain_text: Option<SharedString>,
13813 },
13814}
13815
13816impl CompletionDocumentation {
13817 #[cfg(any(test, feature = "test-support"))]
13818 pub fn text(&self) -> SharedString {
13819 match self {
13820 CompletionDocumentation::Undocumented => "".into(),
13821 CompletionDocumentation::SingleLine(s) => s.clone(),
13822 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13823 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13824 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13825 single_line.clone()
13826 }
13827 }
13828 }
13829}
13830
13831impl From<lsp::Documentation> for CompletionDocumentation {
13832 fn from(docs: lsp::Documentation) -> Self {
13833 match docs {
13834 lsp::Documentation::String(text) => {
13835 if text.lines().count() <= 1 {
13836 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13837 } else {
13838 CompletionDocumentation::MultiLinePlainText(text.into())
13839 }
13840 }
13841
13842 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13843 lsp::MarkupKind::PlainText => {
13844 if value.lines().count() <= 1 {
13845 CompletionDocumentation::SingleLine(value.into())
13846 } else {
13847 CompletionDocumentation::MultiLinePlainText(value.into())
13848 }
13849 }
13850
13851 lsp::MarkupKind::Markdown => {
13852 CompletionDocumentation::MultiLineMarkdown(value.into())
13853 }
13854 },
13855 }
13856 }
13857}
13858
13859pub enum ResolvedHint {
13860 Resolved(InlayHint),
13861 Resolving(Shared<Task<()>>),
13862}
13863
13864pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13865 glob.components()
13866 .take_while(|component| match component {
13867 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13868 _ => true,
13869 })
13870 .collect()
13871}
13872
13873pub struct SshLspAdapter {
13874 name: LanguageServerName,
13875 binary: LanguageServerBinary,
13876 initialization_options: Option<String>,
13877 code_action_kinds: Option<Vec<CodeActionKind>>,
13878}
13879
13880impl SshLspAdapter {
13881 pub fn new(
13882 name: LanguageServerName,
13883 binary: LanguageServerBinary,
13884 initialization_options: Option<String>,
13885 code_action_kinds: Option<String>,
13886 ) -> Self {
13887 Self {
13888 name,
13889 binary,
13890 initialization_options,
13891 code_action_kinds: code_action_kinds
13892 .as_ref()
13893 .and_then(|c| serde_json::from_str(c).ok()),
13894 }
13895 }
13896}
13897
13898impl LspInstaller for SshLspAdapter {
13899 type BinaryVersion = ();
13900 async fn check_if_user_installed(
13901 &self,
13902 _: &dyn LspAdapterDelegate,
13903 _: Option<Toolchain>,
13904 _: &AsyncApp,
13905 ) -> Option<LanguageServerBinary> {
13906 Some(self.binary.clone())
13907 }
13908
13909 async fn cached_server_binary(
13910 &self,
13911 _: PathBuf,
13912 _: &dyn LspAdapterDelegate,
13913 ) -> Option<LanguageServerBinary> {
13914 None
13915 }
13916
13917 async fn fetch_latest_server_version(
13918 &self,
13919 _: &dyn LspAdapterDelegate,
13920 _: bool,
13921 _: &mut AsyncApp,
13922 ) -> Result<()> {
13923 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13924 }
13925
13926 async fn fetch_server_binary(
13927 &self,
13928 _: (),
13929 _: PathBuf,
13930 _: &dyn LspAdapterDelegate,
13931 ) -> Result<LanguageServerBinary> {
13932 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13933 }
13934}
13935
13936#[async_trait(?Send)]
13937impl LspAdapter for SshLspAdapter {
13938 fn name(&self) -> LanguageServerName {
13939 self.name.clone()
13940 }
13941
13942 async fn initialization_options(
13943 self: Arc<Self>,
13944 _: &Arc<dyn LspAdapterDelegate>,
13945 ) -> Result<Option<serde_json::Value>> {
13946 let Some(options) = &self.initialization_options else {
13947 return Ok(None);
13948 };
13949 let result = serde_json::from_str(options)?;
13950 Ok(result)
13951 }
13952
13953 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13954 self.code_action_kinds.clone()
13955 }
13956}
13957
13958pub fn language_server_settings<'a>(
13959 delegate: &'a dyn LspAdapterDelegate,
13960 language: &LanguageServerName,
13961 cx: &'a App,
13962) -> Option<&'a LspSettings> {
13963 language_server_settings_for(
13964 SettingsLocation {
13965 worktree_id: delegate.worktree_id(),
13966 path: RelPath::empty(),
13967 },
13968 language,
13969 cx,
13970 )
13971}
13972
13973pub fn language_server_settings_for<'a>(
13974 location: SettingsLocation<'a>,
13975 language: &LanguageServerName,
13976 cx: &'a App,
13977) -> Option<&'a LspSettings> {
13978 ProjectSettings::get(Some(location), cx).lsp.get(language)
13979}
13980
13981pub struct LocalLspAdapterDelegate {
13982 lsp_store: WeakEntity<LspStore>,
13983 worktree: worktree::Snapshot,
13984 fs: Arc<dyn Fs>,
13985 http_client: Arc<dyn HttpClient>,
13986 language_registry: Arc<LanguageRegistry>,
13987 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13988}
13989
13990impl LocalLspAdapterDelegate {
13991 pub fn new(
13992 language_registry: Arc<LanguageRegistry>,
13993 environment: &Entity<ProjectEnvironment>,
13994 lsp_store: WeakEntity<LspStore>,
13995 worktree: &Entity<Worktree>,
13996 http_client: Arc<dyn HttpClient>,
13997 fs: Arc<dyn Fs>,
13998 cx: &mut App,
13999 ) -> Arc<Self> {
14000 let load_shell_env_task =
14001 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14002
14003 Arc::new(Self {
14004 lsp_store,
14005 worktree: worktree.read(cx).snapshot(),
14006 fs,
14007 http_client,
14008 language_registry,
14009 load_shell_env_task,
14010 })
14011 }
14012
14013 pub fn from_local_lsp(
14014 local: &LocalLspStore,
14015 worktree: &Entity<Worktree>,
14016 cx: &mut App,
14017 ) -> Arc<Self> {
14018 Self::new(
14019 local.languages.clone(),
14020 &local.environment,
14021 local.weak.clone(),
14022 worktree,
14023 local.http_client.clone(),
14024 local.fs.clone(),
14025 cx,
14026 )
14027 }
14028}
14029
14030#[async_trait]
14031impl LspAdapterDelegate for LocalLspAdapterDelegate {
14032 fn show_notification(&self, message: &str, cx: &mut App) {
14033 self.lsp_store
14034 .update(cx, |_, cx| {
14035 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14036 })
14037 .ok();
14038 }
14039
14040 fn http_client(&self) -> Arc<dyn HttpClient> {
14041 self.http_client.clone()
14042 }
14043
14044 fn worktree_id(&self) -> WorktreeId {
14045 self.worktree.id()
14046 }
14047
14048 fn worktree_root_path(&self) -> &Path {
14049 self.worktree.abs_path().as_ref()
14050 }
14051
14052 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14053 self.worktree.resolve_executable_path(path)
14054 }
14055
14056 async fn shell_env(&self) -> HashMap<String, String> {
14057 let task = self.load_shell_env_task.clone();
14058 task.await.unwrap_or_default()
14059 }
14060
14061 async fn npm_package_installed_version(
14062 &self,
14063 package_name: &str,
14064 ) -> Result<Option<(PathBuf, Version)>> {
14065 let local_package_directory = self.worktree_root_path();
14066 let node_modules_directory = local_package_directory.join("node_modules");
14067
14068 if let Some(version) =
14069 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14070 {
14071 return Ok(Some((node_modules_directory, version)));
14072 }
14073 let Some(npm) = self.which("npm".as_ref()).await else {
14074 log::warn!(
14075 "Failed to find npm executable for {:?}",
14076 local_package_directory
14077 );
14078 return Ok(None);
14079 };
14080
14081 let env = self.shell_env().await;
14082 let output = util::command::new_smol_command(&npm)
14083 .args(["root", "-g"])
14084 .envs(env)
14085 .current_dir(local_package_directory)
14086 .output()
14087 .await?;
14088 let global_node_modules =
14089 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14090
14091 if let Some(version) =
14092 read_package_installed_version(global_node_modules.clone(), package_name).await?
14093 {
14094 return Ok(Some((global_node_modules, version)));
14095 }
14096 return Ok(None);
14097 }
14098
14099 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14100 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14101 if self.fs.is_file(&worktree_abs_path).await {
14102 worktree_abs_path.pop();
14103 }
14104
14105 let env = self.shell_env().await;
14106
14107 let shell_path = env.get("PATH").cloned();
14108
14109 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14110 }
14111
14112 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14113 let mut working_dir = self.worktree_root_path().to_path_buf();
14114 if self.fs.is_file(&working_dir).await {
14115 working_dir.pop();
14116 }
14117 let output = util::command::new_smol_command(&command.path)
14118 .args(command.arguments)
14119 .envs(command.env.clone().unwrap_or_default())
14120 .current_dir(working_dir)
14121 .output()
14122 .await?;
14123
14124 anyhow::ensure!(
14125 output.status.success(),
14126 "{}, stdout: {:?}, stderr: {:?}",
14127 output.status,
14128 String::from_utf8_lossy(&output.stdout),
14129 String::from_utf8_lossy(&output.stderr)
14130 );
14131 Ok(())
14132 }
14133
14134 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14135 self.language_registry
14136 .update_lsp_binary_status(server_name, status);
14137 }
14138
14139 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14140 self.language_registry
14141 .all_lsp_adapters()
14142 .into_iter()
14143 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14144 .collect()
14145 }
14146
14147 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14148 let dir = self.language_registry.language_server_download_dir(name)?;
14149
14150 if !dir.exists() {
14151 smol::fs::create_dir_all(&dir)
14152 .await
14153 .context("failed to create container directory")
14154 .log_err()?;
14155 }
14156
14157 Some(dir)
14158 }
14159
14160 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14161 let entry = self
14162 .worktree
14163 .entry_for_path(path)
14164 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14165 let abs_path = self.worktree.absolutize(&entry.path);
14166 self.fs.load(&abs_path).await
14167 }
14168}
14169
14170async fn populate_labels_for_symbols(
14171 symbols: Vec<CoreSymbol>,
14172 language_registry: &Arc<LanguageRegistry>,
14173 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14174 output: &mut Vec<Symbol>,
14175) {
14176 #[allow(clippy::mutable_key_type)]
14177 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14178
14179 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14180 for symbol in symbols {
14181 let Some(file_name) = symbol.path.file_name() else {
14182 continue;
14183 };
14184 let language = language_registry
14185 .load_language_for_file_path(Path::new(file_name))
14186 .await
14187 .ok()
14188 .or_else(|| {
14189 unknown_paths.insert(file_name.into());
14190 None
14191 });
14192 symbols_by_language
14193 .entry(language)
14194 .or_default()
14195 .push(symbol);
14196 }
14197
14198 for unknown_path in unknown_paths {
14199 log::info!("no language found for symbol in file {unknown_path:?}");
14200 }
14201
14202 let mut label_params = Vec::new();
14203 for (language, mut symbols) in symbols_by_language {
14204 label_params.clear();
14205 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14206 name: mem::take(&mut symbol.name),
14207 kind: symbol.kind,
14208 container_name: symbol.container_name.take(),
14209 }));
14210
14211 let mut labels = Vec::new();
14212 if let Some(language) = language {
14213 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14214 language_registry
14215 .lsp_adapters(&language.name())
14216 .first()
14217 .cloned()
14218 });
14219 if let Some(lsp_adapter) = lsp_adapter {
14220 labels = lsp_adapter
14221 .labels_for_symbols(&label_params, &language)
14222 .await
14223 .log_err()
14224 .unwrap_or_default();
14225 }
14226 }
14227
14228 for (
14229 (
14230 symbol,
14231 language::Symbol {
14232 name,
14233 container_name,
14234 ..
14235 },
14236 ),
14237 label,
14238 ) in symbols
14239 .into_iter()
14240 .zip(label_params.drain(..))
14241 .zip(labels.into_iter().chain(iter::repeat(None)))
14242 {
14243 output.push(Symbol {
14244 language_server_name: symbol.language_server_name,
14245 source_worktree_id: symbol.source_worktree_id,
14246 source_language_server_id: symbol.source_language_server_id,
14247 path: symbol.path,
14248 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14249 name,
14250 kind: symbol.kind,
14251 range: symbol.range,
14252 container_name,
14253 });
14254 }
14255 }
14256}
14257
14258fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14259 match server.capabilities().text_document_sync.as_ref()? {
14260 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14261 // Server wants didSave but didn't specify includeText.
14262 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14263 // Server doesn't want didSave at all.
14264 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14265 // Server provided SaveOptions.
14266 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14267 Some(save_options.include_text.unwrap_or(false))
14268 }
14269 },
14270 // We do not have any save info. Kind affects didChange only.
14271 lsp::TextDocumentSyncCapability::Kind(_) => None,
14272 }
14273}
14274
14275/// Completion items are displayed in a `UniformList`.
14276/// Usually, those items are single-line strings, but in LSP responses,
14277/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14278/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14279/// 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,
14280/// breaking the completions menu presentation.
14281///
14282/// 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.
14283pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14284 let mut new_text = String::with_capacity(label.text.len());
14285 let mut offset_map = vec![0; label.text.len() + 1];
14286 let mut last_char_was_space = false;
14287 let mut new_idx = 0;
14288 let chars = label.text.char_indices().fuse();
14289 let mut newlines_removed = false;
14290
14291 for (idx, c) in chars {
14292 offset_map[idx] = new_idx;
14293
14294 match c {
14295 '\n' if last_char_was_space => {
14296 newlines_removed = true;
14297 }
14298 '\t' | ' ' if last_char_was_space => {}
14299 '\n' if !last_char_was_space => {
14300 new_text.push(' ');
14301 new_idx += 1;
14302 last_char_was_space = true;
14303 newlines_removed = true;
14304 }
14305 ' ' | '\t' => {
14306 new_text.push(' ');
14307 new_idx += 1;
14308 last_char_was_space = true;
14309 }
14310 _ => {
14311 new_text.push(c);
14312 new_idx += c.len_utf8();
14313 last_char_was_space = false;
14314 }
14315 }
14316 }
14317 offset_map[label.text.len()] = new_idx;
14318
14319 // Only modify the label if newlines were removed.
14320 if !newlines_removed {
14321 return;
14322 }
14323
14324 let last_index = new_idx;
14325 let mut run_ranges_errors = Vec::new();
14326 label.runs.retain_mut(|(range, _)| {
14327 match offset_map.get(range.start) {
14328 Some(&start) => range.start = start,
14329 None => {
14330 run_ranges_errors.push(range.clone());
14331 return false;
14332 }
14333 }
14334
14335 match offset_map.get(range.end) {
14336 Some(&end) => range.end = end,
14337 None => {
14338 run_ranges_errors.push(range.clone());
14339 range.end = last_index;
14340 }
14341 }
14342 true
14343 });
14344 if !run_ranges_errors.is_empty() {
14345 log::error!(
14346 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14347 label.text
14348 );
14349 }
14350
14351 let mut wrong_filter_range = None;
14352 if label.filter_range == (0..label.text.len()) {
14353 label.filter_range = 0..new_text.len();
14354 } else {
14355 let mut original_filter_range = Some(label.filter_range.clone());
14356 match offset_map.get(label.filter_range.start) {
14357 Some(&start) => label.filter_range.start = start,
14358 None => {
14359 wrong_filter_range = original_filter_range.take();
14360 label.filter_range.start = last_index;
14361 }
14362 }
14363
14364 match offset_map.get(label.filter_range.end) {
14365 Some(&end) => label.filter_range.end = end,
14366 None => {
14367 wrong_filter_range = original_filter_range.take();
14368 label.filter_range.end = last_index;
14369 }
14370 }
14371 }
14372 if let Some(wrong_filter_range) = wrong_filter_range {
14373 log::error!(
14374 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14375 label.text
14376 );
14377 }
14378
14379 label.text = new_text;
14380}